Как не хакать сторонние классы
Бывает, что вы используете какой-то сниппет или компонент, и он немного вас не устраивает. Вам нужно поправить буквально пару строк, но вы понимаете, что при обновлении эти измения пропадут.
Что же делать?
Все просто — нужно расширить сторонний класс своими методами. По сути, это очень похоже на «классные процессоры», только без процессоров и использовать можно везде — это стандартная возможность ООП.
Смысл в том, что нам нужно создать свой собственный класс, который будет наследовать исходный класс и заменять его методы.
Для примера заменим некоторые методы miniShop. Создаем файл /core/components/minishop/model/minishopext.class.php:
Значит, нам нужен теперь сниппет, для запуска нового класса. Можно просто переименовать сниппет miniShop в miniShopExt, или скопировать.
Теперь меняем в новом сниппете инициализацию класса с miniShop на miniShopExt:
miniShopExt унаследовал все методы от miniShop, кроме тех, которые прописаны в нем самом. Теперь нужно только заменить вызов сниппета [[!miniShop]] в корзине на [[!miniShopExt]].
Вот таким способом мы можем изменять любой сторонний класс как нам нужно. Самое главное — мы не лезем в чужой код и не теряем будущие обновления.
Это вообще очень хорошая практика: не хакать чужой код, а наследовать и расширять. В любой момент вы можете инициализировать оригинальный класс, или свой, расширенный.
Что же делать?
Все просто — нужно расширить сторонний класс своими методами. По сути, это очень похоже на «классные процессоры», только без процессоров и использовать можно везде — это стандартная возможность ООП.
Принцип
Смысл в том, что нам нужно создать свой собственный класс, который будет наследовать исходный класс и заменять его методы.
Для примера заменим некоторые методы miniShop. Создаем файл /core/components/minishop/model/minishopext.class.php:
<?php
//загружаем код класса miniShop
require_once 'minishop.class.php';
// extends - это и есть расширение/наследование
class miniShopExt extends miniShop {
// Тут мы инициализируем родительский класс
function __construct(modX &$modx,array $config = array()) {
return parent::__construct($modx, $config);
}
// Если назвать метод, как в родительском класе - это будет замена
// Если нет - добавление нового метода
function addToCart($id, $num = 1, $data = array()) {
// Копируем сюда исходный метод и меняем в нем, что нам нужно
}
function remFromCart($key) {
// И тут. Можно хоть весь класс переписать заново.
}
function newMethod() {
// А это новый метод, пишем тут свой код
}
Мы подключили родительский класс, но не инициализировали. Запускать его мы будем через свой новый класс — miniShopExt.Значит, нам нужен теперь сниппет, для запуска нового класса. Можно просто переименовать сниппет miniShop в miniShopExt, или скопировать.
Теперь меняем в новом сниппете инициализацию класса с miniShop на miniShopExt:
if (!isset($modx->miniShop) || !is_object($modx->miniShop)) {
$modx->miniShop = $modx->getService('minishopext','miniShopExt', $modx->getOption('core_path').'components/minishop/model/minishop/', $scriptProperties);
if (!($modx->miniShop instanceof miniShopExt)) return '';
}
Видите, мы запускаем класс miniShopExt из файла minishopext(.class.php) и сохраняем его в переменную $modx->miniShop, чтобы не переписывать весь сниппет.miniShopExt унаследовал все методы от miniShop, кроме тех, которые прописаны в нем самом. Теперь нужно только заменить вызов сниппета [[!miniShop]] в корзине на [[!miniShopExt]].
Заключение
Вот таким способом мы можем изменять любой сторонний класс как нам нужно. Самое главное — мы не лезем в чужой код и не теряем будущие обновления.
Это вообще очень хорошая практика: не хакать чужой код, а наследовать и расширять. В любой момент вы можете инициализировать оригинальный класс, или свой, расширенный.
Комментарии: 28
Класс) То что я искал!
Мегареспект
Мегареспект
Почему вот такая конструкция не работает в классе miniShopExt
$this->config['tplPaymentRow'] и аналогичные
$this->config['tplPaymentRow'] и аналогичные
Разобрался, эти настройки берутся из сниппета, а у меня все аяксовые запросы выполняются через свой сниппет у которого никаких настроек не прописано.
Сделал вот так в расширении класса miniShopExt. Работает. Если это не правильно поправьте
function __construct(modX &$modx, array $config = array()) {
$snippet = $modx->getObject('modSnippet',array('name'=>'miniShop'));
$config = array_merge($snippet->getProperties(),$config);
parent::__construct($modx, $config);
}
Сделал вот так в расширении класса miniShopExt. Работает. Если это не правильно поправьте
function __construct(modX &$modx, array $config = array()) {
$snippet = $modx->getObject('modSnippet',array('name'=>'miniShop'));
$config = array_merge($snippet->getProperties(),$config);
parent::__construct($modx, $config);
}
Лично я переименовываю miniShop в miniShopExt, меняю вызов класса и дописываю нужные методы, а все параметры остаются.
А ваш метод ничем не хуже, главное, чтобы сниппет miniShop никуда не делся, иначе будет fatal error.
Ну и минимум на пару операций с БД выходит больше (достать сниппет, а потом его параметры).
А ваш метод ничем не хуже, главное, чтобы сниппет miniShop никуда не делся, иначе будет fatal error.
Ну и минимум на пару операций с БД выходит больше (достать сниппет, а потом его параметры).
А после обновления оригинального класса придется менять и измененный класс?
Нет, конечно — в этом и смысл.
Тогда я не пойму что именно вы делаете? вы спиннете переименовываете или название класса в minishop.class.php?
Я переименовываю сниппет.
Я подключаю в переименованном сниппете расширенный класс.
Тот в свою очередь запускает оригинальный класс.
При обновлении перезаписываются оригинальный сниппет и оригинальный класс, а расширенные — нет.
Оригинальный сниппет больше вообще не используется, только расширенный — после каждого обновления его можно просто удалять.
Я подключаю в переименованном сниппете расширенный класс.
Тот в свою очередь запускает оригинальный класс.
При обновлении перезаписываются оригинальный сниппет и оригинальный класс, а расширенные — нет.
Оригинальный сниппет больше вообще не используется, только расширенный — после каждого обновления его можно просто удалять.
Теперь понял )
Глянул что в базе данных настройки сниппетов хранятся в сериализованном виде, можно их и одним запросом достать, и не будет объекта modSnippet. Но тут получается зачем нам тогда API MODX
Хочется делать сразу более менее оптимально
Хочется делать сразу более менее оптимально
Можно, да.
Только это уже какая-то экономия на спичках =)
Только это уже какая-то экономия на спичках =)
Я об этом как раз и задумался =)
Кстати задумался на счет двух операций с БД. Мне кажется что все таки создается объект modSnippet со всеми полями из БД. А уже метод getProperties работает с этим объектом, а не с БД.
Или я гоню?
Или я гоню?
Да, скорее всего.
А есть ли метод чтобы узнать размер памяти занимаемый объектом?
memory_get_usage, она показывает память, занимаемую скриптом.
Поэтому, надо запускать функцию до и после создания объекта, потом отнимать одно значение от другого — получите примерный вес объекта.
php.net/manual/en/function.memory-get-usage.php
Поэтому, надо запускать функцию до и после создания объекта, потом отнимать одно значение от другого — получите примерный вес объекта.
php.net/manual/en/function.memory-get-usage.php
Вот спасибо. Буду экспериментировать))
Еще раз спасибо
Еще раз спасибо
Получается что вот это кусок кода
// Получаем сниппет miniShop, если не можем — ошибка
if (!$snippet = $modx->getObject('modSnippet',array('name'=>'cart'))) {return 'Error: can`t found miniShop snippet';}
// Нам нужны параметры сниппета
$scriptProperties = $snippet->getProperties();
Кушает 650 кб
// Получаем сниппет miniShop, если не можем — ошибка
if (!$snippet = $modx->getObject('modSnippet',array('name'=>'cart'))) {return 'Error: can`t found miniShop snippet';}
// Нам нужны параметры сниппета
$scriptProperties = $snippet->getProperties();
Кушает 650 кб
Спасибо!
Подскажите пожалуйста как расширить класс minishop2. В minishop2 нету сниппета minishop. Правильно ли я понимаю что нужно копировать все сниппеты minishop2(msOrder, msCart и прочие) и в них уже менять инициализацию класса с miniShop на свой, наследованный от miniShop?
Сделал свой класс
1. Создал core/components/minishop2/model/minishop2/minishop_my.class.php и там прописал класс
В новых сниппетах заменил
Сделал свой класс
1. Создал core/components/minishop2/model/minishop2/minishop_my.class.php и там прописал класс
<?php
//загружаем код класса miniShop2
require_once 'minishop2.class.php';
// extends - это и есть расширение/наследование
class miniShop_my extends miniShop2 {
// Тут мы инициализируем родительский класс
function __construct(modX &$modx,array $config = array()) {
return parent::__construct($modx, $config);
}
}
2. Скопировал сниппеты msOrder и msCart в msCart_my и msOrder_my соответсвенноВ новых сниппетах заменил
$miniShop2 = $modx->getService('minishop2');
на if (!isset($miniShop2) || !is_object($miniShop2)) {
$miniShop2 = $modx->getService('minishop_my','miniShop_my', $modx->getOption('core_path').'components/minishop2/model/minishop2/', $scriptProperties);
if (!($miniShop2 instanceof miniShop_my)) return '';
}
И заменил в корзине вызовы сниппетов msCart и msOrder на свои msCart_my и msOrder_my[[!msCart_my?
&tplOuter = `tpl.msCart.outer_my`
&tplRow = `tpl.msCart.row_my`
]]
[[!msOrder_my?
&tplOuter=`tpl.msOrder.outer_my`
&tplSuccess=`tpl.msOrder.success_my`
]]
Но Корзина выдает «Ошибка сервера 500»
В miniShop2 предусмотрен механизм расширения классов, отвечающих за разные части функционала.
Менять сам minishop2.class.php вовсе не нужно.
Менять сам minishop2.class.php вовсе не нужно.
Я расширил класс msOrderHandler, чтобы организовать свою логику стоимости доставки. Но мне, например, нужно поменять работу функции changeOrderStatus из minishop2.class.php. Не подскажите как мне грамотно это сделать?
Внимательно посмотри на эти строки в методе changeOrderStatus.
Ну и стандартный метод вызывает кое-какие события перед и после изменения статуса заказа.
Ну и стандартный метод вызывает кое-какие события перед и после изменения статуса заказа.
одна из самых полезных статей на ресурсе… почему я раньше ее не видел(
А как расширить скрипт на фронте дополнения?
Как правило, у большинства дополнений есть системная настройка с адресом до JS-файла на фронте. Меняете ее, создаете копию файла и изменяете его как душе угодно.
Я имею ввиду, сделать копию компонента. Основное дополнение свою работу выполняет, а копия выполняет другую работу. Если в php есть extends, то как с js быть?
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.