Николай Ланец
4 нояб. 2013 г., 16:36

xPDO::addDerivativeCriteria(), class_key, CRC и прочие связанные друг с другом тонкости

Материал для экспертов.
Заметка: будут использоваться примеры кода из 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. Это очень важно понимать, чтобы правильно планировать свою структуру наследуемых классов.
На этом пожалуй все. Надеюсь, материал кому-то был полезен.
Здравствуйте, это все понятно , а вот если мы захотим создать 2 класса наследуемые от 1 главного, да вот делать это все так чтобы поля в 2 производных ссылались на gxBox.. XPDO генерирует 3 таблицы 1 gxBox ,а в другие 2 таблицы просто унаследовались поля от родительской, а нам то надо чтобы gxBox была частью gxBoxWater или gxBoxAutomobil типо авто Join`ы, тут получилось мы наплодили таблицы а они не централизованы как в такой ситуации поступать? есть конечно альтернатива создать 1 таблицу gxBox и 2 дополняющих (уже без наследования) в gxBox добавить 2 composite по 1 на таблицу и обозвать их соответствующим именем класса, создать колонку в gxBox говорящую какой класс join`ить
$box = $getObject('gxBox',1); $target_class_object = $getObject($box->class_name,1)
блок кода не отображается
А зачем вам разные таблицы? И наследовать надо последовательно, а не два разных класса от одного родителя.
Спасибо за ответы, Пример кода тут скорее видно зачем разные таблици, просто опись полей разная , вот в чем дело, а таким путем ходим только потому что хотим централизованную таблицу, все же возможные вариации полей не всунеш в один gxBox, на деле полей более 30 только у центрального класса , у производных от 15 полей, все это дело должно иметь одну уникальную строку
Понятно почему не сохранялся код. Теги вырезаются методом strip_tags(), только разрешенные проходят, то есть используется метод "что не разрешено - то запрещено". Теги из вашего XML-а не были в списке разрешенных. Добавил. Потом механизм поменяем на принцип "что не запрещено - то разрешено".
Кстати, советую вообще XML-описание модели не использовать. Создаете таблицы в базе данных и генерите модель пакетом CMPGenerator. Гораздо рульней получается.
Да, модели у вас разные, но вы тогда пытаетесь совместить несовместимое. У вас разные объекты, но пытаетесь вы их наследовать от одного класса, еще и таблицы разные используете... Я бы все-таки создал общую таблицу со всеми уникальными полями и рулил свойством class_key различные типы объектов.
Понятно почему не сохранялся код. Теги вырезаются методом strip_tags(), только разрешенные проходят, то есть используется метод "что не разрешено - то запрещено". Теги из вашего XML-а не были в списке разрешенных. Добавил. Потом механизм поменяем на принцип "что не запрещено - то разрешено".
мелочи такие а мозг затрахивают)) CMPGenerator крутая штука когда связей минимум, он связи вроде не генерирует, XML тоже неплох когда нужно видеть все и сразу в одном файле, потом просто распарсить схему, вот сейчас более 500 строк схемы в том числе конструктор планировок(зем уч-> строение(тип стен,материал крыши) -> помещения внутри(кв/м,тип ремонта,пол,потолок)/снаружи(балкон,терраса,виранда,мансарда) -> оборудование/комфорт ) и все поля типов ссылаются на одну таблицу с терминами и типами, там даже ссылка планируется на wiki описание, эксперементирую с компонентом недвижимости, там опись объектов(недвижимости) дикая , можно было конечно просто в поле description/content задать описание квартиры/зем.участка и т.д, делаю ориентируясь на автоматику , чтобы и выборка по критериям была мощной , а критериев уже не мало
Да, модели у вас разные, но вы тогда пытаетесь совместить несовместимое. У вас разные объекты, но пытаетесь вы их наследовать от одного класса, еще и таблицы разные используете... Я бы все-таки создал общую таблицу со всеми уникальными полями и рулил свойством class_key различные типы объектов.
c 1 общей таблицей , страшно за расширяемость в дальнейшем
CMPGenerator крутая штука когда связей минимум, он связи вроде не генерирует
Да, связи не генерирует, приходится вручную прописывать. Но не вижу особой разницы между ручным прописыванием в XML и в уже конечный мап-файл. Хотя каждому свое. Все-таки да, перед глазами все видеть - хорошая штука. Было бы круто накидать визуальный редактор схем, типа как в редакторе phpMyAdmin, автоматизация тут просматривается :)
Недвига... О да, там связей и параметров хватает... Я вон http://www.aska-realty.ru/ программировал, насмотрелся. Давно убедился - крупные проекты только вручную все, и только хардкод. Там одними готовыми решениями не обойтись.
страшно за расширяемость в дальнейшем
А это уже от конечной реализации зависит. Несколько дочерних классов от modResource вполне уживаются в одной таблице, хотя и поведение конечных объектов может местами сильно отличаться.
Хороший сайт, возьму на заметку), мне вручную писать больше нравиться нежели изучать готовое решение, зато там подглядеть можно, для спицифики думаю часто приходится вручную делать, все-таки с таблицами с этими головняк, можно просто без наследования Git как-то я выставил поле class_key(альтернатива class_alias в приведенном примере) у головной таблицы, так-вот все было супер выборка была сразу join`ом на указанную таблицу(класс) class_key, но были ошибки в логе, это и правильно т.к второстепенные классы не наследуются от головного, зато выбираются адекватно
тоесть получается с class_key возможно решить такой вот нюанс с вторичными таблицами, но
Instantiated a derived class msProduct that is not a subclass of the requested class modDocument
меня убивает)
http://schemaviewer.dev.kenters.com в помощ неплохо сделано для тех кто как я пишет xml schema ))))
Объясню суть ошибки: msProduct расширяет класс modResource. Соответственно и запрос должен строиться с modResource:
$o = $modx->getObject('modDocument');
Если в данном случае будет получен объект msProduct, то будет эта ошибка, так как msProduct не является наследником modDocument.
не совсем правильно вы меня поняли, msProduct не причем и вообще компонент minishop не причем
то что вы пишете было всегда ясно , "откуда в контейнере содержимое если его туда не положили" 'modDocument' 'msProduct'
я про то что добавляя поле class_key ,при получении объекта GetObject(target_class) xpdo найдя этот class_key независимо наследуется таблица или ни наследуется - без разницы , возьмет то что там написано и постарается join`ить автоматом этот класс если он сущевствует и дополнит набор полей в target_class с class_key класса, по target_class.id = class_key.id(в противном случае вообще выдаст фатал еррор о том что класса не сущевствует)
обратите внимание на схему:
<model package="gxTest" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1"> <object class="gxBox" table="gx_box" extends="xPDOSimpleObject"> <field key="title" dbtype="varchar" precision="255" phptype="string" null="false"/> <field key="properties" dbtype="text" phptype="string" null="false"/> <field key="class_alias" dbtype="varchar" precision="255" phptype="string" null="false"/> <composite alias="gxBoxWater" class="gxBoxWater" local="id" foreign="id" cardinality="one" owner="local"/> <composite alias="gxBoxAutomobil" class="gxBoxAutomobil" local="id" foreign="id" cardinality="one" owner="local"/> </object> <object class="gxBoxWater" table="gx_box_water" extends="xPDOSimpleObject"> <field key="pressure" dbtype="int" precision="11" phptype="integer" null="false"/> <field key="speed" dbtype="int" precision="11" phptype="integer" null="false"/> <field key="beasts" dbtype="varchar" precision="255" phptype="string" null="false"/> <aggregate alias="gxBox" class="gxBox" local="id" foreign="id" cardinality="one" owner="foreign"/> </object> <object class="gxBoxAutomobil" table="gx_box_automobil" extends="xPDOSimpleObject"> <field key="wheels" dbtype="int" precision="11" phptype="integer" null="false"/> <field key="has_truck" dbtype="tinyint" precision="1" phptype="boolean" null="false"/> <field key="truck_volume" dbtype="int" precision="11" phptype="integer" null="false"/> <aggregate alias="gxBox" class="gxBox" local="id" foreign="id" cardinality="one" owner="foreign"/> </object> <object class="gdBox" table="gd_box" extends="xPDOSimpleObject"> <field key="title" dbtype="varchar" precision="255" phptype="string" null="false"/> <field key="properties" dbtype="text" phptype="string" null="false"/> <field key="class_key" dbtype="varchar" precision="255" phptype="string" null="false"/> <composite alias="gdBoxWater" class="gdBoxWater" local="id" foreign="id" cardinality="one" owner="local"/> <composite alias="gdBoxAutomobil" class="gdBoxAutomobil" local="id" foreign="id" cardinality="one" owner="local"/> </object> <object class="gdBoxWater" table="gd_box_water" extends="xPDOSimpleObject"> <field key="pressure" dbtype="int" precision="11" phptype="integer" null="false"/> <field key="speed" dbtype="int" precision="11" phptype="integer" null="false"/> <field key="beasts" dbtype="varchar" precision="255" phptype="string" null="false"/> <aggregate alias="gdBox" class="gdBox" local="id" foreign="id" cardinality="one" owner="foreign"/> </object> <object class="gdBoxAutomobil" table="gd_box_automobil" extends="xPDOSimpleObject"> <field key="wheels" dbtype="int" precision="11" phptype="integer" null="false"/> <field key="has_truck" dbtype="tinyint" precision="1" phptype="boolean" null="false"/> <field key="truck_volume" dbtype="int" precision="11" phptype="integer" null="false"/> <aggregate alias="gdBox" class="gdBox" local="id" foreign="id" cardinality="one" owner="foreign"/> </object> </model>
в ней есть 6 классов по 3 , и того 2 варианта исполнения(gx/gd) такой структуры
при запросе:
$modx->getObject('gxBox')
мы получим только набор полей этой таблицы gx_box для joina надо проделать:
$modx->getObjectGraph('gxBox','{gxBoxWater:{},gxBoxAutomobil:{}}')
тоесть присоединить к gxBox можно и water и automobil ,потому-что class_alias не имеет магии при запросе:
$modx->getObject('gdBox')
нам вернется набор полей:
Array ( [id] => 2 [wheels] => [has_truck] => [truck_volume] => [title] => Auto [properties] => [class_key] => gdBoxAutomobil )
обратите внимание на то что они спарены в месте, связи aggregate и Composite здесь ни при чем они просто помогают нам при добавлении addOne(), class_key - только это поле (правильно заполненное) повлияло на слияние, значит в нем есть магия и пофигу что выборка происходит не от наследников и вообще здесь этого нет , но всеравно все ок
Instantiated a derived class gdBoxAutomobil that is not a subclass of the requested class gdBox
Я честно скажу: как-то все очень сложно (во всяком случае при поверхностном осмотре). Вдаваться всерьез не стал, так как не вижу для себя практического применения. В тех схемах, которые я применяю и с теми SQL-запросами, которые в итоге формируются, у меня подобных ошибок не возникает.
магия class_key поражает, жаль только что это не документировано я подумал и склоняюсь больше к примеру с gxBox
магия class_key поражает, жаль только что это не документировано
Там много недокументированных возможностей :) Вот, к примеру, меня вообще прёт:
$user = $modx->newObject('modUser'); $user->Profile = $modx->newObject('modUserProfile'); $user->save();
Без всяких ->addOne() и т.п.
Это повод для раздела "Не документированное"))
меня больше поражает , для чего это
ваш фильтр тегов все режет http://php.net/manual/ru/function.htmlentities.php вот такое в XML что значит, видел пару раз , залез в документацию - там нету
[left bracket]param name="wmode" value="opaque"/[right bracket]
Это повод для раздела "Не документированное"))
Для этого есть раздел Эксперименты и исследования
меня больше поражает , для чего это
Оооо, а это ппц как удобно бывает. Особенно не на создание, а на чтение. К примеру
$modx->getObject('modUser', $id)->Profile->email;
В любом месте на сайте можно писать $modx->user->Profile->$key или типа того, и вообще не париться был запрошен ранее объект профиля пользователя или нет. Если не был, xPDO сам выполнит $modx->user->Profile = $modx->user->getOne('Profile'); Если это не удобно, то что же тогда вообще удобно? А с учетом того, что мы все фигачим на modSmarty и у нас в Smarty доступен объект $modx, то тут удобства через край.
htmlentities нам здесь не совсем подходит, так как есть разрешенные HTML-теги, и если мы сейчас все без разбору будем преобразовывать в сущности, то у нас все будет выводиться как текст, а не HTML.
Прямо из smarty такой строчкой, вау
я на это обратил внимание , и сразу подумал про замену и мини парсер вводимых пользователем разрешенных тегов типа [tagname blabla="" blaha=""]view this text here...![/tagname] так устроено в ModxTalks`е, а угловые скобки все в сущности
Как я и говорил, с редакторами и т.п. - это мы чуть позже будем разбираться. Это вопрос, который надо будет изучать со всех сторон. Сырой исходный передаваемый код тоже сохраняется, так что если что, я комменты подредактирую.
За такое баловство буду блочить :)
так что же это за тег param в модели
param name="wmode" value="opaque"
Вообще такие параметры прописывают во встраиваемых flash-объектах на страницах, влияет на поведение окна ролика.
интересно, я про модель
На самом деле если на schema руку набить то всё довольно быстро делается с помощи MIGXdb.
$user->Profile = $modx->newObject('modUserProfile');
Тут надо уже не MODX а сам PHP и ООП понимать. Например:
class My { public $var; //в функции пользуемся так function myfunc($text){ $this->var = $text; } } $my= new My(); $my->myfunc('Мой текст'); echo $this->var; // выведет Мой текст $this->mystatic = "Статическая переменка"; // здесь мы види м что она нигде не прописана но создаётся автоматически и принадлежит класу.
всё просто
кажись я не разобрался как код вставлять правильно
или просто в code достаточьно?
это магические методы ООП php
<php class Test{ public $_fields = array(); public $_composites= array( 'Alias' => array( //addition ), ); public function __call(){} public function __get($varname){ return $this->_cmposites[$varname]?$this->_cmposites[$varname]:$this->_fields[$varname]; } public function __set($varname){ //Some....logic for add relationship object } } $test = new Test(); $test->Alias = $object;
<php //test $born = naw Born(); ?>
извиняюсь за спам просто чтото не получается код писать
все нормально, просто редактор поста не до ума, избегай код писать , пока не поправят
Так я на другом языке не говорю))) Вон по русски и то с ошибками ))))
$this->mystatic = "Статическая переменка";
Вот это совсем не статическая переменная. Статическая определяется параметром static и давно уже в php можно обращаться только через ::
class My { public static $var; function myfunc($text){ self::$var = $text; } } $my = new My; $my->myfunc("sdfsdf"); print $my->var; // PHP notice: Undefined property: My::$var print $my::$var; // OK
Может и правда я просто термин не нашёл для той переменки классовая? Глобальная?
Это просто свойство объекта, не глобальное и ничего такого.
Вообще, можно еще уточнить что публичная переменная. Бывают еще protected и private.
спасибо так и запишем "свойство обьекта" )))))
как получить список классов packages`а?
Через API никак. Только если проходиться поиском по файловой системе. Но есть в корне пакета meta-файл, в котором могут быть перечислены классы, его вот можно использовать.
Спасибо николай, решилось парсингом schema файла , все это нужно было для remove/create ObjectContainer для облегчения редактирования schema (в целевом компоненте все отталкивается от schema) и в случае каких либо умышленных изменений схемы, быстрой синхронизации schema с XPDO мапами и mysql таблицами через API компонента. А уже на этапе работы в рамках самого компонента, можно использовать сгенерированый из той же схемы $xpdo_meta_map массива мой велосипед выглядит так.
все-же беда тут с кодом у вас))
копаюсь и немогу разобраться , допустим у нас есть 10 таблиц они все между собой связаны, 1 таблица является главной , остальные это обстрактно часть иерархии к этой главной таблице, так вот задача такая что когда мы создаем 1 строку в главной таблице, мы отсылаем с формы данные в сумме состовляющие структуру данных этих 10 таблиц, нам надо обработать , проверить эти данные и уже потом сейвить главный объект и всю под иерархию, простные связи Aggregate`сы главного объекта забитые в addOne addMany не могут сейваться через $main->save(), с этим и вся проблема, приходится под иерархию сохранять а потом только главный объект вставляя айдишники на детя в материнские объекты, решение было бы в использовании транзакцию во время валидации структуры, но как мы знаем modX не любит innoDB и транзакции нам труднодоступны
Подправил коммент, выложил код на гист.
Да, это велосипед :) Я, к примеру, вообще XML-схему не составляю и не прикладываю к пакету.
простные связи Aggregate`сы главного объекта забитые в addOne addMany не могут сейваться через $main->save(), с этим и вся проблема, приходится под иерархию сохранять а потом только главный объект вставляя айдишники на детя в материнские объекты,
Очень даже могут. Вы просто что-то не так в своих связях прописали. Скорее всего напутали с owner-ом. Изучайте внимательно этот топик.
P.S. Пошел оффтоп. Пишите свой топик с описанием всех вопросов и задач и там уже общение давайте наводить, так как здесь мы вполне конкретную статью сейчас загружаем неконкретными комментариями.
вообще XML-схему не составляю и не прикладываю к пакету.
К полному моему охереванию.
Антон, давай постараемся без выражений. По делу: XML-схема не имеет обязательного назначения. Она используется только для генерации Map-файлов. Если я эти файлы создаю сам (в чем успешно помогает CMPGenerator), то мне этот XML не нужен. А в процессе работы MODX Revo его для себя никак не использует.
схема удобно когда пакет объектов не маленький(много связей) , по моему схема для меня один из приоритетных файлов описывающий абстрактно весь компонент, я только от нее отталкиваюсь когда осматриваю в общем весь компонент в целом
согласен, схема больше носит описывающий характер
т.к с нее произвожу регенерацию мапы и таблиц =)

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