Magento для PHP MVC разработчиков – Инсталлирование Ресурса (ч.5/11)
Для любого быстро растущего проекта разработки программного обеспечения, задача сохранять синхронизацию между базами данных на стадии разработки и реализации становится важной задачей. Magento предлагает систему для создания версионности скриптов миграции ресурсов, которая может помочь вашей команде решить эту часто противоречивую часть процесса разработки.
В предыдущей статье мы создали модель для публикации веб-блога. Там мы использовали прямой запрос CREATE TABLE
непосредственно в базе данных. А в этом уроке мы создадим Инсталлятор Ресурса, который создаст нужную нам таблицу через наш модуль. Мы также создадим скрипт обновления модуля, который будет обновлять уже инсталлированный модуль. Вот краткий перечень шагов, которые нам нужно будет сделать для этого:
- Добавить настройки ресурса в файл конфигурации
- Создать файл класса ресурсов
- Создать скрипт-инсталлятор
- Создать скрипт для обновления
Добавление Инсталлятора Ресурса
Итак, давайте продолжим развивать модуль веб-блога, который мы создали в прошлый раз. В разделе <global/>
конфигурации модуля (config.xml) добавьте следующее:
<global> <!-- ... --> <resources> <weblog_setup> <setup> <module>Alanstormdotcom_Weblog</module> <class>Alanstormdotcom_Weblog_Model_Resource_Setup</class> </setup> </weblog_setup> </resources> <!-- ... --> </global>
Тег <weblog_setup>
будет использоваться для уникального определения этого Инсталлятора ресурса. Желательно, но не обязательно, использовать конвенцию именования типа modelname_setup
(НАЗВАНИЕ-МОДЕЛИ_setup). Блок тегов <module>Alanstormdotcom_Weblog</module>
должен именоваться в виде Packagename_Modulename
. Наконец,
<class>Alanstormdotcom_Weblog_Model_Resource_Setup</class>
должен содержать имя класса, который мы будем создавать для нашего инсталлятора ресурса. Для первичных скриптов инсталляции не нужно создавать собственный класс, но сделав это сейчас, вы будете иметь большую гибкость в дальнейшем.
После добавления вышеупомянутого раздела в файл конфигурации очистите кэш Magento и попытайтесь загрузить любую страницу своего сайта. Вы увидите исключение вида:
Fatal error: Class 'Alanstormdotcom_Weblog_Model_Resource_Setup' not found in
Magento просто пытался создать экземпляр класса, который мы указали в конфигурации, но не смог его найти. Поэтому нам нужно создать такой файл со следующим содержанием:
Файл: app/code/local/Alanstormdotcom/Weblog/Model/Resource/Setup.php class Alanstormdotcom_Weblog_Model_Resource_Setup extends Mage_Core_Model_Resource_Setup { }
Теперь перезагрузите любую страницу своего сайта на Мадженто. Исключение должно исчезнуть, а страница должна нормально загружаться.
Создание скрипта Инсталлятора
Далее рассмотрим процедуру создания скрипта Инсталлятора. Это скрипт, который будет содержать любой CREATE TABLE
или другой SQL код, который нужно запустить для инициализации нашего модуля.
Во-первых, посмотрите на файл конфигурации config.xml
<modules> <Alanstormdotcom_Weblog> <version>0.1.0</version> </Alanstormdotcom_Weblog> </modules>
Этот раздел должен быть во всех файлах config.xml, с его помощью определяется модуль, а также номер его версии. Название файла скрипта инсталлятора будет базироваться на данном номере версии. Ниже приведены предположения, что текущая версия вашего модуля – 0.1.0.
Создайте следующий файл:
Файл: app/code/local/Alanstormdotcom/Weblog/sql/weblog_setup/mysql4-install-0.1.0.php echo 'Запущено это обновление: '.get_class($this)."\n <br> \n"; die("Выйдем пока");
Часточка weblog_setup
в пути должна совпадать с тегом, который вы создали в файле config.xml (<weblog_setup/>
). Часть названия файла 0.1.0 должна соответствовать первоначальной версии вашего модуля. Очистите кэш Magento и перезагрузите любую страницу на своем сайте, и вы должны увидеть что-то подобное (при отключенных уведомлениях вы не увидите):
Запущено это обновление: Alanstormdotcom_Weblog_Model_Resource_Setup Выйдем пока
А это значит, что ваш сценарий обновления выполнено. Впоследствии мы добавим SQL код к этому скрипту обновления, но пока сосредоточимся на самом механизме установки. Удалите код «die» из скрипта, чтобы выглядело следующим образом:
echo 'Запущено это обновление: '.get_class($this)."\n <br> \n";
Перезагрузите страницу. Вы должны увидеть сообщение об обновлении в верхней части страницы. Перезагрузите снова и страница должна отображаться без уведомления.
Версии ресурсов
Ресурсы для установки система запускает автоматически и только нужные. Это позволяет хранить в системе все скрипты миграции базы данных в соответствующем формате.
Выполните SQL-запрос в базе данных для просмотра таблицы core_resource
select * from core_resource; +-------------------------+------------+--------------+ | code | version | data_version | +-------------------------+------------+--------------+ | adminnotification_setup | 1.6.0.0 | 1.6.0.0 | | admin_setup | 1.6.1.0 | 1.6.1.0 | | api2_setup | 1.0.0.0 | 1.0.0.0 | ……………………………………. | weblog_setup | 0.1.0 | 0.1.0 | | weee_setup | 1.6.0.0 | 1.6.0.0 | | widget_setup | 1.6.0.0 | 1.6.0.0 | | wishlist_setup | 1.6.0.0 | 1.6.0.0 | | xmlconnect_setup | 1.6.0.0 | 1.6.0.0 | +-------------------------+------------+--------------+ 55 rows in set (0.00 sec)
В полученной таблице вы сможете увидеть список всех установленных модулей и их номера версий. Наш модуль можно найти почти в конце:
| weblog_setup | 0.1.0 | 0.1.0 |
Вот как Magento знает, что не нужно повторно запускать скрипт второй раз, и в дальнейшем. Ресурс weblog_setup
уже установлен, поэтому он не будет обновлен. Если вы хотите перезапустить сценарий инсталлятора (полезно в процессе разработки), просто удалите строку для нужного модуля из этой таблицы. Давайте сделаем это сейчас с помощью SQL кода:
DELETE from core_resource where code = 'weblog_setup';
Также нам нужно удалить таблицу, которую мы создали вручную в предыдущем уроке:
DROP TABLE blog_posts;
Затем добавьте следующий код в файл скрипта инсталлятора:
$installer = $this; $installer->startSetup(); $installer->run(" CREATE TABLE `{$installer->getTable('weblog/blogpost')}` ( `blogpost_id` int(11) NOT NULL auto_increment, `title` text, `post` text, `date` datetime default NULL, `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP, PRIMARY KEY (`blogpost_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `{$installer->getTable('weblog/blogpost')}` VALUES (1,'My New Title','This is a blog post', '2017-09-01 00:00:00','2017-09-02 23:10:00'); "); $installer->endSetup();
Очистите кэш Magento и перезагрузите любую страницу в системе. После этого должна появиться новая таблица blog_posts
с одной записью.
Анатомия скрипта Инсталлятора
Итак, давайте рассмотрим скрипт детально. Во-первых, есть $this
.
$installer = $this;
Каждый сценарий инсталлятора запускается из контекста класса ресурса Инсталляции, который мы создали ранее. Это означает, что любая ссылка на $this
из скрипта будет ссылкой на экземпляр объекта из этого класса. Хотя это не является обязательным, большинство сценариев инсталлятора в core модулях имеют псевдоним $this
для переменной, которая называется installer, и это мы тут сделали. Несмотря на то, что это не является необходимым, это конвенция, поэтому лучше всегда следовать конвенции, если у вас нет веских причин для иного.
Далее в коде идут запросы, обрамленные вызовом двух методов:
$installer->startSetup(); //... $installer->endSetup();
Если вы посмотрите на класс Mage_Core_Model_Resource_Setup
в app/code/core/Mage/Core/Model/Resource/Setup.php
(этот класс наследует скрипт), вы увидите, что эти методы выполняют базовые SQL настройки:
public function startSetup() { $this->getConnection()->startSetup() return $this; } public function endSetup() { $this->getConnection()->endSetup(); return $this; }
Посмотрите на класс Varien_Db_Adapter_Pdo_Mysql
, чтобы найти настоящие SQL настройки, которые выполняются для MySQL подключений методами startSetup()
и endSetup()
.
И, наконец, вызов метода run
:
$installer->run(...);
который в качестве параметра содержит строку с SQL кодом, необходимым для настройки таблиц(ы) вашей базы данных. Вы можете указать любое количество запросов, разделенных двоеточием. Вы также, наверное, заметили следующее
$installer->getTable('weblog/blogpost')
Метод getTable
позволяет передавать URI Модели и получать название таблицы. Использование этого метода гарантирует, что ваш скрипт будет продолжать работать, даже если кто-то изменит название этой таблицы в файле конфигурации. Класс Mage_Core_Model_Resource_Setup
содержит много полезных вспомогательных методов, таких как этот. Лучший способ ознакомиться со всем возможным – изучить сценарии Инсталлятора, которые используются core модулями Magento.
Агностические сценарии RDBMS
Начиная с версии 1.6 Magento (теоретически) поддерживает большее количество баз данных, то есть не только MySQL. Поскольку наш набор сценариев содержит сырые SQL запросы, он может некорректно работать в другой системе баз данных, скажем, в MSSQL. По этой причине название файла скрипта инсталлятора начинается с mysql4-.
Для того, чтобы сделать скрипты инсталлирования совместимыми с другими базами данных, Magento предлагает объект таблицы DDL (Data Definition Language). Вот альтернативная версия нашего сценария инсталлирования, которая будет работать на любых поддерживаемых СУБД:
Файл: app/code/local/Alanstormdotcom/Weblog/sql/weblog_setup/mysql4-install-0.1.0.php $installer = $this; $installer->startSetup(); $table = $installer->getConnection()->newTable($installer->getTable('weblog/blogpost')) ->addColumn('blogpost_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( 'unsigned' => true, 'nullable' => false, 'primary' => true, 'identity' => true, ), 'Blogpost ID') ->addColumn('title', Varien_Db_Ddl_Table::TYPE_TEXT, null, array( 'nullable' => false, ), 'Blogpost Title') ->addColumn('post', Varien_Db_Ddl_Table::TYPE_TEXT, null, array( 'nullable' => true, ), 'Blogpost Body') ->addColumn('date', Varien_Db_Ddl_Table::TYPE_DATETIME, null, array( ), 'Blogpost Date') ->addColumn('timestamp', Varien_Db_Ddl_Table::TYPE_TIMESTAMP, null, array( ), 'Timestamp') ->setComment('Alanstormdotcom weblog/blogpost entity table'); $installer->getConnection()->createTable($table); $installer->endSetup();
Как видно из кода, в этой версии скрипта не используются сырые SQL запросы. И какую ж версию вы должны использовать? Если вам нужно, чтобы ваши модули работали на любом базовом сервере RDBMS, воспользуйтесь новыми сценариями обновления в стиле DDL. Если вы беспокоитесь об обратной совместимости, воспользуйтесь стилем сырых SQL запросов, поддерживаемых Magento 1.6 и 1.7 (и, возможно, что будет поддерживаться всеми Magento 1.x версиями).
Обновление модуля
Итак, мы создали скрипт, который будет настраивать начальные таблицы базы данных, но что делать, если нужно изменить структуру существующего модуля? Ресурсы для инсталлирования Magento поддерживают простую схему версий, которая позволит вам автоматически запускать скрипты для обновления ваших модулей.
Когда Magento запускает сценарий инсталляции для модуля, он больше никогда не запустит другой installer для этого модуля (за исключением ручного удаления ссылки в таблице core_resource
). Вместо этого вам нужно создать сценарий обновления. Сценарии обновления очень похожи на сценарии инсталлятора с несколькими ключевыми отличиями.
Чтобы протестировать это, мы создадим скрипт в следующем месте с таким содержанием:
Файл: app/code/local/Alanstormdotcom/Weblog/sql/weblog_setup/upgrade-0.1.0-0.2.0.php: echo 'Тестирование нашего сценария обновления (upgrade-0.1.0-0.2.0.php) и остановки выполнения скрипта перед тем как обновится номер версии системы'; die();
Сценарии обновлении можно найти в той же папке, что и сценарий Инсталляции, но называются они немного по-другому. Во-первых, и что наиболее очевидно, имя файла содержит слово upgrade (то есть, обновление). Во-вторых, вы заметите, что есть два номера версий, разделенных символом «—«. Первый (0.1.0) – это версия модуля, с которой мы обновляемся. Второй (0.2.0) – это версия модуля, до которой мы обновляемся.
Если мы очистим кэш и перезагрузим страницу, наш скрипт не будет работать. Чтобы вызвать обновление, нам нужно обновить номер версии в файле config.xml нашего модуля:
<modules> <Alanstormdotcom_Weblog> <version>0.2.0</version> </Alanstormdotcom_Weblog> </modules>
При наличии нового номера версии, мы должны очистить кэш Magento и загрузить любую страницу на сайте. Так сценарий обновления заработает.
Кстати, мы также могли бы назвать наш скрипт обновления mysql4-upgrade-0.1.0-0.2.0.php
. Это означает, что наше обновление будет содержать MySQL-специфический SQL код.
Прежде чем мы продолжим и фактически реализуем сценарий обновления, есть одна важная часть поведения, которую вам нужно знать. Создайте другой файл обновления в следующем месте с таким содержанием:
Файл: app/code/local/Alanstormdotcom/Weblog/sql/weblog_setup/upgrade-0.1.0-0.1.5.php: echo 'Тестирование нашего сценария обновления (upgrade-0.1.0-0.1.5.php), и не прекращение выполнения <br>';
Если вы перезагрузите страницу, вы заметите, что показываются оба сообщения. Когда Magento замечает, что номер версии модуля изменился, он будет работать со всеми скриптами инсталляции, необходимыми для обновления этой версии. Хотя мы никогда не создавали версию 0.1.5 для модуля Weblog, Magento видит сценарий обновления и попытается запустить его. Скрипты будут работать в порядке от самого низкого до самого верхнего. Если вы посмотрите на таблицу core_resource
,
select * from core_resource where code = 'weblog_setup'; +--------------+---------+--------------+ | code | version | data_version | +--------------+---------+--------------+ | weblog_setup | 0.1.5 | 0.1.5 | +--------------+---------+--------------+ 1 row in set (0.00 sec)
вы заметите, что Magento считает номером версии модуля 1.5. Это потому, что мы завершили выполнение обновления от 1.0 до 1.5, но не завершили выполнение обновления с 1.0 до 2.0.
Итак, исходя из этого, написание нашего фактического сценария обновления является идентичным написанию сценария инсталлирования. Давайте изменим скрипт версии 0.1.0-0.2.0:
$installer = $this; $installer->startSetup(); $installer->getConnection() ->changeColumn($installer->getTable('weblog/blogpost'), 'post', 'post', array( 'type' => Varien_Db_Ddl_Table::TYPE_TEXT, 'nullable' => false, 'comment' => 'Blogpost Body' ) ); $installer->endSetup(); die("Вы увидите, почему это здесь через секунду");
Попробуйте обновить страницу на своем сайте и… ничего. Сценарий обновления не запустился. Поле post в нашей таблице все еще возвращает нулевые значения, а что еще важнее, вызов die()
не остановил выполнение. Вот почему так произошло:
- Ресурс
weblog_setup
был в версии 0.1.0 - Мы обновили наш модуль до версии 0.2.0
- Magento увидел обновленный модуль и увидел, что для запуска было два сценария обновления; от 0.1.0 до 0.1.5 и от 0.1.0 до 0.2.0
- Magento поставил в очередь оба скрипта для запуска
- Magento запустил скрипт с 0.1.0 до 0.1.5
- Ресурс
weblog_setup
теперь имеет версию 0.1.5 - Magento запустил скрипт с 0.1.0 до 0.2.0, выполнение было приостановлено
- На следующей загрузке страницы Magento увидел
weblog_setup
в версии 0.1.5 и не увидел никаких сценариев обновления для запуска, поскольку оба скрипты указали, что их следует запустить с версии 0.1.0
Правильный способ добиться того, что мы хотим, состоит в именовании наших скриптов следующим образом:
upgrade-0.1.0-0.1.5.php #Этот обновляет с 0.1.0 до 0.1.5 upgrade-0.1.5-0.2.0.php #А этот обновляет с 0.1.5 до 0.2.0
Magento достаточно умен, чтобы запускать оба скрипта при загрузке одной страницы. Вы можете вернуться во времени и попробовать это, обновив таблицу core_resource
UPDATE core_resource SET version = '0.1.0', data_version = '0.1.0' WHERE code = 'weblog_setup';
Одна из удивительных прихотей Magento системы в том, что обновления будут запускаться так, как это было ранее настроено. Это означает, что вам нужно быть осторожными, когда несколько разработчиков добавляют в систему свои сценарии обновления.
Подведение итогов
Теперь вы должны знать основы использования ресурсов инсталлирования Magento для создания версий скриптов миграции базы данных, а также понять скрипты, содержащиеся в core модулях. Кроме создания стандартного способа написания сценариев миграции для разработчиков, ресурсы инсталлирования становятся гораздо важнее при создании и модификации моделей Entity Attribute Value.
Автор: Alan Storm (http://alanstorm.com/magento_setup_resources/)
Перевод на русский: SebWeo
- Magento для PHP MVC разработчиков (Alan Storm) – ч.1/11
- Magento для PHP MVC разработчиков – разбор контроллера (ч.2/11)
- Magento для PHP MVC разработчиков – Макеты, Блоки и Шаблоны (ч.3/11)
- Magento для PHP MVC разработчиков – Модели и основы ORM (ч.4/11)
- Magento для PHP MVC разработчиков – Инсталлирование Ресурса (ч.5/11)
- Magento для PHP MVC разработчиков – Расширенный ORM – EAV (ч.6/11)
- Magento для PHP MVC разработчиков – Особая конфигурация системы (ч.7/11)
- Magento для PHP MVC разработчиков – Углубленная настройка системы (ч.8/11)
- Magento для PHP MVC разработчиков – Коллекции Varien Data (ч.9/11)
- Magento для PHP MVC разработчиков – Переопределение и обновляемость системы (ч.10/11)
- Magento для PHP MVC разработчиков – Конфигурация системы по умолчанию (ч.11/11)