[modExtra] Update таблиц своего компонента
Добрый день!
Все мы знаем, что MODX прекрасен мощью решений с помощью компонентов. Я, например, всегда отдаю заказчику сайт в виде компонента, содержащего нужные элементы, зависимости от других компонентов, инициализацию нужных опций и т.д. В этом мне всегда помогал modExtra.
Но вот в один прекрасный момент я задумался, как сделать пользовательские таблицы в своём компоненте таким образом, чтобы при апдейте компонента они были способны расширяться, да и вообще поддерживаться в актуальном состоянии.
Итак задача:
В этом нам помогут ресолверы таблиц, заготовка для которых есть в modExtra и хранится она тут: _build/resolvers/resolve.tables.php. Мы видим, что на каждую таблицу вызывается метод
Кроме этого можно посмотреть на решение Василия в Tickets, где он «руками» пытается недостающие поля таблиц добавить, а лишние удалить.
Порывшись в документации и коде MODX понял, что нас полностью бы устроило добавление строчки
Хочу предложить своё решение, которое должно подойти в подавляющем большинстве случаев:
Решение пусяковое, но оно делает разработку компонента несколько комфортнее.
Спасибо за внимание.
Все мы знаем, что MODX прекрасен мощью решений с помощью компонентов. Я, например, всегда отдаю заказчику сайт в виде компонента, содержащего нужные элементы, зависимости от других компонентов, инициализацию нужных опций и т.д. В этом мне всегда помогал modExtra.
Но вот в один прекрасный момент я задумался, как сделать пользовательские таблицы в своём компоненте таким образом, чтобы при апдейте компонента они были способны расширяться, да и вообще поддерживаться в актуальном состоянии.
Итак задача:
- У нас есть файл схемы mycomponent.mysql.schema.xml, который поставляется вместе с компонентом (или его новой версией) и содержит актуальную информацию о структуре пользовательских таблиц.
- У нас есть БД в которой может не быть наших таблиц (установка с нуля), а могут быть (как правильной, так и неправильной структуры).
В этом нам помогут ресолверы таблиц, заготовка для которых есть в modExtra и хранится она тут: _build/resolvers/resolve.tables.php. Мы видим, что на каждую таблицу вызывается метод
$manager->createObjectContainer($tmp);Если залезть в его потроха, то можно увидеть, что он находит (соответствующую пользовательскому классу) таблицу в БД и, если её не существует, создаёт её, в противном случае ничего не делает. Что ж, неплохое начало. Но на этом решение modExtra заканчивается.Кроме этого можно посмотреть на решение Василия в Tickets, где он «руками» пытается недостающие поля таблиц добавить, а лишние удалить.
Порывшись в документации и коде MODX понял, что нас полностью бы устроило добавление строчки
$manager->alterObjectContainer($tmp);, но у этой функции есть только прототип, а реализации для mySql пока нет.Хочу предложить своё решение, которое должно подойти в подавляющем большинстве случаев:
foreach ($objects as $tmp) {
$manager->createObjectContainer($tmp);
$exist = array();
$c = $modx->prepare("SHOW COLUMNS IN {$modx->getTableName($tmp)}");
$c->execute();
while ($cl = $c->fetch(PDO::FETCH_ASSOC)) {
$exist[$cl['Field']] = $cl['Field'];
}
$fieldMeta = $manager->xpdo->getFieldMeta($tmp, true);
while (list($key, $meta)= each($fieldMeta)) {
if (array_key_exists($key, $exist)) {
unset($exist[$key]);
$manager->alterField($tmp, $key);
} else {
$manager->addField($tmp, $key);
}
}
foreach ($exist as $key) {
$manager->removeField($tmp, $key);
}
}
break;Несколько комментариев:- Сначала мы запоминаем название всех существующих колонок.
- Потом пробегаемся по схеме и выполняем одно из действий: добавить колонку, удалить или обновить.
- Если мы делаем апдейт, а схема не изменилась, то всегда будет вызываться alterField, который проверит изменился ли тип поля и исправит его ТОЛЬКО в том случае, если это необходимо.
- Неважно, есть в таблице данные или нет, скрипт правильно отработает и ничего не пострадает.
Решение пусяковое, но оно делает разработку компонента несколько комфортнее.
Спасибо за внимание.
Комментарии: 12
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
П.С. А ключик от modExtra он мне оставил.
Тады вааще все автоматом работать будет. А то я постоянно забываю добавлять классы.
Замените, пожалуйста unset($tableFields[$field)]); на unset($tableFields[array_search($field, $tableFields)]);
И в аналогичном месте с индексами unset($indexes[$name]); на unset($indexes[array_search($name, $indexes)]);
Массивы же теперь стали не ассоциативные. В вашем примере в списке филдов и индексов реально не происходит удаления, зато потом происходит реальное удаление оставшихся в списке филдов и индексов.
Спасибо.
Думаю, можно это и добавить в modExtra, как образец. Вместе с предложениями Сергея по индексам.
Теперь в большинстве случаев вообще не нужно лезть в этот ресолвер. Спасибо Михаилу.
П.С. Также я добавил код удаления таблиц при деинсталяции. Он закомментирован. Если вдруг кому-то нужно будет удалять таблицы, нужно просто раскомментировать.
С этим изменением в подобных случаях будут удалены и все данные в таблицах, чему многие не обрадуются.
А, туплю, он же закомментирован по умолчанию. Тогда всё ок, вопросов нет.
А разработчик должен понимать всю ответственность такого решения.