Связать кастомную таблицу с modUsers
Связать пользовательскую таблицу с modUser. Требуются расширить данные о пользователе, поле extended в modx_user_attributes не подходит из за json, поля будут активно участвовать в поиске.
в пакете modExtra-master(MyExtUser) создаю простейшую схему:
1.
3. В резолвере прописываю объекты
Ключ: myextuser_assets_url Знаачение: {assets_path}components/myextuser/
Ключ: myextuser_core_path Значение: {core_path}components/myextuser/
5. Собираю пакет, устанавливаю. Создаю сниппет
6.
[2015-06-09 13:17:38] (ERROR @ /index.php) No foreign key definition for parentClass: modUser using relation alias: Data
1.
<?xml version="1.0" encoding="UTF-8"?>
<model package="myextuser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" phpdoc-package="myextuser"
version="1.1">
<object class="extUser" extends="modUser">
<composite alias="Data" local="id" class="Userdata" foreign="userdata_id" cardinality="one" owner="local" />
</object>
<object class="Userdata" table="data" extends="xPDOSimpleObject">
<field key="userdata_id" dbtype="int" precision="11" phptype="integer" null="false" attributes="unsigned"/>
<field key="anyfield" dbtype="varchar" precision="100" phptype="string" null="true" />
<aggregate alias="extUser" local="userdata_id" foreign="id" cardinality="one" owner="foreign" />
</object>
</model>
2. Генерирую модель, синхронизирую, делаю все как тут: bezumkin.ru/training/course1/2136/3. В резолвере прописываю объекты
$objects = array(
/*'MyExtUserItem',*/
'extUser',
'Userdata'
);
4. Прописываю системные настройки:Ключ: myextuser_assets_url Знаачение: {assets_path}components/myextuser/
Ключ: myextuser_core_path Значение: {core_path}components/myextuser/
5. Собираю пакет, устанавливаю. Создаю сниппет
6.
if (!$MyExtUser = $modx->getService('myextuser', 'MyExtUser', $modx->getOption('myextuser_core_path', null, $modx->getOption('core_path') . 'components/myextuser/') . 'model/myextuser/', $scriptProperties)) {
return 'Could not load MyExtUser class!';
}
$User = $modx->getObject('modUser', $modx->user->get('id'));
$Data = $User->getOne('Data');
$Data->set('anyfield','any text');
Итог: ошибка в логе[2015-06-09 13:17:38] (ERROR @ /index.php) No foreign key definition for parentClass: modUser using relation alias: Data
Комментарии: 27
Всё верно. Ты создал новый объект и добавил ему связь с modUser.
А у modUser, как не было связи с твоим новым объектом, так и нет. Нужно где-то её прописать, например вот так, только тебе нужно заменить ключ массива Services на Data.
А у modUser, как не было связи с твоим новым объектом, так и нет. Нужно где-то её прописать, например вот так, только тебе нужно заменить ключ массива Services на Data.
Прописал
Но при генерации пакета удаляется добавленная связь…
<?php
$xpdo_meta_map = array (
'modUser' =>
array (
0 => 'extUser',
),
'xPDOSimpleObject' =>
array (
0 => 'Userdata',
),
);
$this->map['modUser']['composites']['Data'] = array(
'class' => 'Userdata',
'local' => 'id',
'foreign' => 'userdata_id',
'cardinality' => 'one',
'owner' => 'local',
);
прописываю в файле MyExtUser/core/components/myextuser/model/myextuser/metadata.mysql.phpНо при генерации пакета удаляется добавленная связь…
Естественно, удаляется — файл же перезаписывается.
Придётся прописывать заново каждый раз. Других способов не знаю, извини.
Придётся прописывать заново каждый раз. Других способов не знаю, извини.
что сразу не обратил. Вы пишите что я создал новый объект в моем случае (Userdata), и добавил связь с modUser, а именно
<aggregate alias="extUser" local="userdata_id" foreign="id" cardinality="one" owner="foreign" />
А у modUser не было связи и нет… меня смутило. Как же, я же расширяю объект modUser и прописываю связь. Разве не такой принцип? При генерации модели, разве это связь не должна учитываться?<object class="extUser" extends="modUser">
<composite alias="Data" local="id" class="Userdata" foreign="userdata_id" cardinality="one" owner="local" />
</object>
Разве не такой принцип?Нет.
Ты работаешь со своими объектами и к чужим отношения не имеешь. Модель MODX уже сгенерирована и лежит в отдельной директории. Как ты думаешь, она должна перегенерироваться в зависимости от твоих действий?
Верно, никак. Она о твоих действиях вообще не в курсе.
Вы правы, не поспоришь. Может подскажите как реализовать, как пример: отношение объектов user и user_attributes. Как я понимаю, достаточно создать одну схему(объект), указать связь с modUser.
<?xml version="1.0" encoding="UTF-8"?>
<model package="myextuser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" phpdoc-package="myextuser"
version="1.1">
<object class="Userdata" table="data" extends="xPDOSimpleObject">
<field key="userdata_id" dbtype="int" precision="11" phptype="integer" null="false" attributes="unsigned"/>
<field key="anyfield" dbtype="varchar" precision="100" phptype="string" null="true" />
<aggregate alias="extUser" class="modUser" local="userdata_id" foreign="id" cardinality="one" owner="foreign" />
</object>
</model>
и прописать$this->map['modUser']['composites']['Services'] = array(
'class' => 'Userdata',
'local' => 'id',
'foreign' => 'userdata_id',
'cardinality' => 'one',
'owner' => 'local',
);
Василий, что не так в этот раз. Я немного пересмотрел связь объектов, и теперь делаю так.
Создаю схему:
Добавил системные настройки с ключем
Ключ: myextuser_core_path Значение: {core_path}components/myextuser/
Собрал и установил пакет myextuser.
Добавил в файл /public_html/core/components/myextuser/model/myextuser/metadata.mysql.php
Создаю схему:
<?xml version="1.0" encoding="UTF-8"?>
<model package="myextuser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" phpdoc-package="myextuser"
version="1.1">
<object class="Userdata" table="data" extends="xPDOSimpleObject">
<field key="userdata_id" dbtype="int" precision="11" phptype="integer" null="false" attributes="unsigned"/>
<field key="anyfield" dbtype="varchar" precision="100" phptype="string" null="true" />
<aggregate alias="extUser" class="modUser" local="userdata_id" foreign="id" cardinality="one" owner="foreign" />
</object>
</model>
Генерирую модель как описано у вас bezumkin.ru/training/course1/2136/Добавил системные настройки с ключем
extension_packages
со значением [{"myextuser":{"path":"[[++core_path]]components/myextuser/model/"}}]
Ключ: myextuser_assets_url Значение: {assets_path}components/myextuser/Ключ: myextuser_core_path Значение: {core_path}components/myextuser/
Собрал и установил пакет myextuser.
Добавил в файл /public_html/core/components/myextuser/model/myextuser/metadata.mysql.php
<?php
$xpdo_meta_map = array (
'xPDOSimpleObject' =>
array (
0 => 'Userdata',
),
);
$this->map['modUser']['composites']['Services'] = array(
'class' => 'Userdata',
'local' => 'id',
'foreign' => 'userdata_id',
'cardinality' => 'one',
'owner' => 'local',
);
Создал сниппет:$modx->addPackage('myextuser', MODX_CORE_PATH . 'components/myextuser/model/');
if (!$MyExtUser = $modx->getService('myextuser', 'MyExtUser', $modx->getOption('myextuser_core_path', null, $modx->getOption('core_path') . 'components/myextuser/') . 'model/myextuser/', $scriptProperties)) {
return 'Could not load MyExtUser class!';
}
$User = $modx->getObject('modUser', $modx->user->get('id'));
$Data = $User->getOne('Services');
$Data->set('anyfield','any text');
$Data->save();
Выдает 500 ошибку… что я не так делаю? <object class="chGuest" extends="modUser">
<field key="class_key" dbtype="varchar" precision="45" phptype="string" null="false" default="chGuest"/>
<composite alias="Data" class="chGuestData" local="id" foreign="id" cardinality="one" owner="local" />
</object>
<object class="chGuestData" table="ch_guests_data" extends="xPDOSimpleObject">
<field key="surname" dbtype="varchar" precision="45" phptype="string" null="false" default=""/>
<field key="name" dbtype="varchar" precision="45" phptype="string" null="false" default=""/>
<field key="patronymic" dbtype="varchar" precision="45" phptype="string" null="false" default=""/>
<composite alias="Guest" class="chGuest" local="id" foreign="id" cardinality="one" owner="foreign" />
</object>
Иной вариант — расширение пользователей с указанием нового класса.
Связь Data — по аналогии с msProduct, очень сильно упрощает работу с полями в дополнительной таблице.
Класс chGuestData — стандартный класс, расширяющий xPDOSimpleObject.
chGuest содержит методы прозрачного подтягивания полей из chGuestData: github.com/bezumkin/miniShop2/blob/master/core/components/minishop2/model/minishop2/msproduct.class.php
Ты забыл указать, что всем юзерам сайта придётся указывать class_key = chGuest, что может быть не очень удобно по разным причинам.
Верно, спасибо за замечание.
Необходимо смотреть, что удобнее для конкретной задачи.
Необходимо смотреть, что удобнее для конкретной задачи.
Еще есть вот такой вариант расширения классов.
Вот мой резолвер из одного проекта:
gist.github.com/antixrist/be29c8381214654af04e
Вам нужны вот эти строчки:
gist.github.com/antixrist/be29c8381214654af04e#file-resolve-tables-php-L38-L57
Подставьте вместо вот этого вашу связь:
Ну и при копипасте не забудьте подставить свои пути/настройки.
Смысл в том, чтобы автоматически добавлять нужную связь к системному классу при пере-/установке своего компонента.
Если что-то не понятно — спрашивайте)
gist.github.com/antixrist/be29c8381214654af04e
Вам нужны вот эти строчки:
gist.github.com/antixrist/be29c8381214654af04e#file-resolve-tables-php-L38-L57
Подставьте вместо вот этого вашу связь:
$this->map['modUser']['composites']['Data'] = array(
'class' => 'Userdata',
'local' => 'id',
'foreign' => 'userdata_id',
'cardinality' => 'one',
'owner' => 'local',
);
Ну и при копипасте не забудьте подставить свои пути/настройки.
Смысл в том, чтобы автоматически добавлять нужную связь к системному классу при пере-/установке своего компонента.
Если что-то не понятно — спрашивайте)
Алексей спасибо, ценная вещь, обязательно воспользуюсь, т.к у меня все пакетами идет. Но мне пока не запустить связанный объект, может вы подскажите. Выше я спросил Василия, но не соображу как дать ссылку на описание моих действий, поэтому, извините, продублирую......, по сравнению с 1 постом схема изменилась в резольвере, соответсвенно прописан только один объект
Добавил системные настройки с ключем
extension_packages со значением
[{«myextuser»:{«path»:"[[++core_path]]components/myextuser/model/"}}]Ключ: myextuser_assets_url Значение: {assets_path}components/myextuser/
Ключ: myextuser_core_path Значение: {core_path}components/myextuser/
Собрал и установил пакет myextuser.
Добавил в файл /public_html/core/components/myextuser/model/myextuser/metadata.mysql.php
$objects = array(
/*'MyExtUserItem',*/
'Userdata'
);
Создаю схему:<?xml version="1.0" encoding="UTF-8"?>
<model package="myextuser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" phpdoc-package="myextuser"
version="1.1">
<object class="Userdata" table="data" extends="xPDOSimpleObject">
<field key="userdata_id" dbtype="int" precision="11" phptype="integer" null="false" attributes="unsigned"/>
<field key="anyfield" dbtype="varchar" precision="100" phptype="string" null="true" />
<aggregate alias="extUser" class="modUser" local="userdata_id" foreign="id" cardinality="one" owner="foreign" />
</object>
</model>
Генерирую модель как описано у вас bezumkin.ru/training/course1/2136/Добавил системные настройки с ключем
extension_packages со значением
[{«myextuser»:{«path»:"[[++core_path]]components/myextuser/model/"}}]Ключ: myextuser_assets_url Значение: {assets_path}components/myextuser/
Ключ: myextuser_core_path Значение: {core_path}components/myextuser/
Собрал и установил пакет myextuser.
Добавил в файл /public_html/core/components/myextuser/model/myextuser/metadata.mysql.php
<?php
$xpdo_meta_map = array (
'xPDOSimpleObject' =>
array (
0 => 'Userdata',
),
);
$this->map['modUser']['composites']['Services'] = array(
'class' => 'Userdata',
'local' => 'id',
'foreign' => 'userdata_id',
'cardinality' => 'one',
'owner' => 'local',
);
Создал сниппет:$modx->addPackage('myextuser', MODX_CORE_PATH . 'components/myextuser/model/');
if (!$MyExtUser = $modx->getService('myextuser', 'MyExtUser', $modx->getOption('myextuser_core_path', null, $modx->getOption('core_path') . 'components/myextuser/') . 'model/myextuser/', $scriptProperties)) {
return 'Could not load MyExtUser class!';
}
$User = $modx->getObject('modUser', $modx->user->get('id'));
$Data = $User->getOne('Services');
$Data->set('anyfield','any text');
$Data->save();
500 ошибка
Добавьте в начало вашего сниппета вот это:
Дальше смотрите ошибку. А пока не охота медитировать над кодо-текстом)
p.s. не забудьте на рабочем сайте удалить эти строки. Это только для отладки
error_reporting(E_ALL);
ini_set('display_errors', 1);
Дальше смотрите ошибку. А пока не охота медитировать над кодо-текстом)
p.s. не забудьте на рабочем сайте удалить эти строки. Это только для отладки
Выдает Fatal error: Call to a member function set() on a non-object in public_html/core/cache/includes/elements/modsnippet/45.include.cache.php on line 14
Не нравится ему метод set. Весь вопрос почему?
Не нравится ему метод set. Весь вопрос почему?
Ему не «set» не нравится. Ему не нравится, что в переменной $Data ничего нет.
Т.е. вам обязательно в коде нужно делать проверку типа такой:
Другой вопрос — почему в этой переменной ничего нет? Есть ли в вашей таблице получаемый объект? Рискну предположить, что нет)
Сперва создайте объект (либо через $User->addOne('MyExtUser', array(/*...*/)), либо $modx->newObject('MyExtUser')), а уж потом получайте его.
Т.е. вам обязательно в коде нужно делать проверку типа такой:
if ($Data instanceof MyExtUser) {
$Data->set('anyfield','any text');
$Data->save();
}
Другой вопрос — почему в этой переменной ничего нет? Есть ли в вашей таблице получаемый объект? Рискну предположить, что нет)
Сперва создайте объект (либо через $User->addOne('MyExtUser', array(/*...*/)), либо $modx->newObject('MyExtUser')), а уж потом получайте его.
Алексей, все таки если помочь захотите, то кодо-текст посмотреть надо будет. Он тем более создан самый простой, для проверки работы, смысловой нагрузки никакой не несет. Могу на словах описать что я хотел получить. Я хотел расширить атрибуты юзера, через свою таблицу Userdata. Что бы работа осуществлялась как встроенные объекты user и user_attributes.
Т.е. создать связь user и моя таблица. И записывать туда специфичные данные юзера. Т.е. с профайлом modx работает так (но меня таблица не устраивает):
Т.е. создать связь user и моя таблица. И записывать туда специфичные данные юзера. Т.е. с профайлом modx работает так (но меня таблица не устраивает):
$user = $modx->getObject('modUser', $modx->user->get('id'));
$profile = $user->getOne('Profile');
$profile->set('fullname', $_POST['fullname']);
$profile->save();
Поэтому я хотел создать свою таблицу, со своими полями и работать так (создать связь с базовым класом)$user = $modx->getObject('modUser', $modx->user->get('id'));
$profile = $user->getOne('Services'); //алиас связи с моей таблицей
$profile->set('fullname', $_POST['fullname']);
$profile->save();
кодо-текст посмотреть надо будет
Могу на словах описать что я хотел получитьМысль про кодо-текст была о том, что вылавливать ошибку, читая код в виде текста, желания не возникает. Но смысловая нагрузка вашего кода понятна с первого взгляда.
А вот вы, похоже, не совсем понимаете как работают табличные объекты и связи между ними.
Изучайте документацию:
rtfm.modx.com/xpdo/2.x/getting-started/using-your-xpdo-model/creating-objects
rtfm.modx.com/xpdo/2.x/getting-started/using-your-xpdo-model/setting-object-fields
rtfm.modx.com/xpdo/2.x/getting-started/using-your-xpdo-model/working-with-related-objects
А вот вы, похоже, не совсем понимаете как работают табличные объекты и связи между ними.Я конечно не гуру modx, но он меня не перестает удивлять.
$User = $modx->getObject('modUser', $modx->user->get('id'));
$Data = $modx->newObject('Userdata');
$Data->set('anyfield','any text');
$User->addOne($Data);
$User->save();
Так работает, я честно говоря думал, что объект уже создан… вернее создается экземпляр класса при обращении по алиасу т.е. в этой строке$profile = $user->getOne('Services');
где то глубоко в недрах modx думал, что объект уже создан… вернее создается экземпляр класса при обращении по алиасуС чего это вдруг?) Если xpdo будет на каждое обращение к новым объектам создавать все его зависимые объекты, то был бы просто ппц.
Поэтому, нужен объект — извольте его сперва создать)
Алексей, вы правы. Спасибо огромное вам и всем остальным за помощь. Я еще не пробовал ваш первый пост, с резольвером, если что не так будет получатся отпишу…
Не за что)
Все отлично работает. Связь добавляется.
вопрос еще, скорей всего его уже обсуждали. Глядя на резольвер, на первые две строчки,
вопрос еще, скорей всего его уже обсуждали. Глядя на резольвер, на первые две строчки,
$modelPath = $modx->getOption('myextuser_core_path', null, $modx->getOption('core_path') . 'components/myextuser/') . 'model/';
$modx->addPackage('myextuser', $modelPath);
логичней заменить? $modx->addPackage
на $modx->addExtensionPackage
?
Не. Деталей не помню, но там были какие-то приколы и ошибки нелогичные при упаковывании компонента.
Поэтому сперва addPackage, создаём/удаляем/обновляем таблицы, потом removeExtensionPackage, а потом addExtensionPackage.
Вот только в этом порядке при сборке пакета исчезли эти странные ошибки.
С тех пор эта копипаста у меня так и гуляет из компонента в компонент)
Поэтому сперва addPackage, создаём/удаляем/обновляем таблицы, потом removeExtensionPackage, а потом addExtensionPackage.
Вот только в этом порядке при сборке пакета исчезли эти странные ошибки.
С тех пор эта копипаста у меня так и гуляет из компонента в компонент)
Дописал после $modx->addPackage('myextuser', $modelPath);
$modx->addExtensionPackage, срабатывает при второй сборке пакета. В общем пока так пойдет.
Возник вопрос. Есть какой нибудь инструмент переводящий структуру таблиц на mysql в xml schema xpdo modx.......?
$modx->addExtensionPackage, срабатывает при второй сборке пакета. В общем пока так пойдет.
Возник вопрос. Есть какой нибудь инструмент переводящий структуру таблиц на mysql в xml schema xpdo modx.......?
CMPGenerator или даже UiCMPGeneratorСпасибо…
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.