Разработка модулей для Magento 1.x — большой гайд + видео

21454f16b8cd4adb938c1e34c2103838.jpg

Привет, Хабр! Несмотря на давно уже выпущеную Magento 2, Magento первой версии еще живее всех живых и пока еще не собирается нас покидать. Команда Magento будет поддерживать первую версию продукта 3 года с даты выпуска версии 2, т.е. примерно до ноября 2018. Рынок пестрит широчайшим выбором тем, модулей и сервисов заточеных под Magento 1.x версии. И большое количество сайтов, которые сейчас на Magento 1.x, не торопятся обновляться. Работы много — выхлопа мало. А значит, разработка под Magento первых версий еще актуальна и так будет несколько лет.

Но не о перспективах развития e-commerce решений пойдет речь в этой статье. Тут я решил собрать своеобразный гайд по созданию модулей для Magento 1.x (далее просто Magento). Но не простой гайд, в котором надо всего лишь следовать инструкциям, а с небольшими пояснениями «почему пишем так, а не иначе». Я старался найти золотую середину между краткостью и достаточностью. И в первую очередь, гайд несет пользу новичкам в деле разработки модулей для Magento. Но и более опытным пользователям данный материал может принести пользу.

Собственно, я старался сделать каждую часть самодостаточной, т.е. если вас интересует только отдельный момент, то вы можете взять всю необходимую информацию из конкретного раздела и не бегать по всему гайду. А если уже какие-то участки из раздела у вас реализованы, то их можно и пропустить. Такое же и отношение к видео. Только видео уроков достаточно для работы, но и без видео можно обойтись, порядок дейтсвий и листинги с комментариями есть. Хотя некоторые вещи лучше глянуть в видео, т.к. там по мимо кодинга еще присутствуют и демонстрации работоспособности. Да и я просто мог, что-то упустить. Так что в видео могут присутствуют некоторые незадокументированные моменты, и в текстовой версии могут быть дополнения, которых нет в видео. Это было не избежно, т.к. все делалось в разное время.

  • Сервер на Ubuntu 16.04 LTS
  • Установка тестового магазина
  • Структура и конфигурация модуля
  • Отладка кода XDEBUG + PHPSTORM
  • Модели, коллекции. Работа с базой данных
  • Контроллеры и роутинг
  • Хелперы
  • Конфигурация модуля в админке
  • Frontend блоки. Макеты. Темплейты
  • Admin интерфейс. Грид. Форма редактирования
  • События и слушатели
  • Крон и задачи по расписанию
  • Использование рендереров в админке
  • Использование WYSIWYG редактора
  • Использование Rule Conditions (условий)
  • Использование вкладок на странице редактирования
  • Вывод таблицы (grid) товаров на странице редактирования и на frontend.
  • Создание модуля способа оплаты (Payment Method)
  • Модуль способа доставки (Shipping Method)

Подготовка


Все начинается с подготовки рабочего места, а в нашем случае — сервера с установленым тестовым магазином.

Если, у вас окружение уже готово — можете перейти к следующему разделу.

Сервер на Ubuntu 16.04 LTS


Скачиваем дистрибутив Ubuntu 16.04, конфигурируем «виртуалку». И устанавливаем Ubuntu на наш виртуальный компьютер. Процесс установки в целом простой и не требует документации, но весь процесс установки и настройки можно пройти в видео ниже.
Видео: Установка UBUNTU 16.04 — Nginx + php7-fpm + mysql + samba


Установим и настроим необходимый софт.
sudo su
apt-get install && apt-get upgrade

Ставим файловый менеджер, редактор и диспетчер задач
apt-get install mc nano htop

Настроим статически IP адрес (в принципе это можно и не делать, а статический адрес назначить на стороне роутера):
nano /etc/network/interfaces

Пример настройки:
iface eth0 inet static
address 192.168.0.100
netmask 255.255.255.0
gateway 192.168.0.1
dns-nameservers 192.168.0.1 8.8.8.8
auto eth0

где eth0 — сетевой интерфейс. Его можно посмотреть написав ifconfig
Вебсервер Nginx:
apt-get install nginx

PHP 7.0 FPM:
apt-get install php-fpm php-xdebug php-soap php-gd php-mbstring php-mcrypt php-curl php-xml

MySQL 5.7 и phpMyAdmin:
apt-get install mysql-server-5.7 phpmyadmin

Сменим владельца и права на папку, где будут файлы магазина:
chown -R dev:dev /var/www
chmod -R 777 /var/www

dev: dev  — имя и группа пользователя. Я использовал это имя при установке Ubuntu.
Теперь необходимо настроить установленое ПО.

Nginx


Я сделал 3 конфига для Nginx: динамический домен, конфиг для Magento 2 (пригодится), конфиг для phpMyAdmin. Прицнип действия так называемого конфига с динамическими доменами прост.
  • Мы настраиваем у себя соответствие домен — IP. Как мы это делаем, не важно, я прописываю в hosts файле. Например, magento.dev 192.168.0.100
  • Когда Nginx получает запрос, он делает server_root путь вида /var/www/(доменное имя). Пример: пишем в браузере magento.dev — server_root /var/www/magento.dev
  • Ну, а наш магазин необходимо разместить в папке /var/www/magento.dev

dynamic.conf
    server {
    listen 80;
    server_name $http_host;
    root /var/www/$http_host;

    location / {
    index index.html index.php;
    try_files $uri $uri/ @handler;
    expires 30d;
    }

    location  /. {
    return 404;
    }

    location @handler {
    rewrite / /index.php;
    }

    location ~ .php/ {
    rewrite ^(.*.php)/ $1 last;
    }

    location ~ .php$ {
    if (!-e $request_filename) { rewrite / /index.php last; }

    expires        off;
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  SCRIPT_NAME  $document_root$fastcgi_script_name;
    fastcgi_param  MAGE_RUN_TYPE store;
    include        fastcgi_params;
    }
    }

    


m2.conf
    # Magento Vars

    #
    # Example configuration:
    upstream fastcgi_backend {
    server   unix:unix:/run/php/php7.0-fpm.sock;
    }
    server {
    set $MAGE_ROOT /var/www/m2.dev;
    set $MAGE_MODE default; # or production or developer
    listen 80;
    server_name m2.dev;
    root /var/www/m2.dev/pub;

    index index.php;
    autoindex off;
    charset off;

    add_header 'X-Content-Type-Options' 'nosniff';
    add_header 'X-XSS-Protection' '1; mode=block';

    location /setup {
    root $MAGE_ROOT;
    location ~ ^/setup/index.php {
    fastcgi_pass   fastcgi_backend;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;
    }

    location ~ ^/setup/(?!pub/). {
    deny all;
    }

    location ~ ^/setup/pub/ {
    add_header X-Frame-Options "SAMEORIGIN";
    }
    }

    location /update {
    root $MAGE_ROOT;

    location ~ ^/update/index.php {
    fastcgi_split_path_info ^(/update/index.php)(/.+)$;
    fastcgi_pass   fastcgi_backend;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  PATH_INFO        $fastcgi_path_info;
    include        fastcgi_params;
    }

    # deny everything but index.php
    location ~ ^/update/(?!pub/). {
    deny all;
    }

    location ~ ^/update/pub/ {
    add_header X-Frame-Options "SAMEORIGIN";
    }
    }

    location / {
    try_files $uri $uri/ /index.php?$args;
    }

    location /pub {
    location ~ ^/pub/media/(downloadable|customer|import|theme_customization/.*\.xml) {
    deny all;
    }
    alias $MAGE_ROOT/pub;
    add_header X-Frame-Options "SAMEORIGIN";
    }

    location /static/ {
    if ($MAGE_MODE = "production") {
    expires max;
    }
    location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ {
    add_header Cache-Control "public";
    add_header X-Frame-Options "SAMEORIGIN";
    expires +1y;

    if (!-f $request_filename) {
    rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last;
    }
    }
    location ~* \.(zip|gz|gzip|bz2|csv|xml)$ {
    add_header Cache-Control "no-store";
    add_header X-Frame-Options "SAMEORIGIN";
    expires    off;

    if (!-f $request_filename) {
    rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last;
    }
    }
    if (!-f $request_filename) {
    rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last;
    }
    add_header X-Frame-Options "SAMEORIGIN";
    }

    location /media/ {
    try_files $uri $uri/ /get.php?$args;

    location ~ ^/media/theme_customization/.*\.xml {
    deny all;
    }

    location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ {
    add_header Cache-Control "public";
    add_header X-Frame-Options "SAMEORIGIN";
    expires +1y;
    try_files $uri $uri/ /get.php?$args;
    }
    location ~* \.(zip|gz|gzip|bz2|csv|xml)$ {
    add_header Cache-Control "no-store";
    add_header X-Frame-Options "SAMEORIGIN";
    expires    off;
    try_files $uri $uri/ /get.php?$args;
    }
    add_header X-Frame-Options "SAMEORIGIN";
    }

    location /media/customer/ {
    deny all;
    }

    location /media/downloadable/ {
    deny all;
    }

    location /media/import/ {
    deny all;
    }

    location ~ cron\.php {
    deny all;
    }

    location ~ (index|get|static|report|404|503)\.php$ {
    try_files $uri =404;
    fastcgi_pass   fastcgi_backend;

    fastcgi_param  PHP_FLAG  "session.auto_start=off \n suhosin.session.cryptua=off";
    fastcgi_param  PHP_VALUE "memory_limit=256M \n max_execution_time=600";
    fastcgi_read_timeout 600s;
    fastcgi_connect_timeout 600s;
    fastcgi_param  MAGE_MODE $MAGE_MODE;

    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;
    }
    }

    


phpmyadmin.conf
    server {
    listen 80;
    server_name pma myadmin;
    root /usr/share/phpmyadmin/;
    index index.php;

    location /setup/index.php {
    deny all;
    }
    location ~ .php$ {
    if (!-e $request_filename) { rewrite / /index.php last; }

    expires        off;
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  SCRIPT_NAME  $document_root$fastcgi_script_name;
    fastcgi_param  MAGE_RUN_TYPE store;
    include        fastcgi_params;
    }
    include        fastcgi_params;
    }
    

Кладем конфиги в папку /etc/nginx/sites-availiable/ и делаем симлинки на них в папке /etc/nginx/sites-enabled/. Или просто складываем их в папку /etc/nginx/sites-enabled/

PHP 7.0 FPM


Редактируем /etc/php/7.0/fpm/php.ini. Нас волнуют только некоторые параметры, которые в принципе можно настроить на свой вкус.
    max_execution_time = 300
    max_input_time = 160
    memory_limit = 512M
    display_errors = On
    log_errors = On
    html_errors = On
    date.timezone = (тут свою таймзону указать)

Samba server
Мне нравится работать через самбу, подмонтировать себе сетевой диск и спокойно копировать файлы. Но вам она может и не понадобиться. На вкус и цвет, как говорится… Мой конфиг таков:
smb.conf

    [global]
    workgroup = WORKGROUP

    server string = %h server (Samba, Ubuntu)

    dns proxy = no

    log file = /var/log/samba/log.%m

    max log size = 1000

    syslog = 0

    panic action = /usr/share/samba/panic-action %d

    server role = standalone server
    passdb backend = tdbsam

    obey pam restrictions = yes

    unix password sync = yes

    passwd program = /usr/bin/passwd %u
    passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .

    pam password change = yes

    map to guest = bad user
    null passwords = Yes
    guest account = www-data

    [www]
    path = /var/www/
    comment = WWW folder
    guest ok = yes
    browseable = yes
    read only = no
    locking = no
    force user = www-data
    force group = www-data
    


Установка тестового магазина


Процесс установки прост и не требует каких-то особых умений. Но для внесения ясности, оставлю видео-инструкцию спрятанную под спойлером.

Видео: Устанавливаем тестовый магазин Magento


Cоздание модуля



Структура и конфигурация


Видео: Структура и конфигурация модуля Magento


Созданная в уроке структура модуля IGN_Siteblocks-1.zip

Учиться создавать модули будем на примере модуля для вывода блоков на страницах магазина (его frontend части). И первым делом мы придумываем название модуля. Название должно быть коротким и нести смысл. А еще нам нужно выбрать неймспейс (обычно название компании разработчика или его ФИО). И финальное наименование принимает вид Namespace_Modulename. В нашем случае я назвал IGN_Siteblocks.

Создадим регистрационный XML файл:

app/etc/modules/IGN_Siteblocks.xml
    
    
        
            
                true 
                local
            
        
    
    

Поговорим о codePool. Всего их 3: local, community, core (и enterprise в Enterprise версии Magento).

И сразу решим, что в core мы ничего изменять не будем, там базовые файлы системы и если их надо изменить, то есть другие способы, помимо их непосредственного редактирования.
Мы можем спокойно использовать local и community (На самом деле, лучше сразу взять community, но в этом примере будет local).

Зайдем в админку магазина, в раздел System > Configuration > Advanced > Disable Modules Output и увидим наш IGN_Siteblocks.

Создадим папки для нашего модуля:

app/code/local/IGN/Siteblocks/

  1. Block  — классы блоков, отвечают за рендеринг страниц
  2. controllers  — контроллеры принимают запросы
  3. etc  — тут всякие конфигурационные файлы
  4. Helper  — дополнительные классы помощники
  5. Model  — модели
  6. sql  — инсталяционные скрипты

Модули в Magento реализуют паттерн MVC. У нас есть модели, вид (блоки, темплейты и макеты) и контроллеры. В папке etc создадим config.xml
app/code/local/IGN/Siteblocks/etc/config.xml
    
    
        
            
                1.0.0
            
        
        
            
        
        
            
        
        
            
        
        
            
        
        
            
        
    
    


Тут мы будем декларировать наши блоки, модели, контроллеры, хелперы, обсерверы, реврайты, макеты, переводы и стандартные значения некоторых настроек модуля.

Отладка кода XDEBUG + PHPSTORM


Видео: Отладка кода XDEBUG + PHPSTORM


Тут я бы все-таки рекомендовал посмотреть на видеоинструкцию. Сначала настроим сервер:
apt-get install php-xdebug

Отредактируем настройки в php.ini или xdebug.ini
/etc/php/7.0/conf.d/20-xdebug.ini
zend_extension = xdebug.so
xdebug.idekey = "PHPSTORM"
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 1
xdebug.remote_enable = 1
xdebug.remote_port = 9000


Сохраняем и не забываем перезагрузить сервис service php7.0-fpm restart. В PHPSTORM создаем новый Remote Debug конфиг.

Добавляем сервер с соответсвтующим адресом и портом. В поле IDE key вводим слово PHPSTORM.

Модели, коллекции. Работа с базой данных.


Видео: Модели, коллекции. Работа с базой данных Magento


Созданная в уроке структура модуля IGN_Siteblocks-2.zip

Модели представляют собой классы для работы с данными и только данными. Никаких тонкостей со способом сохранения этих данных в базе. Никакого кода связанного с рендерингом этих данных. В Magento это: Customer, Product, Order и тд.

Что бы наш модуль мог использовать модели, необходимо отконфигурировать config.xml
Напомню, что модели, блоки и хелперы добавляются в global секцию. config.xml принимает следующий вид:

app/code/local/IGN/Siteblocks/etc/config.xml
    
    
        
            
                1.0.0
            
        
        
            
                 
                    IGN_Siteblocks_Model
                    siteblocks_resource
                
                
                    IGN_Siteblocks_Resource
                    
                         
                            ign_siteblock
IGN_Siteblocks


Важно определиться с названием префикса (не знаю какой термин тут подойдет лучше). Я выбрал siteblocks. Это произвольное название и как правило формируется из неймспейса и имя модуля или только имени модуля. Ну или для запутывания разработчиков, можно выбрать совершенно произвольную строку, заранее прикупив оберег от проклятий.

Выбирайте четко и желательно без использования заглавных символов. Одна опечатка, и будете долго копаться, искать проблему. Название модели и привязка к таблице. Имя модели соответствует названию файла модели. Название таблицы в базе произвольное. В моем случае что бы обратиться к модели, нужно написать так:

Mage::getModel('siteblocks/block');

Теперь можно добавлять модели. Создадим модель Block. Для каждой, привязанной к таблице, модели нужно создавать 3 файла: модель, ресурсная модель, модель коллекции. Модель абстрагируется от работы с базой, ресурсные модели находятся уровнем ниже. Там мы реализуем логику фильтрации, сортировки, обработки данных до их сохранения и после загрузки из базы.
Код модели Block.php:
app/code/local/IGN/Siteblocks/Model/Block.php
    _init('siteblocks/block'); //Все в соотвествии с указанными в config.xml параметрами
    }
    }
    


Модели наследуется от Mage_Core_Model_Abstract. Ресурсные модели сохраняем в папке Model/Resource.
app/code/local/IGN/Siteblocks/Model/Resource/Block.php
    _init('siteblocks/block','block_id'); //block_id это наш PRIMARY KEY в таблице, по умолчанию entity_id
    }

    }
    


app/code/local/IGN/Siteblocks/Model/Resource/Block/Collection.php
    _init('siteblocks/block');
    }
    }
    


Наши классы пусты, но они уже реализуют необходимый минимум функционала по наследованию.
Добавлять в них код будем по необходимости. А если мы хотим добавить еще моделей, то добавляем еще одну привязку модели к таблице и новых 3 файла. Можно сколько угодно добавлять моделей, не привязанных к таблице (просто для реализации какого-то функционала), то просто добавляем новый файл, наследоваться от Mage_Core_Model_Abstract не обязательно.

Не забываем создать инсталяционный скрипт, который будет создавать таблицу для нашей модели.

app/code/local/IGN/Siteblocks/sql/siteblocks_setup/install-1.0.0.sql
    startSetup();

    $installer->run("
    CREATE TABLE IF NOT EXISTS `{$this->getTable('siteblocks/block')}` (
    `block_id` int(11) NOT NULL AUTO_INCREMENT,
    `title` varchar(500) NOT NULL,
    `content` text NOT NULL,
    `block_status` tinyint(4) NOT NULL,
    `created_at` datetime NOT NULL,
    PRIMARY KEY (`block_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
    ");

    //Альтернативный способ создания таблицы
    $table = $installer->getConnection()
    ->newTable($this->getTable('siteblocks/block'))
    ->addColumn('block_id',Varien_Db_Ddl_Table::TYPE_INTEGER,null,array(
    'identity' => true,
    'unsigned' => true,
    'nullable' => false,
    'primary'  => true
    ))
    ->addColumn('title',Varien_Db_Ddl_Table::TYPE_VARCHAR,null,array(
    'nullable' => false
    ))
    ->addColumn('content',Varien_Db_Ddl_Table::TYPE_TEXT,null,array(
    'nullable' => false
    ))
    ->addColumn('block_status',Varien_Db_Ddl_Table::TYPE_TINYINT,null,array(
    'nullable' => false
    ))
    ->addColumn('created_at',Varien_Db_Ddl_Table::TYPE_DATETIME,null,array(
    'nullable' => false
    ));

    $installer->endSetup();
    


ВАЖНЫЙ МОМЕНТ!

Если вы уже пробовали зайти в админку, при установленом модуле, когда еще не было инсталяционного скрипта. Скорее всего ваш инсталл скрипт больше никогда не запустится. В этом случае необходимо найти и удалить запись siteblocks_setup из таблицы core_resource в базе магазина.

При апгрейде версии модуля. Мы указываем новую версию в config.xml, например: 1.0.1. И создаем апгрейд скрипт: upgrade-1.0.0–1.0.1.php. И в таком же духе при последующих апгрейдах.

Говоря о моделях и коллекциях, нельзя не упомянуть о самых базовых методах этих классов.

Немного примеров использования моделей
    //Загрузить объект из таблицы block_id = 1
    $block = Mage::getModel('siteblocks/block')->load(1);

    //Удалить блок
    $block->delete();

    //Cохранить
    $block->save();

    //удалить блок не делая его загрузки из базы
    Mage::getModel('siteblocks/block')->setId(1)->delete();

    //Загрузить коллекцию блоков из таблицы
    $blocks = Mage::getModel('siteblocks/block')->getCollection();

    //Коллекция блоков где block_id = 1, 2 и 3
    $blocks->addFieldToFilter('block_id',array('in'=>array(1,2,3))) ;

    echo $blocks->getSelect(); //выведет сформировавшийся SQL запрос

    //Альтернативный способ загрузки коллекции
    $blocks = Mage::getResourceModel('siteblocks/block_collection');
    



Контроллеры и роутинг


Видео: Контроллеры и роутинг в Magento.


Созданная в уроке структура модуля IGN_Siteblocks-3.zip

Контроллеры, согласно паттерну MVC, отвечают за обработку запросов. Принимают на себя так называемый входной сигнал в виде HTTP запроса. Перешел по ссылке — отработал соответствующий контроллер.

Перед созданием контроллеров сконфигурируем роутинг в config.xml. Роутинг для frontend и admin части настраивается отдельно. А значит добавляем routers в секцию frontend и admin.

config.xml принимает вид:

app/code/local/IGN/Siteblocks/etc/config.xml
    
    
        
            
                1.0.0
            
        
        
            
                
                    IGN_Siteblocks_Model
                    siteblocks_resource
                
                
                    IGN_Siteblocks_Resource
                    
                        
                            ign_siteblock
IGN_Siteblocks
standard IGN_Siteblocks siteblocks IGN_Siteblocks_Adminhtml


Теперь можно создавать свои контроллеры в папке controllers нашего модуля. Класс контроллера для frontend части должен наследоваться от класса Mage_Core_Controller_Front_Action.

Создадим тестовый контроллер TestController.php

app/code/local/IGN/Siteblocks/controllers/TestController.php


Если сейчас перейти по URL вида example.com/siteblocks/test/mytest. Вы увидете белый экран с надписью «test». Если этого не произошло, значит на каком-то этапе произошла ошибка.

Перепроверяйте код и читайте логи. URL состоит из router (siteblocks) / controller (TestController) / action (mytestAction)

GET параметры можно передавать 2 мя способами:

  • Классическим способом: example.com/siteblocks/test/mytest? param=val¶m2=val
  • Через слэши: example.com/siteblocks/test/mytest/param/val/param2/val

Контроллеры для админки создаются в папке controllers/Adminhtml. Класс контроллера для frontend части должен наследоваться от класса Mage_Adminhtml_Controller_Action.

Создадим тестовый контроллер TestController.php:

app/code/local/IGN/Siteblocks/controllers/Adminhtml/TestController.php


На него можно зайти по URL: example.com/admin/test/mytest — где admin это ваш путь в админку.

И тут есть ньюанс: такой урл уже может быть занят другим модулем. Выхода тут 2: меняем название контроллера на заведомо неконфликтное (например IgntestController.php) или складываем контроллеры в подпапку.

app/code/local/IGN/Siteblocks/controllers/Adminhtml/Siteblocks/TestController.php


Теперь наш URL принимает вид: example.com/admin/siteblocks_test/mytest

Хелперы


Видео: Хелперы в Magento


Созданная в уроке структура модуля IGN_Siteblocks-4.zip

Классы хелперов в Magento используются как дополнительные классы. В них стоит реализовывать стороннюю логику, которая не вписывается в функционал моделей, блоков или контроллеров. Но модуль нуждается как минимум в одном классе хелпера Data.php.

Этот хелпер используется по-умолчанию для перевода текста (лейблов, пунктов меню и тд) и другой логики.

В хелпере рекомендуется декларировать методы чтения настроек из конфига. Хелперы должны наследоваться от класса Mage_Core_Helper_Abstract.

app/code/loca/IGN/Siteblocks/Helper/Data.php


Для переводов текста в хелпере существует метод __(), а его применение выглядит так:
echo Mage::helper('siteblocks')->__('Some text')

Файлы переводов мы декларируем в config.xml.
app/code/local/IGN/Siteblocks/etc/config.xml


    
        
            1.0.0
        
    
    
        
            
                IGN_Siteblocks_Model
                siteblocks_resource
            
            
                IGN_Siteblocks_Resource
                
                    
                        ign_siteblock
IGN_Siteblocks IGN_Siteblocks_Helper
standard IGN_Siteblocks siteblocks IGN_Siteblocks.csv IGN_Siteblocks_Adminhtml


А файл IGN_Siteblocks.csv создаем в папке app/locale/en_US/. Содержимое вида: «Some text», «Some text».

Стараемся выводить текст с использованием своего хелпера и в таком случае, упрощается локализация модуля на разные языки.

Достаточно скопировать файл переводов в соответствующую локаль и перевести второй столбец и нет необходимости копаться в коде.

Конфигурация модуля в админке


Видео: Конфигурация модуля в админке Magento


Созданная в уроке структура модуля IGN_Siteblocks-5.zip

Для придания модулю гибкости, мы создадим страницу с настройками модуля. Делается это сугубо через xml файлы. Нам необходимо создать 2 файла:

system.xml — где будут добавлены поля
adminhtml.xml — где будут указаны разделы и права доступа

А стандартные значения настроек мы можем указать в секции default в файле config.xml

app/code/local/IGN/Siteblocks/etc/config.xml


    
        
            1.0.0
        
    
    
        
            
                IGN_Siteblocks_Model
                siteblocks_resource
            
            
                IGN_Siteblocks_Resource
                
                    
                        ign_siteblock
IGN_Siteblocks IGN_Siteblocks_Helper
standard IGN_Siteblocks siteblocks IGN_Siteblocks.csv IGN_Siteblocks_Adminhtml 1 10


app/code/local/IGN/Siteblocks/etc/adminhtml.xml


    
        
            
                
                    
                        
                            
                                
                                    
                                        Siteblocks
                                    
                                
                            
                        
                    
                
            
        
    



app/code/local/IGN/Siteblocks/etc/system.xml


     
         
            
            2
        
    
    
        
            
            ign 
            text
            1
            1
            1
            1
            
                
                    
                    1
                    1
                    1
                    1
                    1
                    
                        
                            
                            select 
                            siteblocks/source_status 
                            1
                            1
                            1
                            1
                            Is module enabled
                        
                        
                            
                            text
                            2
                            1
                            1
                            1
                            1 
                        
                        
                            
                            textarea
                            3
                            1
                            1
                            1
                            1
                        
                    
                
            
        
    



В наших настройках выводится дропдаун с опциями, и используется собственная модель для этих опций:
app/code/local/IGN/Siteblocks/Model/Source/Status.php
 self::ENABLED, 'label'=>Mage::helper('siteblocks')->__('Enabled')),
            array('value' => self::DISABLED, 'label'=>Mage::helper('siteblocks')->__('Disabled')),
        );
    }

    /**
     * Get options in "key-value" format
     *
     * @return array
     */
    public function toArray()
    {
        return array(
            self::DISABLED => Mage::helper('siteblocks')->__('Disabled'),
            self::ENABLED => Mage::helper('siteblocks')->__('Enabled'),
        );
    }




Frontend блоки. Макеты. Темплейты


Видео: Frontend блоки. Макеты. Темплейты Magento


Созданная в уроке структура модуля IGN_Siteblocks-6.zip

Займемся выводом информации на frontend части магазина. И, как не сложно догадаться из заголовка, у нас будут задействованы 3 типа файлов: блоки, макеты и темплейты.

Блоки это классы, отвечающие за подготовку и вывод информации. Блоки используют для вывода темплейты, но не всегда. Если используется темплейт, то он просто инклюдится в методе fetchView:

112287ad9c1345a9bc7c6bea34bef52d.png

Поэтому из темплейта к блоку обращаемся через $this.

app/code/local/IGN/Siteblocks/Block/List.php
getCollection()
            ->addFieldToFilter('block_status',array('eq'=>IGN_Siteblocks_Model_Source_Status::ENABLED));
    }
}


Блок наследуется от класса Mage_Core_Block_Template . Но это зависит от того, что наш блок будет выводить. Так, например, при выводе списка товаров, желательно наследоваться от блока Mage_Catalog_Block_Product_List. Макеты используются для построения структуры страницы, какие элементы выводить на странице и в каком порядке.

Создадим файл макетов:

app/design/frontend/base/default/layout/siteblocks.xml


     
        
            
                My Siteblocks
            
        
        
            
        
    

     
        
            
        
        
            
        
    

     
         
            
        
    



В макете мы можем добавлять js, css файлы в head, мы можем добавить или удалить блок в на какой-то интересующей нас странице. Тема макетов довольно обширна и сверху я привел минимально простой макет, который добавит наш блок в нескольких местах сайта.

Альтернативным вариантом (без макето) вы можете в контроллере вывести HTML код:

$html = Mage::app()->getLayout()->createBlock('siteblocks/list')->setTemplate('siteblocks/list.phtml')->toHtml()
$this->getResponse()->setBody($html);

И будет выведен HTML код только этого блока. Такое часто нужно, например при использовании AJAX запросов.

В макете у нас упоминается файл siteblocks/list.phtml. Его можно и не указывать, если в темплейте указать его по-умолчанию.

class IGN_Siteblocks_Block_List extends Mage_Core_Block_Template {
protected $_template = 'siteblocks/list.phtml';
}

Создадим темплейт:
app/design/base/default/template/siteblocks/list.phtml
getBlocks() as $block):?>
    
getTitle()?>
getContent()?>


Как видно в коде, мы вызываем метод блока getBlocks, возвращающий коллекцию записей, которые мы и выводим. Переименуем TestController или создадим новый. IndexController
app/code/local/IGN/Siteblocks/controllers/IndexController.php
loadLayout(); #загружаем макеты
        $this->renderLayout(); #выводим html
    }
}


URL по которому мы увидим вывод имеет вид: example.com/siteblocks/index/index или example.com/siteblocks, т.к. index/index можно опустить.

А handle в макете будет использоваться такой: siteblocks_index_index. Чтобы посмотреть на вывод записей, необходимо добавить их на прямую в базу или перейти к следующему шагу разработки формы редактирования.

Admin интерфейс. Грид. Форма редактирования.


Видео: Admin интерфейс. Грид. Форма редактирования в Magento


Созданная в уроке структура модуля IGN_Siteblocks-7.zip

Процесс создания Admin интерфейса состоит из нескольких этапов:

  • Добавляем пункты в меню
  • Создаем блоки
  • Создаем контроллеры

Добавляем пункты в меню:
app/code/local/IGN/Siteblocks/etc/adminhtml.xml


    
        
            
                
                    
                        
                            
                                
                                    
                                        Siteblocks
                                    
                                
                            
                        
                    
                    
                        
                            
                                Siteblocks
                            
                        
                    
                
            
        
    
            

© Habrahabr.ru