Саша, привет! Вопрос: ты хочешь при Ajax-запросе оформить ответ в HTML? То есть тебе там нужен шаблонизатор?

Коля, добрый вечер. Решил добавить свои ajax-плюшки, написал процессор (.../basket/public/...), все работает. Возник вопрос: я не могу из этого процессора запустить smarty (чтобы через .tpl переписать часть странички). Как мне это сделать?

UPD:

  1. Пересмотрел часть логики с комментариями. В частности считаю, что любое действие над комментарием — это и обязательное действие над диалоговой веткой. То есть добавляем мы комментарий, или обновляем имеющийся — это и проверка доступов к диалоговой ветке, и выполнение update над ней (фикс последнего изменения и т.п.). В итоге, create-процессор комментария — это расширение update-процессора диалоговой ветки. 2. Добавил автоматический пересчет количества дочерних комментариев в самих комментариях и общего кол-ва комментариев в диалоговой ветке в целом при сохранении объекта нового комментария и удалении существующего. То есть даже если вручную в любом месте через xPDO создать или удалить объект комментария, пересчет автоматически будет выполнен. Это обязательно позволит существенно снизить нагрузку на сервер, так как всегда можно будет легко узнать сколько комментариев в диалоге вообще, и сколько дочерних комментариев в любом отдельном комментарии (это необходимо при построении дерева комментариев при разбивке на постраничность). Надо вот еще будет серьезно подумать над тем, как лучше получать список комментариев.

Это не решение проблемы в целом. Я описывал, что здесь проблема как раз в пустом ключе сессии. Конечно, завершив все сеансы (удалив записи сессий из БД) и авторизовавшись снова, у вас будет новая сессия с нормальным ключом. Но вообще не исключается вариант, что через некоторое время у вас опять будет пустой ключ в сессии, и опять возникнет эта же проблема. Вот здесь я писал хоть и хардкорный, но все таки действенный фикс этой проблемы: forums.modx.com/thread/85173/after-upgrade-to-2-2-8-problem-access-denied-on-save?page=6#dis-post-476634

Такая же проблема решилась у меня последовательностью в админке:

  1. Безопасность -> перезагрузить права доступа
  2. Безопасность -> завершить все сеансы Выбрасывает на страницу логина, заходим заново, проблема ушла

Пожалуйста! Aсе в SDK не реагирует на пробел (то есть по клавише Space ноль эмоций) за пределами SDK, например при создании чанка все в порядке Отключите в настройках компрессию JS-ов в админке. Это бага у нас, которую еще предстоит пофиксить. 2) если возникает желание удалить Project в SDK — каким образом это можно сделать (случайно создал 2 с одинаковым именем — двойной выбор в Select Project)? Тоже пока не доработано (все руки не доходят, более важные задачи стоят). Пока что только через базу данных.

Топик: modxSDK, git и я

Доброго времени суток! Во-первых, спасибо за этот инструмент, его действительно не хватало, особенно когда приходится работать с разных компьютеров. Но возникли и вопросы и предложения.

  1. установлен modx 2.2.10, язык панели — русский, Aсе в SDK не реагирует на пробел (то есть по клавише Space ноль эмоций) за пределами SDK, например при создании чанка все в порядке
  2. если возникает желание удалить Project в SDK — каким образом это можно сделать (случайно создал 2 с одинаковым именем — двойной выбор в Select Project)?
Топик: modxSDK, git и я

Материал для экспертов. Заметка: будут использоваться примеры кода из minishop2 от bezumkin. Пусть никто не ищет подвоха, его здесь нет. Просто материал предметный, а проверить примеры может всякий, скачав его из репозитория. Кто захочет поиграться с примерами, лучше устанавливайте Console. В свое время у нас уже был очень сложный диалог по поводу xPDO::addDerivativeCriteria(), и вот только сейчас я разобрался со всей этой системой на 100%, и могу четко все разложить по полочкам и описать. В статье рассматривается поведение xPDO, когда у вас в одной таблице, в которой есть колонка class_key, хранятся записи нескольких производных классов. Эта ситуация широко известна. К примеру в таблице site_content хранятся записи производных modResource классов modDocument, modWebLink и т.п. Подробней обо всем этом можно прочитать здесь. Коротко: когда в таблице есть колонка class_key, то xPDO, получая записи из такой таблицы методами getObject(), getCollection() и т.п., возвращает конечные объекты именно тех классов, имена которых указаны в этих колонках. То есть, к примеру, сделав выборку трех записей из таблицы site_content, значения class_key которых будут modDocument, modWebLink и modSymLink, на выходе мы получим не 3 объекта modResource, а три уникальных объекта от соответствующих классов. Собственно, на этом и строятся CRC. Мы добавляем свой собственный класс, расширяя modResource, и при выборке $modx->getCollection('modResource'), вместе со всеми прочими документами, получаем и собственные объекты (чисто локальный пример). Но здесь есть очень много всяких тонкостей. И чтобы было проще их понять, рассмотрим на реальных примерах с использованием кастомного класса msProduct из пакета minishop2. Сразу уточню, что у меня документ с id=100 — это как раз документ с class_key=msProduct. Это важно запомнить, чтобы четко понимать результаты примеров. Пример $q = $modx->newQuery('msProduct', 100); $docs = $modx->getCollection('msProduct', $q); Вот здесь у нас с выполнением никаких проблем не возникло. Результирующий объект — инстанс класса msProduct, и все ОК. Теперь уберем id из условия, и выполним запрос, который вернет нам все документы. $q = $modx->newQuery('msProduct'); $docs = $modx->getCollection('msProduct', $q); И получим вот такие ошибки в лог: Instantiated a derived class modDocument that is not a subclass of the requested class msProduct Что это за ошибки и почему они происходят? Для этого стоит изучить метод xPDOObject::_loadInstance() ....... $instance= $xpdo->newObject($actualClass); if (is_object($instance) && $instance instanceof xPDOObject) { ....... $parentClass = $className; $isSubPackage = strpos($className,'.'); if ($isSubPackage !== false) { $parentClass = substr($className,$isSubPackage+1); } if (!$instance instanceof $parentClass) { $xpdo->log(xPDO::LOG_LEVEL_ERROR, "Instantiated a derived class {$actualClass} that is not a subclass of the requested class {$className}"); } То есть, если реальный инстанс полученного объекта не является инстансом запрашиваемого в getCollection() класса, то xPDO пишет ошибку. Следует отметить, что он все равно вернет полученный объект, но логи будут расти. То есть если мы заменим msProduct на modResource, то этих ошибок не будет. $q = $modx->newQuery('msProduct'); $docs = $modx->getCollection('modResource', $q); В данном случае мы запросили коллекцию объектов modResource, и так как все они — производные от modResource, то и ошибки нет. Но это еще совсем не все. Как в мультике — «Стрижка только началась»… Вот здесь стоит рассмотреть более внимательно код, и еще жду ответа от Джейсона Коварда о возможном баге. Собственно, ответ уже есть. Да, это бага. Тикет создан и он его обещал пофиксить прямо сейчас. Ну да ладно, баг — багом, но он нам не мешает дальнейшему рассмотрению поднятой темы. Итак, дело в том, что существует метод xPDOObject::addDerivativeCriteria(), который автоматически добавляет условие class_key в запрос. Давайте посмотрим код. public function addDerivativeCriteria($className, $criteria) { if ($criteria instanceof xPDOQuery && !isset($this->map[$className]['table'])) { if (isset($this->map[$className]['fields']['class_key']) && !empty($this->map[$className]['fields']['class_key'])) { $criteria->where(array('class_key' => $this->map[$className]['fields']['class_key'])); if ($this->getDebug() === true) { $this->log(xPDO::LOG_LEVEL_DEBUG, "#1: Automatically adding class_key criteria for derivative query of class {$className}"); } } else { foreach ($this->getAncestry($className, false) as $ancestor) { if (isset($this->map[$ancestor]['table']) && isset($this->map[$ancestor]['fields']['class_key'])) { $criteria->where(array('class_key' => $className)); if ($this->getDebug() === true) { $this->log(xPDO::LOG_LEVEL_DEBUG, "#2: Automatically adding class_key criteria for derivative query of class {$className} from base table class {$ancestor}"); } break; } } } } return $criteria; } То есть, если в описании запрошенного класса нет указания таблицы (что с большой вероятностью говорит о том, что запрошенный класс — производный), то в условие автоматически добавляется условие class_key=$className. К слову о баге: дело в том, что класс modResource наследуется не напрямую от класса xPDOObject, а от его производного modAccessibleObject, в котором метод loadCollection() переопределяется, без вызова родительского, и в этом методе не прописано $xpdo->addDerivativeCriteria($className, $criteria); То есть у нас не происходит автоматического добавления условия class_key. Если бы эта бага отсутствовала, то при запросе $modx->getCollection('msProduct', $q) xPDO автоматически бы добавил условие class_key=msProduct, и сделал бы выборку только записей с этим class_key. Это позволило бы избежать необходимости каждый раз прописывать $where = array('class_key' => 'msProduct'), как это сейчас делается в minishop2. При чем это касается как сниппетов, так и процессоров на выборки и т.п. (кстати, там есть тоже бага, о которой скажу чуть позже). Василий, бери на заметку, это тебе скорее всего пригодится: баг пофиксят, но не все сразу обновятся. Чтобы не писать во всех местах условие $where = array('class_key' => 'msProduct'), можно добавить два статических метода в класс msProduct public static function load(xPDO & $xpdo, $className, $criteria= null, $cacheFlag= true){ if (!is_object($criteria)) { $criteria= $xpdo->getCriteria($className, $criteria, $cacheFlag); } $xpdo->addDerivativeCriteria($className, $criteria); return parent::load($xpdo, $className, $criteria, $cacheFlag); } public static function loadCollection(xPDO & $xpdo, $className, $criteria= null, $cacheFlag= true){ if (!is_object($criteria)) { $criteria= $xpdo->getCriteria($className, $criteria, $cacheFlag); } $xpdo->addDerivativeCriteria($className, $criteria); return parent::loadCollection($xpdo, $className, $criteria, $cacheFlag); } Тогда при явных запросах $modx->getCollection('msProduct') условие class_key=msProduct будет автоматически добавлено, и будут возвращены только объекты msProduct. А при выборке $modx->getCollection('modResource') будут возвращены все объекты без разбора, включая msProduct. Но при формировании чистого SQL-я это не поможет, так как эти методы просто не будут вызваны. Но можно формировать запросы так (правда это уж совсем на заметку): $q = $modx->newQuery('msProduct'); $modx->addDerivativeCriteria('msProduct', $q); $docs = $modx->getCollection('msProduct', $q); Баг №2. Второй баг касается метода xPDO::getCount(). Этот метод так же формирует запрос без учета метода xPDO::addDerivativeCriteria(), в результате чего можно получить неверное количество найденных строк. Это особенно критично для GetList — процесоров. Когда первый баг пофиксят, не надо будет в List-процессорах дописывать условия where class_key=$className, как это сейчас используется в minishop2. Но при этом, скорее всего процессор вернет правильное количество объектов, но неправильное число найденных строк, так как он сначала выполнит подсчет строк без учета class_key= (и просто найдет все строки по критерию), а уже потом выполнит запрос с учетом class_key. Этот баг тоже будет пофиксен в ближайшее время. Момент 3. Наследование Итак, считаем, что у нас баги все пофиксены. Давайте теперь более внимательно рассмотрим наследование, и что это нам может дать (в том числе и ошибки). Мы уже отметили, что делая выборку $modx->getCollection('modResource'), мы получим все объекты с различными class_key, а делая выборку $modx->getCollection('modDocument'), мы получаем только объекты с class_key=modDocument (напоминаю, что сейчас это не так из-за багов, но мы договорились считать, что баги пофиксены). Такое поведение обусловлено тем, что в модели класс modResource четко описана таблица, и метод xPDO::addDerivativeCriteria() не добавляет условия class_key=$className, а в классе modDocument таблица не указана, и потому условие class_name=modDocument было автоматически создано. К слову, если добавить в описание класса modDocument 'table'=>'site_content', то xPDO вернет все записи, и создаст положенные записи об ошибках в лог. Ну да ладно, это так, уточнение. Итак, мы получаем довольно хороший механизм: мы можем создать единую таблицу для нескольких кастомных классов, хранить их записи в единой таблице, все объекты будут иметь уникальные ID, и нам не придется париться с написанием условий для выборки, все будет создаваться автоматически, и указывая в запросе базовый класс, мы будем получать все объекты, а указывая конкретный класс, будем получать объекты только этого класса. Просто обалденно! Но здесь есть еще один маленький момент. Рассмотрим его на примере все того же msProduct. Он у нас унаследован от класса modResource. Выполним вот такой запрос: $q = $modx->newQuery('msProduct'); $modx->addDerivativeCriteria('msProduct', $q); $docs = $modx->getCollection('modDocument', $q); Получаем все ту же ошибку Instantiated a derived class msProduct that is not a subclass of the requested class modDocument Дело в том, что и modDocument, и msProduct — дочерние классы от modResource, но msProduct не является дочерним классом от modDocument. Это очень важно понимать, чтобы правильно планировать свою структуру наследуемых классов. На этом пожалуй все. Надеюсь, материал кому-то был полезен.

Прикольно, но не сейчас. Я подумаю на счет этого в новой версии.