Первичный ключ xPDOObject
Как известно, при создании собственных таблиц в MODX принято наследовать или xPDOSimpleObject, или xPDOObject.
Отличие между ними ровно одно — в SimpleObject уже прописан первичный ключ id, а в Object — нет. То есть, если вы хотите, чтобы у вашей таблицы создавалось поле id с становилось primary key — нужно наследовать SimpleObject.
Я, однако, люблю простые таблицы ключ-значение, в которые добавляю первичным ключом два и более полей сразу. Например, в репозитории пакет может быть в нескольких категориях, значит нужно создать таблицу extraCategoryMember из двух полей category_id и package_id.
Ключ id мне здесь совершенно не нужен, ведь он будет расти при каждой операции добавления пакета в категорию, а таких операций может быть очень много. Конечно, вряд ли INT(10) скоро закончится, но зачем хранить лишнее?
Итак, вот моя схема:
Всё прекрасно работает, за исключением одного — при удалении пакета, такие связанные объекты остаются, а в логе ошибка:
При разработке MS2 я решил вопрос ручным удалением связанных объектов в методе msProductData::remove(), но в этот раз решил разобраться.
В каждом объекте есть метод getPK(), который возвращает поле, являющееся первичным ключом объекта. В случае xPDOSimpleObject возвращается строка id. В случае xPDOObject не возвращается ничего.
Оказывается, чтобы getPK() вернул нам массив, как и должен, нужно обязательно прописать в схеме у полей атрибут index=«pk», не смотря на то, что в схемах версии 1.1 индексы в атрибутах не указываются.
Моя схема теперь выглядит вот так:
И теперь getPK возвращает мне массив:
Ошибка из лога пропала, связанные объекты удаляются корректно.
Даже не знаю, ошибка это, или я чего-то не понял, но, несмотря на используемую версию схемы 1.1, указывать атрибут index=«pk» для полей-ключей необходимо.
Хотя в документации четко прописано, что:
У объекта xPDOSimpleObject этот параметр уже прописан, поэтому ошибки не возникает.
Отличие между ними ровно одно — в SimpleObject уже прописан первичный ключ id, а в Object — нет. То есть, если вы хотите, чтобы у вашей таблицы создавалось поле id с становилось primary key — нужно наследовать SimpleObject.
Я, однако, люблю простые таблицы ключ-значение, в которые добавляю первичным ключом два и более полей сразу. Например, в репозитории пакет может быть в нескольких категориях, значит нужно создать таблицу extraCategoryMember из двух полей category_id и package_id.
Ключ id мне здесь совершенно не нужен, ведь он будет расти при каждой операции добавления пакета в категорию, а таких операций может быть очень много. Конечно, вряд ли INT(10) скоро закончится, но зачем хранить лишнее?
Итак, вот моя схема:
<object class="extraCategoryMember" table="extras_category_members" extends="xPDOObject">
<field key="category_id" dbtype="integer" attributes="unsigned" precision="10" phptype="integer" null="false" default="0" />
<field key="package_id" dbtype="integer" attributes="unsigned" precision="10" phptype="integer" null="false" default="0" />
<index alias="category" name="category" primary="true" unique="true" type="BTREE">
<column key="category_id" length="" collation="A" null="false" />
<column key="package_id" length="" collation="A" null="false" />
</index>
</object>Всё прекрасно работает, за исключением одного — при удалении пакета, такие связанные объекты остаются, а в логе ошибка:
[2013-05-11 15:49:49] (ERROR @ /assets/components/extras/connector.php) Error removing dependent object: Array
(
[category_id] => 10
[package_id] => 2
)При разработке MS2 я решил вопрос ручным удалением связанных объектов в методе msProductData::remove(), но в этот раз решил разобраться.
xPDOObject::getPK()
В каждом объекте есть метод getPK(), который возвращает поле, являющееся первичным ключом объекта. В случае xPDOSimpleObject возвращается строка id. В случае xPDOObject не возвращается ничего.
Оказывается, чтобы getPK() вернул нам массив, как и должен, нужно обязательно прописать в схеме у полей атрибут index=«pk», не смотря на то, что в схемах версии 1.1 индексы в атрибутах не указываются.
Моя схема теперь выглядит вот так:
<object class="extraCategoryMember" table="extras_category_members" extends="xPDOObject">
<field key="category_id" dbtype="integer" attributes="unsigned" precision="10" phptype="integer" null="false" default="0" index="pk" />
<field key="package_id" dbtype="integer" attributes="unsigned" precision="10" phptype="integer" null="false" default="0" index="pk" />
<index alias="category" name="category" primary="true" unique="true" type="BTREE">
<column key="category_id" length="" collation="A" null="false" />
<column key="package_id" length="" collation="A" null="false" />
</index>И теперь getPK возвращает мне массив:
array (size=2)
'category_id' => string 'category_id' (length=11)
'package_id' => string 'package_id' (length=10)Ошибка из лога пропала, связанные объекты удаляются корректно.
Заключение
Даже не знаю, ошибка это, или я чего-то не понял, но, несмотря на используемую версию схемы 1.1, указывать атрибут index=«pk» для полей-ключей необходимо.
Хотя в документации четко прописано, что:
Schema Version 1.1
In 2.0.0-rc3, the schema was changed to implement a new model element that describes Table Indexes separately from the field element's index and index_group attributes.
…
Do not add version=«1.1» (leave off the version attribute or set it to 1.0) if you have not yet described your indexes in the new schema format or xPDO will create the tables with no indexes.
У объекта xPDOSimpleObject этот параметр уже прописан, поэтому ошибки не возникает.
Комментарии: 16
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
пример:
Схема:
http://schemaviewer.dev.kenters.com/51aa188bce3e55.64196579
Я хочу сделать так, чтобы при удалении строки из таблицы doodles, удалялась соответствующая строка из doodlesCategories. Какие связи необходимо поставить?
Для таких выборок либо вручную, либо pdoTools.
Пробовал объявить в схеме класс modResource — не помогает.
И это все затрется при первом же обновлении MODX.
Что собственно и происходит при удалении через remove() или если мы используем процессор от modObjectRemoveProcessor. А проблема в следующем: так как во всех случаях прежде чем удалить объект, его нужно получить через getObject('msSfiltersProduct', $criteria) Где $criteria либо массив данных, если обратились через процессор, либо строка или целое. При этом вызове у нас вызывается $this->parseConditions($conditions, $conjunction); Вот этот метод и гадит нам. Дело в том что условие строиться на основе primary key и его типа, приведу вырезанный кусок данного метода: Видно, что проверки на тип ключа как массива нет и $result будет всегда == NULL, и getObject вернет нам первый объект. Что же делать… как вариант не указывать несколько primary key, у всех кроме одного нужно указывать index=«index». В самом объекте указать индекс может выглядеть так:
Возможно я и ошибся где-то хз, пусть найдет добрый человек и поправит меня если я не прав.
И еще, не проверял в новых версиях XPDO, но в текущей такое есть (xPDO 2.3.0-pl (July 15, 2014)):
если мы пропишем несколько полей с primary key в одном объекте (тип объекта не важен), то AUTO INCREMENT параметр не добавляется ни в одно поле, какой бы вы generator не прописывали. В результате будем всегда получать error.