Николай Ланец
30 июня 2013 г., 21:45

Отключение парсера и PHP-код в шаблонах MODX Revolution

Почти 8 часов утра. За трое суток поспал часов восемь, но не могу уснуть и не поделиться своими идеями (которые пол-ночи проверял на работоспособность, и она подтвердилась).
Сразу скажу, что материал может послужить поводом для серьезных холиваров, но очень хотелось бы, чтобы споры если и будут, то чтобы были конструктивными, так как то, что я замыслил, для многих может показаться просто кощунством, особенно для тех, кто не представляет для себя программирования на MODX без использования MODX-тегов. Я ни в коем случае не хочу сказать, что на данное решение всем надо переходить поголовно, но всерьез считаю, что это серьезный прорыв, так как сожет не только на порядок снизить системные требования к хостингу, но и серьезно прибавить производительности. Правда для этого потребуется полное программирование на PHP без использования синтаксиса MODX (конечно будут места для маневров, но в целом расчет на отказ от парсера).
Итак, с описания моего личного отношения к разработке на MODX, и что мне не нравится.
Уже довольно давно я практически не использую MODX-тегов. То есть вообще минимум сторонних компонентов, минимум чанков и т.д. А есть сайт, который я полностью напрограммировал на Смарти, и единственное что там было для парсинга, это [[*pagetitle]] и т.п., то есть все то, что легко можно было закинуть в Смарти, но было видимо лень. Так вот, не смотря на то, что парсить было практически нечего, само собой MODX в любом случае подключал свой парсер, и парсил весь выплевываемый контент, даже если это несколько мегабайт sitemap.xml, и там вообще нет тегов. То есть это бессмысленная трата ресурсов.
Другая вещь, которая мне очень не нравится, это невозможность использования PHP-кода напрямую в MODX-шаблонах. Даже если у меня сайт на Смарти, и у меня вся логика прописана в PHP, я все равно должен в шаблон воткнуть хотя бы один сниппет, который был бы обработан парсером, и только после того, как был бы полностью обработан объект modResourse. Очень меня расстраивал тот факт, что в шаблонах нельзя сразу писать PHP-код.
Плюс ко всему MODX-парсер — это самый большой источник уязвимостей MODX, так как для воздействия на него из вне только то и надо, что суметь скормить ему строку.
Так же я считаю не идеальной систему шаблонов в MODX, то точнее какой-то не комплексной или не доработанной (сложно слова подобрать). Объясню: я уже говорил, что MODX-шаблоны выполняют две задачи (связь шаблон-TV и индивидуальное оформление страницы). Но шаблон не является инструментом общего оформления всего сайта (то есть темой, скином). Как в том же Livestreet — есть папка шаблонов (скинов), в конфиге указал только название нужного шаблона, и все, весь сайт поменялся. Закинул новый шаблон, и опять полностью сменил оформление сайта. В MODX этого нет. У меня постоянное ощущение того, что к шаблонам не хватает еще одного объекта: темы. То есть грубо говоря должна быть Тема, а создаваемые шаблоны просто привязываются к нужной теме и все. То есть конечное оформление происходит именно в теме, а не в шаблоне от head и до подвала. (К слову, у меня есть альтернативная идея завязывать шаблоны на категориях, чтобы документы, имеющие разные шаблоны, но одной группы, на выходе прогонялись через некий конечный шабло-тему. Но сейчас речь не совсем об этом). В общем лично для себя я увидел выход именно в использовании Smarty на уровне MODX, тем более, что она там стоит по умолчанию, и ее просто надо задействовать для своих целей. Но если мы используем Смарти, и пишем на чистом PHP, то зачем нам MODX-парсер и бездумный парсинг конечного кода? Как бы то ни было, это все-таки регулярные выражения, плюс лишние объекты и действия. В общем я всерьез задумался над тем, насколько вообще реально отключить MODX-парсер, но так, чтобы код не затронуть. И я нашел такое решение (саму теорию сейчас выставляю на обсуждение, а готовый пакет выпущу на днях, когда все как следует обкатаю и соберу).
Итак, парсер — это объект modParcer. Он не является неотъемлемой частью MODX-а. В админке он инициализируется сразуу же в index.php (метод $modx->getPaser()), во фронтенде он инициализируется в объекте modResponse, а в коннекторах он вообще не инициализируется (запросы обрабатываются объектами modConnectorRequest и modConnectorResponse, и там парсер не инициализируется). Но MODX позволяет нам указать свой собственный класс-обработчик запросов, в котором мы как раз и может убрать весь лишний код, связанный с инициализацией парсера и самим парсингом. Уверен, для крупных проектов это может быть очень действующим способом снизить нагрузку. Но это не убивает парсер. Если в каком-то исключительном случае будет не обойтись без использования парсера, то выход всегда есть. Можно создать сниппет, который будет работать примерно как getPage, то есть в него будет передаваться имя вызываемого объекта, его тип и параметры. В этом сниппете уже будет вызываться парсер MODX и прежде чем вернуть конечный контент, он будет парситься локально в этом сниппете.
Другая идея связана как раз с тем, чтобы заставить шаблоны обрабатывать чистый PHP-код. Вот тут все оказалось гораздо сложнее, но решение все равно нашлось, и это очень радует. К сожалению нельзя просто так заставить modTemplate обрабатывать PHP, да и modResource-у это не очень нравится (если документ кешируемый, то полученный конечный код из шаблона все равно присваивается документу и кешируется, и в следующий раз PHP-код уже не выполняется). Но здесь в помощь пользовательские ресурсы. Конечный пакет так же выпущу чуть позже, а пока краткая теория: 1. Создаем свой объект шаблона, расширяющий modTemplate. В метод process() прописываем проверку, что если это не статический шаблон, то выполнять родительский process(), а иначе глобалим $modx (чтобы был виден «внутри» кода шаблона), и инклюдим файл. При чем вообще не страшно, если там HTML или HTML в перемешку с PHP. Проблем не возникает, все тоже самое, что и просто проинклюдить php-файл. 2. Создаем пользовательский ресурс, расширяющий modResource, со всеми положенными MySQL-классами. В map-классе этого объекта нам только и надо что сделать, так это переопределить класс шаблона вместо modTemplate. 3. Чуть-чуть переписываем функцию process() этого объекта и все. Исполнение PHP-кода в шаблонах готово. Остается только добавить наш новый тип ресурсов в меню выбора типа ресурса. В общем все будет понятней, когда будет готов пакет. Но в целом это решение все равно дает понять, что не все идеально. Ведь нам только и надо было, что создать новый класс шаблона. Вот класс ресурса можно менять через интерфейс, а класс шаблона нет. Предусматривается только modTemplate. А подгрузка шаблона происходит через метод modResource::getTemplate(), в котором четко прописано $this->getOne('Template'). И здесь не предусматривается смена класса шаблона. Так что скорее всего хотя я и выпущу пакет для тех, кому будет интересно, да и так, по мелочи использовать, но в серьезных проектах скорее всего буду править методы process в modTemplate и modResource. Там поправить надо будет всего строчек пять кода, но это обеспечит наилучший эффект.
UPD: Идея получила продолжение в виде пакета phpTemplates. http://modxclub.ru/blog/111.html

Добавить комментарий