Не могу точно сказать как давно в MODX Revolution появился метод addExtensionPackage() (скорее всего начиная с версии 2.2), но могу точно сказать, что на этот метод надо обратить внимание любителям писать свои эддоны. В чем его суть? Он позволяет указывать MODX-у, какие пакеты подключать при инициализации движка. Это будет более понятно тем, кому приходилось подключать свои пакеты через $modx->addPackage(), чтобы можно было работать со своими объектами через стандартные методы $modx->newObject(), $modx->getObject() и т.п. Просто если вы написали свой пакет, и его классы не находятся в папке core/model/modx/, то просто так к этим объектам нельзя обратиться, необходимо «дать знать» MODX-у, где эти объекты хранятся. Для этого как раз и существует метод $modx->addPackage(). Но в чем проблема? Проблема в том, что приходится каждый раз думать о том, чтобы пакет обязательно был подключен, и для этого как правило создается плагин, срабатывающий по событию onHandleRequest, или кто как изворачивается. С плагином сразу проблема возникает: при запросах на коннекторы просто так не вызываются события, их вызов приходится дописывать. В общем тонкостей довольно много. Но лично я для себя использую в качестве решения большинства этих головняков метод $modx->addExtensionPackage(); Вызывая этот метод с указанием названия своего пакета (класса) и пути до пакета, MODX записывает эти данные в системную настройку extension_packages. То есть таким образом мы выполняем «подключение» пакета, и выполняется это всего один раз. К примеру $modx->addExtensionPackage('mypackage', '[[++core_path]]components/mypackage/model/'); После того, как вы выполните этот скрипт и данные о пакете появятся в настройке extension_packages, каждый раз при инициализации контекста будет выполняться подключение указанных пакетов. И да, именно возможность указания настроект для конкретных контекстов, позволяет четко управлять, где будут пакеты подключаться, а где нет. Вообще этот метод описан для кастомных типов документов, но годится для многих случаев. Правда пока очень глубоко не вдавался, но есть подозрения, что он не хочет таким образом подключать пакеты внутри папки /core/model/modx/, в частности пакет sources не хочет подключать никак.
В этот раз постараемся разобраться с методами проверки прав доступов ->hasPermission() и ->checkPolicy(); Я не буду в этом топике рассказывать как в принципе создавать Роли, группы пользователей, настраивать доступы к контекстам и группам ресурсов. Об этом написано не мало. Но так как многие настраивая эти политики (то есть зная где это делается) часто не получают желаемого результата (то есть не всегда понимают как что работает), то в этом топике я опишу принципы проверки прав к контекстам и ресурсам, чтобы каждый всегда мог проверить что и куда у него разрешено и где что работает или нет. Итак, для начала повторно отметим, что для проверки прав есть два метода:
Сейчас столкнулся вот с какой проблемой: решил переместить один из документов на уровень выше, но MODX вернул ошибку сохранения документа. Это было довольно странно, так как этот документ я создал несколько минут назад, и я его легко мог редактировать и сохранять. Проблемы возникала именно при попытке пересортировать дерево. Полез ковырять системный процессор… Оказывается проблема была вовсе не в доступе к этому ресурсу, а в доступе к другому ресурсу, который находился в группе ресурсов, на которую я не имел прав save. Но так как при пересортировке дерева MODX пытается сохранить все задействованные документы (у всех же в этом уровне ранг меняется), и он проверяет права на сохранение каждого ресурса, то он и вернул ошибку, и не сохранил мой ресурс. Конечно плохо, что ошибка общая, типа «Не удалось выполнить сохранение». Было бы лучше, если бы он сразу сообщал к какому именно ресурсу нет доступа. Это бы очень упросило понимание проблемы. В общем в таком случае необходимо донастроить права.
Мы уже разговаривали о кешировании и парсинге здесь и здесь. И вот еще небольшая порция информации для размышления. Что мы имеем? Небольшой сайт-визитку с каталогом. На главную выводится помимо парочки менюшек еще и главный источник проблем в области производительности — галерея товаров с использованием пакета Gallery. В принципе у нас главная не меняется, потому у нас стоит задача максимально закешировать документ, чтобы вообще летало. Посмотрим какой производительности можно добиться, применяя кеширование. Сразу вкратце обрисую схему работы документа: в шаблоне только один исполняющий сниппет, который подгружает PHP-файл и там уже происходит основная работа. То есть по идее, если мы сделаем этот сниппет кешируемый, у нас должно получиться максимальное кеширование. Посмотрим. Вариант 1. Документ не кушируемый вообще. Генерация страницы 760-900 мсек. Вариант 2. Документ кешируемый, сниппет не кешируемый. Генерация 630-700 мсек. Вариант 3. Сниппет полностью кешируемый. Генерация 217-275 мсек. Итак, у нас полное кеширование корневого сниппета. А генерация 200+ мсек. В чем проблема? Проблема в том, что внутри этого сниппета могут встречаться другие некешируемые элементы. Но даже если эти элементы кешируемые, в кеше документа все равно не будет сплошного HTML-кода, а будет массив кешируемых элементов с их значениями, и все равно при каждой загрузке страницы MODX-парсер будет пробегаться по этим элементам и заменять их на их значения. Вот часть кеша этой страницы: '[[$webim.output]]' => '<div style="margin: 0 0 0 16px;">
<!-- webim button --><a href="/webim/client.php?locale=ru" target="_blank"onclick="if(navigator.userAgent.toLowerCase().indexOf('opera') != -1 && window.event.preventDefault) window.event.preventDefault();this.newWindow = window.open('/webim/client.php?locale=ru&url='+escape(document.location.href)+ '&referrer='+escape(document.referrer), 'webim', 'toolbar=0,scrollbars=0,location=0,status=1,menubar=0,width=640,height=480,resizable =1');this.newWindow.focus();this.newWindow.opener=window;return false;"> <img src="/webim/button.php?i=webim&lang=ru" border="0" width="163" height="61" alt=""/> </a><!-- / webim button -->
</div>', '[[~9]]' => 'chugunnie_radiatory.html', Может не очень видно, но это ассоциативный массив с двумя ключами: '[[$webim.output]]' и '[[~9]]'. То есть как мы не старались, у нас все равно документ закеширован не идеально. Но нам есть еще что сказать… Вариант 4. Парсим полученный сниппетом контент. Итак, прежде чем в сниппете выполнить return $output, выполняем следующее: дописываем перед return парсинг имеющегося контента. $maxIterations= intval($modx->getOption('parser_max_iterations', null, 10)); $modx->parser->processElementTags('', $output, true, false, '[[', ']]', array(), $maxIterations); $modx->parser->processElementTags('', $output, true, true, '[[', ']]', array(), $maxIterations); Таким образом мы уже на уровне сниппета обработаем все MODX-элементы в полученном контенте, и в кеш страницы запишется в качестве значения нашего сниппета чисто конечный HTML-код. И что мы имеем на выходе? Генерация страницы 84-100 мсек. Много или мало? Для сравнения если прописать в index.php exit сразу перед выполнением $modx->handleRequest();, то есть MODX проинициализируется, но не начнет еще обрабатывать запрос и генерить страницу, это время составит 60-70 мсек. Но даже это еще не все. Я уже писал про свои шаблоны, в которых будет выполняться чистый php-код. То, как MODX работает сейчас, хочу я или нет, но хотя бы один сниппет MODX-парсер вынужден обработать, который прописан в шаблоне. Выполнение же php-кода на уровне шаблона позволит получать из пользовательского кеша полный HTML-код страницы, и отдавать этот код сразу браузеру, не дожидаясь работы MODX-парсера. Скорее всего даже здесь это добавит еще как минимум 10 мсек. экономии. Так что работа в этом направлении продолжается.Очень прошу подключиться к дискуссии знатоков шаблонизатора Twig. Да и знатоки MODX Revolution тоже мимо не проходите;-) Утром я писал про свои наработки в области «MODX без парсера» и «Статические шаблоны с PHP-кодом». И вот сегодня эта история получила продолжение. Общался с Райном Трешем об этом, и он очень заинтересовался данным решением. При этом он написал следующее: this almost begs the question (but I think I know) why are you using MODX CMS at all then, and not just using xPDO + Smarty?
Почти 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-код уже не выполняется). Но здесь в помощь пользовательские ресурсы. Конечный пакет так же выпущу чуть позже, а пока краткая теория:
Итак, предлагаю всем, кому интересно и кто силен в php, установить и обкатать phpTemplates. Источники: sourceforge.net/projects/modxphptemplate/ (готовый пакет) github.com/Fi1osof/phptemplates Этот пакет устанавливает в систему новый тип ресурсов (phpTemplateResource) и новый тип шаблонов (phpTemplate). Это решение позволяет в статических MODX-шаблонах писать не только HTML-код и MODX-теги, но и php-код, то есть подгружает такие шаблоны как обычный php-файл. Это позволяет непосредственно в шаблоне писать чистый php-код с использованием API MODX и без него, использовать сторонние шаблонизаторы (такие как Smarty) и так далее. Обратная сторона медали (пока до конца не исследована, потому и надо как можно больше тестов): данное решение направлено на то, чтобы как можно меньше использовать MODX-парсер (в перспективе вообще отказаться), и как можно больше писать на чистом php. Велика вероятность того, что при использовании большого числа MODX-тегов производительность может понизиться. Так же при использовании таких шаблонов управление кешем придется полностью брать на себя, то есть использовать $modx->cacheManager, кеширование шаблонизаторов и т.п. Но в руках опытного программиста это стать очень гибким инструментом. P.S. Отдельное спасибо proxyfabio за участие в разработке пакета! UPD: Пакет phpTemplates теперь доступен в официальном репозитории.
Данный урок больше всего будет полезен именно новичкам, особенно тем, у кого либо вообще нет опыта разработки на MODX, либо очень маленький опыт. В первом «сравнительном» уроке я постарался перечислить все элементы (объекты), присутствующие в MODX Revolution (хотя вряд ли смог все перечислить). В этом уроке мы постараемся классифицировать их, чтобы понять, что для чего нужно. Сразу определюсь, под каким углом мы будем все это рассматривать: мы постараемся разобраться, для разработки на каком уровне будет достаточно знать только HTML, не имея опыта программирования на PHP, а на каком уровне без PHP уже обойтись будет нельзя. Забегая вперед скажу, что довольно много можно сделать без знания PHP, и даже такие объекты, как сниппеты и плагины, которые в принципе содержат в себе PHP-код, и то можно использовать без знания PHP, если использовать именно сторонние решения, и есть достаточно внятная документация по использованию. Итак, для начала попробуем просто своими словами определить два уровня разработки: Просто сборка сайтов из готовых компонентов. Индивидуальный сайт, со своим уникальным функционалом. Уточню: в данной статье будет больше материала именно для первого уровня разработки. Так что же нам дает MODX Revolution, как среда разработки сайтов? А дает он многое. На нем можно создавать как простые сайты-визитки, так и очень серьезные проекты. И в зависимости от того, какие стоят задачи, для разработки своего проекта можно будет ограничиться даже набором стандартных готовых решений (типа Wayfinder, getResources и т.п.), а где-то уже потребуются серьезные знания и опыт веб-разработок, но зато даже в базовой сборке MODX Revolution способен дать инструментарий для разработки веб-разработчикам любого уровня. Главное только понимать что для чего нужно. Пойдем по порядку. Ресурсы (modResource) По сути основа любой страницы сайта. Содержит все основные параметры страницы (краткий и длинный заголовок, описание, пользовательский контент и т.п.). Здесь вообще все просто, разобраться даже блондинка сможет (с подсказками), которая хотя бы в ворде работала. ? В настройках страницы можно указать (или увидеть, если уже указано) родительский ресурс, даты публикации и отмены публикации, является ли страница контейнером и т.п. ? Так же можно указать тип документа. По умолчанию это HTML, но можно указать и другой тип, к примеру XML. ? Тип документа влияет на то, какие заголовки будут отправлены сервером браузеру, суффикс страницы в адресной строке (если используется ЧПУ) и т.п. Помимо стандартных типов документов, можно создать сколько угодно своих. ? ? ? В третьей вкладке управления ресурсом можно указать к каким группам ресурсов данная страница относится. ? Сейчас никаких групп ресурсов не создано, потому и выбрать нечего. Более детально группы ресурсов разберем в одном из последующих уроков. Скажу только, что это напрямую связано с распределением прав доступов к странице. Можно создать группы ресурсов, разрешить, к примеру, просмотр их только зарегистрированным пользователям, отнести страницу к данной группе ресурсов, и уже эту страницу увидят только зарегистрированные пользователи. Шаблоны (modTemplate) С шаблонами все просто, и все сложно. Простое расскажу сейчас, для объяснения более сложного посвящу отдельный урок. Шаблоны выполняют две задачи:
СущностьОписание MODX EvolutionMODX Revolution Базовые элементы Категории++ РесурсыMODX-документы++ ШаблоныШаблоны для оформления документов++ Параметры TVДополнительные параметры для шаблонов (TV — это не телевизор, о чем кстати и значек в админке Рево намекает, а Template Variable). Позволяет создавать дополнительные поля для документов++ ЧанкиБлоки HTML-кода++ СниппетыБлоки PHP-кода++ ПлагиныБлоки PHP-кода, выполняемые по системным событиям. Позволяют вклиниться в логику движка и отдельных компонентов.++ МодулиРасширения MODX. Могут использоваться не только как расширения оформления и функционала админки, но и как единое хранилище пользовательских переменных для связанных элементов, таких как чанки, сниппеты, ресурсы и т.п.+- Наборы параметровНаборы параметров можно передавать в качестве аргумента элементам, таким как чанк или сниппет, и значения набора параметров будут переданы этому элементу. Только надо иметь ввиду, что для этого набор параметров должен быть связан с этим элементом. В данном плане суть набора параметров напоминает суть Модулей в Evolution, только имеет преимущество в том, что одному элементу может быть привязано сразу несколько наборов параметров, и на уровне синтаксиса эти наборы можно переключать. В Эво с модулями такой фокус не пройдет.-+ КонтекстыКонтексты позволяют создавать несколько сайтов на одном движке. Вообще у контекстов очень много сфер преминения, не буду сейчас все расписывать, это тема для отдельного топика.-+ ДействияПо сути это элементы оформления админки. Можно самому переиначить все пункты меню, скрыть ненужные пункты, создать свои, ограничить права и т.д. Роль Действий в Эво выполняют Модули, с той разницей, что в Эво Модули — это чисто пользовательские элементы, а в Рево Действия — это в общем. То есть в Эво вы не сможете через админку удалить все элементы и пункты меню админки, а в Рево можно.-+ Пространства именПозволяют создавать более обособленные модули, что улучшает управляемость отдельными компонентами всей Системы-+ Источники файловПозволяют в одной системе создать сколь угодно источников файлов, что позволяет для отдельных компоненов сразу указывать где хранить пользовательские файлы и какие пути до них формировать. На сегодня Рево нативно поддерживает два типа источников файлов: 1. Файловая система 2. Хранилища Amazon S3-+ Группы ресурсовПозволяет объединять ресурсы в отдельные группы. Это удобно в том плане, что можно настроить доступы к отдельным группам ресурсов.++ Web-пользователиВ Эво простые пользователи и пользователи-менеджеры, это отдельные сущности со своими таблицами. Для этого даже отдельно есть «Управление веб-пользователями» и «Управление менеджерами», а так же «Права веб-пользователей» и «Права менеджеров». Не очень круто… В Рево есть только Пользователи. Какие права имеют каждый пользователь в отдельности или группа пользователей, определяют настройки политик безопасности.++ Менеджеры+- Шаблоны политик доступовПозволяют создать «заготовки» для политик доступов. В Эво это частично присутствует, так как для создания пользовательских Ролей (наборов политик доступов) уже есть один общий шаблон политик, но во-первых, его нельзя редактировать через админку, а во-вторых, нельзя создать свой шаблон. В Рево это все можно делать.+-+ Политики доступаНаборы прав на те или иные доступы. В Эво и Рево это имеет несколько различающийся смысл. В Рево Политика доступа — это пока еще только набор тех или иных прав. Политика как бы не привязывается к конкретному пользователю. Политики проявляются только тогда, когда проверяются права доступа к тому или иному объекту, но на основе данных «Группа пользователя», «Ранг» и «Роль» (в общем сейчас в два предложения не уложиться и сейчас это все будет слишком запутанно. Обязательно все это рассмотрим потом в отдельной теме). Так вот, а в Эво это работает по другому. В Эво создается Роль (что по сути является Политикой доступов), и в данной Роли уже прописываются все права, какие будет иметь пользователь с данной Ролью. При чем когда вы редактируете пользователя, для него вы не указываете Роль, вы указываете только группу пользователя. Это и есть его права. При чем для Менеджеров необходимо создавать свои группы пользователей отдельно. И веб-пользователей нельзя поместить в группу менеджеров, и наоборот. Конечно, если быть еще более точным, то веб-пользователям в Эво как бы и вообще нельзя дать доступы. Можно только определить доступ отдельных групп пользователей к отдельным группам ресурсов, но определить какой группе веб-пользователей можно сохранять документы, а какие нет — нельзя. И еще уйма ограничений.+-+ Группы пользователейВ Эво группы пользователей несут только две функции: 1) Сгруппировать пользователей, просто для структуры. 2) Определить к каким группам ресурсов будет иметь пользователь группы. На этом все. В Рево все гораздо серьезней. Опять-таки, этот вопрос вынесем в отдельный топик. Скажу только, что пользователь с одной и той же Ролью может находиться в разных Группах пользователей, и иметь разные права, скажем, в зависимости от того, к какому контексту идет обращение. Так же Группа пользователя (в купе с настройками политик) будет определять уровни доступов к Контекстам, Группам ресурсов, Категориям элементов и источникам файлов. К слову, более мощной системы политик безопасности, чем в Рево, я не встречал ни в одном движке.++ Элементы управления Управление политиками безопасности++ Управление пользователями++ Управление системными настройками++ Управление пакетамиВ Эво нет такого инструмента, как Система пакетов. То есть нельзя устанавливать пакеты, удалять и т.п. Все приходится делать вручную.-+ Управление словарямиВ Эво тоже есть словари, но только на файлах. Управления словарями через админку там нет.-+
В данном топике рассмотрим различные примеры вызова сниппетов, и как это сказывается на кешировании. Для начала сразу уточним, что есть два метода вызова сниппетов: