Янв 5

Популярность 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 уже знает о нашем модуле. Включить или выключить его можно при помощи изменения параметра конфигурационного файла.
Управлять модулем также можно через админку: System -> Configuration -> Advanced.
Значение local для узла говорит о том, что наш модуль относится к 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>

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

Создание 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 ;-)

Окт 9
Strip BBCode tags
icon1 Snowcore | icon2 Useful, php | icon4 10 9th, 2009| icon3No Comments »

Довольно популярная задача - убрать все BBCode теги из текста.
Сделать это можно при помощи следующео регулярного выражения:


Strip all BBCode tags:

<?php
    $text = preg_replace(/[[\/\!]*?[^\[\]]*?]/si, “”, $text);
?>


Авг 19
Zend PHP 5 Certification
icon1 Snowcore | icon2 php | icon4 08 19th, 2009| icon312 Comments »

Моя длительная подготовка к Zend PHP 5 Certification наконец-то начала переходить из этапа активного обучения к действиям.

Всем рекомендую сначала купить Zend PHP 5 Certification Online Practice Testing. Стоимость небольшая, а пользы очень много. Можно купить 1, 5 или 10 тестовых экзаменов по цене $10, $17 и $22 соответственно. Не пожалел, купил максимальное количество - 10 шт. Расплатился в интернет-магазине Zend при помощи VISA (этому магазину можно доверять на все 100, ведь он сделан на самой надежной и перспективной eCommerce платформе - Magento).

За отпуск все приобретенные знания подзабылись немножко, но я решил себя проверить - сдать первый пробный екзамен без повторения материала. Результатом очень доволен :-)

Результаты пробного теста

Что ж, подучу еще XML и Web services, streams and sockets, сдам еще парочку раз, и вперед!

Янв 27

Одной из частей Zend Framework Certification является Zend Coding Standards. Рассмотрим, что нужно знать для успешной сдачи сертификации (материал из официального руководства по подготовке к сертификации).

Хорошие стандарты кодирования являются очень важным аспектом в разработке любого проекта.
Особенно, если над одним проектом трудятся несколько разработчиков.
Наличие стандартов кодирования помогает удостовериться, что код имеет высокое качество,
мало багов и его легко поддерживать.

Форматирование PHP файлов

  • Никогда не используйте закрывающий тег “?>” для файлов, которые содержат только PHP код -
    это предотвращает от лишних пробелов и спецсимволов при выводе
  • Отступ должен - 4 пробела, не используйте символ табуляции
  • Максимальная длина строки - 120 символов, но старайтесь не превышать количества
    в 80 символов для понятности
  • Строки должны заканчиваться символом перехода на новую строку (Unix), но не символом возврата каретки или комбинацей последнего с первым

Правила именования

Имена классов

  • Имя класса должно быть привязано к его расположению в директориях (фактически имя класса - путь к файлу класса)
  • Содержат только буквенно-цифровые символы. Цифры не одобряются. Знак нижнего подчеркивания используется только в качестве разделителя пути к файлу класса (например: Zend/Db/Table.php привязан к Zend_Db_Table)
  • Имена, содержащие несколько слов: в общем случае, каждое слово содержит большую первую букву, остальные - в нижнем регистре (например: Zend_Pdf). Но есть исключения, когда слово представляет собой сокращение или какое-либо нестандартное слово (например: Zend_XmlRpc)
  • Классы, созданные разработчиками ZF или его партнерами, должны начинаться на “Zend_” и обязаны быть расположены в иерархии папки Zend/ и с другой стороны класс, написанный не разработчиками ZF никогда не может начинаться на “Zend_”

Интерфейсы

Интерфейсы должны следовать таким же правилам, как и классы, и заканчиваться словом “Interface
(например: Zend_Log_Adapter_Interface)

Имена файлов

  • Для всех файлов разрешаются буквенно-цифровые символы, символ подчеркивания и дефис. Пробелы запрещены
  • Любой файл, который содержит любой PHP код, должен иметь расширение “.php”, за исключением View скриптов

Имена функций

  • Могут содержать только буквенно-цифровые символы. Символ подчеркивания не разрешается.
    Цифры не желательны
  • Имена, состоящие из нескольких слов: camelCase стиль
  • Функция должна иметь осмысленное имя для улучшения понимания кода (ну это и так понятно :)
  • Аксессоры для объектов должны начинаться с “get” или “set” (ООП)
  • (Примечание: не рекомендуется использование функций в глобальной области видимости. В таком случае сделайте эти функции методами статического класса)

Имена методов

  • Всегда начинаются с буквы в нижнем регистре
  • Должны содержать имя паттерна, если он применяется
  • private и protected методы должны начинаться с символа нижнего подчеркивания
    (единственный случай, когда символ подчеркивания разрешен в имени метода) - хотя, сами Zendовцы не всегда придерживаются данного пункта :)

Имена переменных

  • Также как и функции могут содержать только буквенно-цифровые символы. Символ подчеркивания не разрешается. Цифры не желательны
  • Всегда начинаются с буквы в нижнем регистре, camelCase
  • private и protected переменные начинаются с подчеркивания

Именование констант

  • Могут содержать буквенно-цифровые символы и знаки подчеркивания
  • Используются буквы в верхнем регистре
  • Имена, состоящие из нескольких слов: каждое слово отделяется символом подчеркивания
  • Должны быть определены как члены класса при помощи конструкции “const”

Стиль кодирования

Установка границ PHP кода

  • PHP код должен быть разграничен тегами <?php и ?>
  • Короткая запись тегов не разрешена (<? и ?>)

Строки - литералы

  • Если строка является литералом (не содержит никаких подстановок переменных), то она определяется в одиночных кавычках (например: $str = ‘Пример строки-литерала’)
  • В случае, если строка содержит апостроф, она может быть заключена в двойные кавычки. Это особенно одобряется для написания SQL запросов

Строки - конкатенация

  • Строки могут быть сконкатенированы при помощи оператора “.”, при этом должен присутствовать пробел перед и после оператора
  • Для более удобного восприятия длинные строки можно разбивать на несколько, при этом оператор конкатенации ставится в начале строки, на уровне знака присваивания:

$sql = “SELECT `id`, `name` FROM `people` “
     . “WHERE `name` = ‘Inga’ “
     . “ORDER BY `name` ASC”;

Массивы с цифровыми индексами

  • Отрицательные значения не разрешены для использования в качестве индексов
  • Могут начинаться с положительного индекса (больше нуля), но такое не одобряется. Лучше использовать 0 для начала индекса массива
  • Для массивов, которые определяются при помощи функции array в несколько строк каждая следующая строка должна начинаться на уровне первого заданного значения в массиве

Ассоциативные массивы

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

$sampleArray = array(‘firstKey’  => ‘firstValue’,
                     ’secondKey’ => ’secondValue’);

Обявление класса

  • Открывающая фигурная скобка ставится на следующей строке после имени класса (”one true brace” форма)
  • Код класса должен иметь отступ в 4 пробела, без табуляций (зачем это снова напоминать? :)
  • В одном файле - только один класс, не больше
  • Добавление дополнительного кода в файл класса не рекомендуется. Если же данная ситуация имеет место, то класс и дополнительный код разделяются двумя пустыми строками

Свойства класса

  • Именование свойств класса аналогично именованию обычных переменных (см. выше)
  • Свойства класса определяются в самом верху тела класса (до методов)
  • Объявление свойств класса осуществляется при помощи спецификаторов доступа private, protected или public (старая конструкция var запрещена)
  • Доступ к свойствам класса на прямую, указав для них спецификатор public не одобряется. Пользуйтесь методами аксессорами (get/set)

Методы класса

  • Именование методов аналогично правилам для функций
  • Методы объявляются при помощи спецификаторов доступа private, protected или public
  • Открывающая фигурная скобка пишется с новой строки, после имени метода. Между именем функции и открывающей круглой скобкой никаких пробелов
  • Функции в глобальной области видимости сильно не одобряются
  • Передача по ссылке разрешена только в объявлении функции
  • Аргументы, которые передаются в функцию разделяются запятыми с пробелом

Операторы управления - if/else

  • Управляющие операторы if/else должны иметь пробел перед открывающей круглой скобкой (условие), а также пробел после закрывающей круглой скобки
  • Для условия внутри скобок операторы отделяются пробелами. Использование круглых скобок для группировки множественных условий одобряется
  • Открывающая фигурная скобка пишется на строке, где написано условие. Закрывающая фигурная скобка пишется на отдельной строке. Код внутри фигурных скобок имеет отступ в 4 пробела (а они опять о том же :)

if ($someValue > 0) {
    $checked = true;
} else {
    $newValue = 7;
}

Switch

  • Также как и для if - пробелы вокруг круглых скобок
  • Все операторы switch должны иметь default case

switch ($key) {
    case KEY_UP:
        $obj->moveUp();
        break;
    case KEY_DOWN:
        $obj->moveDown();
        break;
    default:
}

Внутритекстовая документация - формат документации

  • Все блоки документации (”docblocks”) должны быть совместимы с форматом phpDocumentor
  • Все файлы с исходным кодом, написанные для Zend Framework, или которые взаимодействуют с фреймворком, должны содержать блок документации уровня файла (”file-level” docblock) в верхней части каждого файла. А также блок документации уровня класса(”class-level” docblock)

Внутритекстовая документация - файлы

  • Каждый файл, содержащий PHP код должен иметь блок документации в формате phpDocumentor. Минимальный блок должен содержать следующее:
/**
 * Краткое описание для файла
 *
 * Длинное описание для файла (если есть)...
 *
 * LICENSE: информация о лицензии
 *
 * @copyright 2009 Zend Technologies
 * @license    http://www.zend.com/license/3_0.txt    PHP License 3.0
 * @version    $Id:$
 * @link         http://dev.zend.com/package/PackageName
 * @since      File available since Release 1.2.0
 *
 */

Внутритекстовая документация - классы

  • Правила как и для файлов. Минимальный набор phpDocumentor тегов: Descriptions, @copyright, @license, @version, @link, @since, @deprecated

Внутритекстовая документация - функции

  • Каждая функция и методы объектов должны иметь блок документации. Он должен содержать описание функции, все аргументы и все возможные возвращаемые значения
  • Не обязательно использовать “@access” тег
  • Для функций и методов, которые могут выбрасывать исключения лучше использовать @throws тег

« Previous Entries