Подгрузка "классных" процессоров средствами API MODX
Сразу уточню, что материал рассчитан в основном на тех, что уже использует процессоры, знает что это такое и как их готовить. И вообще этот материал многим может показаться сухим и не интересным. Но кто программирует (Илья, это тебя особенно касается;-)), обязательно надо изучить материал. Поверьте на слово, что это очень мощный инструментарий. Я не раз уже поднимал тему подгрузки файлов-процессоров средствами API MODX. Раньше, когда у нас процессоры были просто php-файлами, нас это вообще не интересовало, мы просто выполняли action) и все. MODX делал require этого файла и все, возвращал полученный результат. Сейчас же у нас процессоры стали гораздо умнее — их можно расширять другими процесс-классами и т.п. Процессоры сегодня могут содержать очень мощный функционал, и это часто полностью законченные, самостоятельные классы. Так зачем нам писать кучу лишнего кода, когда мы можем использовать уже готовые классы, переопределить их и заставить работать под свои нужды? Рассмотрим стандартный механизм работы процессора (здесь и далее будем рассматривать только «классные» процессоры). Мы выполняем modx->runProcessor(params, processor_absolute_path. И тогда нам доступен сам класс процессора. Но в чем здесь проблема? Во-первых, элементарно не удобно. То есть каждый раз нам надо писать актуальный путь до процессора. А если мы его переместили, и вообще в другой пакет? Идти высчитывать кол-во методов dirname(), писать папки и т.п. Во-вторых, отсутствие стандартного метода и единых проверок может даже привести к фатальным ошибкам. В общем, я и с Джейсоном пытался этот вопрос обсуждать, но как-то мы не пришли к какому-то единому знаменателю (я Джейсона пытался убедить в необходимости ввести метод типа modX::loadProcessor()). А вот Марк Mark-H мне сегодня подкинул очевидную идею — использовать modx->addPackage(path); и далее уже выполнять подгрузку файла процессора так: classname, '', false, true); (третий параметр false указывает на то, что не надо игнорировать подключенные пакеты, и надо искать по их папкам, а четвертый параметр true указывает на то, что надо игнорировать класс работы с базой данных (ведь у нас это просто процессор)). Все. Теперь не надо высчитывать пути. Как этот процесс максимально оптимизировать? Каждый раз писать $modx->addPackage() мягко выражаясь — не очень удобно. Потому лучше само собой добавить это в extensionPackages. Но надо учитывать две задачи:
-
Уникальность имен пакетов (то есть нельзя два пакета назвать processors, при этом именно название пакета плюсуется к конечному пути пакета). А ведь нам очень желательно, чтобы процессоры лежали в папке processors, чтобы не рушить стандарты (тот же processor-плагин пакета modxSmarty ищет процессоры именно в папке processors).
-
Возможность указывать несколько пакетов с процессорами. В общем, обычно экстеншены ведут к папке component/model/packageName/. Нам этот путь не подходит, так как противоречит вышеизложенным правилам. Значит делаем два пакета. Один ведет в component/model/packageName/ (он нам нужен для хранения основных классов, в том числе и тех, которые работают с базой данных), а второй в component/processors/packageName/. Через консоль выполняем два запроса: modx->getService(class); То есть у нас всегда в MODX будет свой объект modx->addExtensionPackage('myProcessors', '[[++core_path]]components/myPackage/processors/'); А вот это уже мы добавили папку для наших процессоров. То есть надо будет создать папку myPackage в [[++core_path]]components/myPackage/processors/, и там создавать наши процессоры. Код нашего сервис-класса будет выглядеть так: class myClass{ public $modx = null;
function __construct(modX & modx) { this->modx = & $modx; }
public function loadProcessor(fqn){ return this->modx->loadClass(fqn, '', false, true); } } То есть теперь, чтобы не писать каждый раз эти лишние 3 параметра, можно просто выполнять modx->myservice->loadProcessor(classname знак точки — это разделитель директорий, то есть. И вот теперь один небольшой пример: instance = myclass::getInstance(modx, 'myclass' )){ response = response->getResponse()); } В данном случае мы могли не только стандартный метод processs выполнить, но и любой другой дозволенный. Так же если вы свои процессоры пишите, и какие-то зависят от других, то теперь не обязательно писать require_once, а можно использовать этот метод, выполняя в начале кода modx->modxsite->loadProcessor(), возвращающий реальное название процесор-класса. Обкатывать это будет уже в процессе. UPD2: Обновленная сборка с новым методом this — это текущая инстанция MODX-а. При вызове же через this — это this в этих классах. Понятно, что мало кто этот хук вообще использует, но тем не менее. Можно было бы использовать modx->loadProcessor() использовать исключительно для подгрузки только тех процессоров, которые не используют переменную this instanceof modX){ modxsite = & this->modxsite; } else{ modxsite = & this; } $modxsite->loadProcessor('class'); Но учтите, что хотя если вы про это и забудете, оно будет работать, но по хорошему, лучше этим не злоупотреблять. Только если у вас стабильная выработанная методология. В принципе по мне, так это меньшее зло, чем require_once abs_path;