Создание модуля для Magento — часть 1

PHP*
Популярность Magento постоянно растет. Появляется множество новых интеренет-магазинов, написанных на этом замечательном движке.
К сожалению, информации для разработчиков маловато, поэтому, будем исправлять ситуацию :)
В мои планы входит написание нескольких статей о том, как создать модуль для Magento, на примере модуля блога.
Оригинал данной статьи находится на моем блоге.


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

Модуль создается в отдельном namespace. Обычно, namespace — это название компании разработчика модуля.
В данной статье я буду создавать модуль блога для Magento в своем неймспейсе Snowcore.
Название модуля не должно содержать символов подчеркивания. Все custom модули создаются в директории /app/code/local
Мой модуль будет называться Snowcore_Blog

Перейдем непосредственно к делу. Что же нужно для написания модуля для Magento?

Отключение кеша Magento


Первым делом отключаем cache в Magento, иначе не сможем увидеть своих изменений :) Отключить кеширование можно в админке: System — Cache Management — в первой вкладке Cache Control изменяем параметр All Cache на Disable, жмем Save cache settings

Создание структуры директорий


В папке модуля создаем следующую структуру:
/app/code/local/Snowcore/Blog/

    Block
    controllers
    etc
    Helper
    Model
    sql


Добавляем директорию для шаблонов:
/app/design/frontend/default/default/template/blog
(здесь первый default — это интерфейс, второй default — тема)

Подключение модуля


Для подключения модуля нужно создать XML файл конфигурации:
/app/etc/modules/Snowcore_Blog.xml

<?xml version="1.0"?>
<config>
  <modules>
    <Snowcore_Blog>
      <active>true</active>
      <codePool>local</codePool>
    </Snowcore_Blog>
  </modules>
</config>



На данном этапе Magento уже знает о нашем модуле. Включить или выключить его можно при помощи изменения параметра <active> конфигурационного файла.
Управлять модулем также можно через админку: System -> Configuration -> Advanced.
Значение local для узла <codePool> говорит о том, что наш модуль относится к custom модулям и размещается в папке /app/code/local

Создание XML конфигурации для модуля


Создаем новый xml файл: /app/code/local/Snowcore/Blog/etc/config.xml

<config>
    <modules>
        <Snowcore_Blog>
            <version>0.1.0</version>
        </Snowcore_Blog>
    </modules>
    <frontend>
        <routers>
            <blog>
                <use>standard</use>
                <args>
                    <module>Snowcore_Blog</module>
                    <frontName>blog</frontName>
                </args>
            </blog>
        </routers>
    </frontend>
    <admin>
        <routers>
            <blog>
                <use>admin</use>
                <args>
                    <module>Snowcore_Blog</module>
                    <frontName>blog</frontName>
                </args>
            </blog>
        </routers>
    </admin>
    <adminhtml>
        <menu>
            <blog module=“blog>
            <title>Blog</title>
            <sort_order>77</sort_order>
                <children>
                    <article module=“blog>
                        <title>Manage Articles</title>
                        <sort_order>0</sort_order>
                        <action>blog/adminhtml_article</action>
                    </article>
                </children>
            </blog>
        </menu>
        <acl>
            <resources>
                <all>
                    <title>Allow Everything</title>
                </all>
                <admin>
                    <children>
                        <blog>
                            <title>Blog Module</title>
                            <sort_order>200</sort_order>
                        </blog>
                    </children>
                </admin>
            </resources>
        </acl>
        <layout>
            <updates>
                <blog>
                    <file>blog.xml</file>
                </blog>
            </updates>
        </layout>
    </adminhtml>
    <global>
        <models>
            <blog>
                <class>Snowcore_Blog_Model</class>
                <resourceModel>blog_mysql4</resourceModel>
            </blog>
            <blog_mysql4>
                <class>Snowcore_Blog_Model_Mysql4</class>
                <entities>
                    <article>
                        <table>blog_articles</table>
                    </article>
                </entities>
            </blog_mysql4>
        </models>
        <resources>
            <blog_setup>
                <setup>
                    <module>Snowcore_Blog</module>
                </setup>
                <connection>
                    <use>core_setup</use>
                </connection>
            </blog_setup>
            <blog_write>
                <connection>
                    <use>core_write</use>
                </connection>
            </blog_write>
            <blog_read>
                <connection>
                    <use>core_read</use>
                </connection>
            </blog_read>
        </resources>
        <blocks>
            <blog>
                <class>Snowcore_Blog_Block</class>
            </blog>
        </blocks>
        <helpers>
            <blog>
                <class>Snowcore_Blog_Helper</class>
            </blog>
        </helpers>
    </global>
</config>



В данном файле определяются основные настройки модуля.
Секция <adminhtml> отвечает за настройки меню и доступов к разным ресурсам в админ части приложения.
Часть <global> хранит информацию об используемых моделях и ресурсах, хелперах и блоках.

Создание Helper


Хелпер содержит всего пару строчек кода /app/code/local/Snowcore/Blog/Helper/Data.php

<?php
class Snowcore_Blog_Helper_Data extends Mage_Core_Helper_Abstract
{

}



Этот хелпер нужен для того, чтобы работала система переводов.
На данном этапе у нас должен появиться новый пункт в главном меню админки:
Magento admin menu


Сразу создадим хелпер для статей:
/app/code/local/Snowcore/Blog/Helper/Article.php

<?php
class Snowcore_Blog_Helper_Article extends Mage_Core_Helper_Abstract
{

}



Создание моделей


Magento использует «тонкие» модели. Есть два типа моделей:
  • Обычная модель: отвечает за бизнес-логику
  • Ресурс-модель, которая работает с базой

Для начала нам понадобятся модели для статей.

Создаем обычную модель:
/app/code/local/Snowcore/Blog/Model/Article.php

<?php
class Snowcore_Blog_Model_Article extends Mage_Core_Model_Abstract
{
    public function _construct()
    {
        parent::_construct();
        $this->_init(‘blog/article’);
    }
}



В ней мы указываем ресурс-модель, с которой будет работать данная модель.

Создаем ресурс-модель:
/app/code/local/Snowcore/Blog/Model/Mysql4/Article.php

<?php
class Snowcore_Blog_Model_Mysql4_Article extends Mage_Core_Model_Mysql4_Abstract
{
    public function _construct()
    { 
        $this->_init('blog/article', 'article_id');
    }
}



Второй параметр метода _init это первичный ключ таблицы articles.

Создаем коллекцию для статей:
/app/code/local/Snowcore/Blog/Model/Mysql4/Article/Collection.php
С коллекциями работает grid, который показывает список сущностей (статей).

<?php
class Snowcore_Blog_Model_Mysql4_Article_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
{
    public function _construct()
    {
        parent::_construct();
        $this->_init('blog/article');
    }
}



SQL установщик для модуля


Установка модуля (создание таблиц в базе) происходит автоматически.
Здесь главное правильно указать версию для модуля, она должна совпадать с версией, которая назначена в XML конфигурации.
/app/code/local/Snowcore/Blog/sql/blog_setup/mysql4-install-0.1.0.php

<?php
$installer = $this;

$installer->startSetup();

$installer->run("

– DROP TABLE IF EXISTS {$this->getTable('blog_articles')};
CREATE TABLE {$this->getTable('blog_articles')} (
 `article_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `title` varchar(150) NOT NULL,
 `slug` varchar(150) NOT NULL,
 `content` text,
 `meta_keywords` varchar(255) NOT NULL DEFAULT '',
 `meta_description` varchar(160) NOT NULL DEFAULT '',
 `created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 PRIMARY KEY (`article_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
    "
);

$installer->endSetup();



Установка модуля (создание необходимых таблиц) происходит автоматически — при обращении к любой странице. Если возникают проблемы с установкой модуля (таблицы не создались) — посмотрите в базе таблицу core_resource, там должна быть запись со значением code = blog_setup. Удалите запись, модуль переустановится.

Создание Layout модуля


Создаем новый XML:
/app/design/adminhtml/default/default/layout/blog.xml

<?xml version="1.0"?>
<layout version="0.1.0">
    <blog_adminhtml_article_index>
        <reference name="content">
            <block type="blog/adminhtml_article" name="article" />
        </reference>
    </blog_adminhtml_article_index>
</layout>



Создание блоков


Блоки отвечают за отображение модуля. В рамках первой статьи создаем блоки для админки.
Изначально нам понадобится блок для отображения списка существующих записей — grid.

Создаем контейнер для grid:
/app/code/local/Snowcore/Blog/Block/Adminhtml/Article.php

<?php
class Snowcore_Blog_Block_Adminhtml_Article extends Mage_Adminhtml_Block_Widget_Grid_Container
{
    public function __construct()
    {
        $this->_controller = 'adminhtml_article';
        $this->_blockGroup = 'blog';
        $this->_headerText = Mage::helper('blog/article')->__('Articles Manager');
        $this->_addButtonLabel = Mage::helper('blog/article')->__('Add Article');
        parent::__construct();
    }
}



Далее создаем сам Grid:
/app/code/local/Snowcore/Blog/Block/Adminhtml/Article/Grid.php

<?php
class Snowcore_Blog_Block_Adminhtml_Article_Grid extends Mage_Adminhtml_Block_Widget_Grid
{
    public function __construct()
    {
        parent::__construct();
        $this->setId('blogArticleGrid');
        $this->setDefaultSort('article_id');
        $this->setDefaultDir('ASC');
        $this->setSaveParametersInSession(true);
    }

    protected function _prepareCollection()
    {
        $collection = Mage::getModel('blog/article')->getCollection();
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }

    protected function _prepareColumns()
    {
        $this->addColumn('article_id', array(
         'header'    => Mage::helper('blog/article')->__('ID'),
         'align'     => 'right',
         'width'     => '50px',
         'index'     => 'article_id',
        ));

        $this->addColumn('title', array(
         'header'    => Mage::helper('blog/article')->__('Title'),
         'align'     => 'left',
         'index'     => 'title',
        ));

        return parent::_prepareColumns();
    }

    public function getRowUrl($row)
    {
        return $this->getUrl('*/*/edit', array('id' => $row->getId()));
    }
}



Кратко о гриде:
  • В конструкторе мы задаем параметры сортировки
  • В методе _prepareCollection указывается, с какой коллекцией будет работать grid
  • Метод _prepareColumns позволяет определить, какие колонки будут отображаться в таблице сущностей
  • Метод getRowUrl определяет формат ссылки для перехода на форму редактирования (при клике на определенную строку)


Cоздание контроллера



В рамках этой статьи у контроллера будет только index action (отображение таблицы со статьями)
/app/code/local/Snowcore/Blog/controllers/Adminhtml/ArticleController.php

<?php
class Snowcore_Blog_Adminhtml_ArticleController extends Mage_Adminhtml_Controller_action
{
    protected function _initAction()
    {
        $this->loadLayout()
            ->_setActiveMenu('blog/article')
            ->_addBreadcrumb(Mage::helper('adminhtml')->__('Articles Manager'), Mage::helper('adminhtml')->__('Articles Manager'));
        return $this;
    } 
 
    public function indexAction()
    {
        $this->_initAction()     
            ->renderLayout();
    }
}



Итог


Наш контроллер пока содержит index действие, в котором происходит инициализация layout и breadcrumbs. На данном этапе на странице Manage Articles отображается содержимое таблицы статей. Таблица пока пустая, но для проверки работоспособности грида, можете добавить вручную пару записей в базу.
Mage_Adminhtml_Block_Widget_Grid предоставляет возможность использования фильтра и сортировки списка по заданным полям.

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

Следите за обновлениями!

See you soon ;-)
+24
6 января 2010, 17:59
64
Snowcore 17,0

комментарии (30)

+1
Scorpion #
Спасибо очень интересует информация про этот продукт…
0
jeje #
>Первым делом отключаем cache в Magento,
или чистим var/cache

сколько о Magento не пиши, а все равно вопросов много ;)
0
Snowcore #
Я бы сказал даже так:
«Первым делом отключаем cache в Magento И чистим var/cache»
0
McAndrews #
Не соглашусь с отключение кеша — в этом случае достаточно сильно замедляется генерация страниц, а при разработке обычно приходится по многу раз перегружать страницы, что приводит к потери времени. Очистка кеша в освновном нужна, если были изменены xml-файлы, а при изменении php, phtml, css и т.д. кеш очищать не обязательно. Для быстрой очистки кеша так же можно написать скрипт (unix: rm -rf var/caсhe/*, windows: del /S /Q var\cache\*) и вызывать его по комбинации клавиш.
+2
lozoffoy #
Статья хорошая, но вот после дискуссии о необходимости очистки кеша лично у меня «нарисовался» некий скептицизм.

При адекватном проектировании, продукт должен работать быстро и без кеша. А кеширование включают при повышенных нагрузках на сервер, либо при тяжёлой БД.
0
McAndrews #
Да, вы совершенно правы — производительность в Magento это одно из самых узких мест ). Для этого, в боле-менее больших проектах её поднимают на кластерах (в облаках). Или специально-оптимизированные хостинги на производительных серверах для «небольших» проектов используют (memcache, eAccelerator и т.д.). На обычном VPS можно и не пытаться ).

Но список встроенных функций, гибкая конфигурация, достаточно большое количество модулей, большое комьюнити, возможность интеграции с существующими учётными системами и магазинами для многих перекрывает её недостатки.
0
Snowcore #
Модуль будет работать с включенным кешем
0
Snowcore #
Я имел ввиду отключить кеш на время разработки модуля :)
0
lozoffoy #
Дело даже не в том, что кеш нужно отключить на время разработки.

Сам подход к проектированию CMS должен подразумевать, что необходимость кеша встает только при наличии «отягчающих обстоятельств». Будь то набег ботов, посещаемость 50000 в сутки либо магазин на 100000 товаров.

Брать за основу разработки ZF также не самое оптимальное решение. Да это ускорит разработку, но и налагает рад зависимостей от стороннего продукта. Что в конкретном случае, добавляет камень в огород ресурсоёмкости.

ZF отлично подходит для штучного продукта, который нужно сдать в срок и забыть про него, либо для очень узко направленной не изощрённой CMS.

Когда же заходит разговор о чём-то серьёзном да ещё и с намеком на дальнейшее динамичное развитие. К сожалению приходится писать практически всё с нуля и ручками. Нарабатывать тех процесс, API и пр.

Здесь же, на мой взгляд, разработчики сделали уклон в сторону быстрого старта. Забыв о том, что всю эту красоту в дальнейшем придётся тянуть на себе.

Я не по наслышке знаю что значит разработка CMS и как может аукнуться в будущем любая мелочёвка.
0
Snowcore #
1) Magento рассчитан в основном на крупные магазины. Например, poster.com, в базе которого находится более 200 тысяч продуктов или homedics.com

2) На самом деле Magento не вплотную завязан на Zend Framework. Начало разработки Magento начиналось в то время, когда ZF был на стадии первой версии. Поэтому часть логики была написана разработчиками Magento (это касалось контроллеров, роутинга и др.)
0
shamann #
насколько я заметил, отключение кэша действует только для frontend. Админка всё равно кэшируется. В любом случае лучше чистить var/cache в ручную.
0
NZea #
Для создания простого модуля, используйте следующюю статью: www.magentocommerce.com/wiki/custom_module_with_custom_database_table

там есть файлик, для создания самого простого модуля.
0
shamann #
однако хорошо постарались в wiki, давно не проверял доки на официальном сайте. Раньше материалов по разработке там почти не было.
+2
Arekus #
Это очень перспективный движок! Судя по описанию, разработчики под него будут стоить очень дорого.
0
Shark #
Этот волнистый XML-конфиг так прикольно смотрится издалека :)
+6
Arekus #
Если его повернуть на 90 градусов, то он будет совпадать с силуэтом рельефа за окном разработчика!
0
Tremor #
скажите, а насколько быстро работает эта cms? какая нагрузка на сервер в сравнении, например, с drupal?
0
Snowcore #
Разработка идет стабильно, регулярно появляются новые версии. Нагрузка на сервер приличная.
0
shamann #
а вы установите локально и сами всё ощутите ;) Нагрузка очень большая.
0
spaceemangrechko #
Название модуля не должно содержать символов подчеркивания.
Мой модуль будет называться Snowcore_Blog
+1
Zaido #
Название модуля в данном случае «Blog», «Snowcore» выступает в роли неймспейса.
+1
advocat #
parent::_construct(); вызывать не нужно, так как в нем нет смысла :)

Как по мне, то статья получилась на 4ку, немного неудачное разбитие подачи информации, хотя видно, что автор старался и более-менее разобрался с мадженто :)

Из комментариев к этой части, удивило, что при частичном выкладывании автор попытался покрыть конфиг в большей степени c учетом напр frontend, но про частично описанную систему перевода в том же config забыл упомянуть

В Magento действительно получаются дорогостоящие операции по сборка xml (config, layout), и кеш по большому счету нужно чистить только при изменении xml файлов

Установка модуля (создание необходимых таблиц) происходит автоматически — при обращении к любой странице.

Если включен кеш и в нем лежит конфиг — этого не произойдет ;)
0
advocat #
К сожалению не удалось дописать комментарий полностью :)
Также чувствуется копипаст, особенно в некоторых местах с
www.magentocommerce.com/wiki/custom_module_with_custom_database_table

P.S. А вообще приятно читать про детище, которому ты посвятил больше 2х лет :)
С удовольствием почитаю продолжение
0
shamann #
детище?
поделитесь впечатлениями, очень интересен «взгляд изнутри» так сказать. AlexeyTokar интересно высказался
что вы думаете?
+1
advocat #
Улыбнуло™ читать комментарии от человека, который проработал месяц и которого уволили :)
Не мне его судить, так как мы лично не знакомы. Я пришел через пол года открытия компании в Киеве и Magento была в очень сыром виде, даже не было публичного бэта релиза. Могу заверить, что в компании никогда не было текучки кадров, а тем более большого числа приходящих и уходящих разработчиков. Возможно под этим он подразумевал себя и своего друга, которого уволили вместе с ним.

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

А в целом, я доволен результатом :)

Если есть какие-то более конкретные вопросы — готов на них ответить
НЛО прилетело и опубликовало эту надпись здесь
0
akramarev #
Спасибо за статью! Однако, есть готовый генератор кода для создания модуля, а как им воспользоваться описано, например, здесь (почти год назад): magento.verych.ru/2009/02/создание-нового-модуля-с-нуля/
+1
Snowcore #
Да, есть такое. Но для начала нужно научиться создавать структуру самому, ручками :)
0
dede #
0
Snowcore #
Not Found

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.