Magento для Разработчиков: Часть 1 - Введение в Magento

Что такое Magento? Это самая мощная онлайн платформа для электронной коммерции в этом мире, изменившая лицо коммерции навсегда!

Конечно вы уже знаете это раз читаете эту статью. Наверно вы даже не догадываетесь что Magento также является PHP объектно-ориентированным Фрэимворком, который может быть использован для создания современных и мощных онлайн веб-приложений на базе Magento.

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

Обзор статьи.

Организация Кода в Модулях

Magento организует свой код в индивидуальных Модулях. В типичном Модель-Вид-Контроллер ( MVC ) приложении, все Контроллеры лежат в одной папке, все Модели в другой и т.д. В Magento, файлы сгруппированы вместе по своей функциональности, называемые Модулями в Magento.

Код Magento

Для примера, вы сможете найти Контроллеры, Модели, Помощники, Блоки и т.д относящиеся к функциям Checkout в Magento в

app/code/core/Mage/Checkout

Также вы сможете найти Контроллеры, Модели, Помощники, Блоки и т.д относящиеся к функциям Google Checkout в Magento в

app/code/core/Mage/GoogleCheckout
Ваш Код

Когда вам нужно изменить или расширить Magento, вместо того чтобы редактировать файлы ядра напрямую, или располагать ваш новый Контроллер, Модель, Помощник, Блок и т.д. вместе с кодом Magento, вы можете просто создать свой Модуль в

app/code/local/Package/ИмяМодуля

Пакеты ( также часто называемые Пространством Имён ) это уникальное имя, которое, идентифицирует вашу компанию или организацию. Цель в том чтобы каждый пользователь всемирного сообщества Magento использовал имя своего Пакета при создании новых модулей, чтобы избежать проблем с кодом от других разработчиков.

Когда вы создаёте новый Модуль, вам нужно сказать о нём Magento. Это делается созданием XML файла в папке:

app/etc/modules

Существует два вида файлов в этой папке, первый включает индивидуальный Модуль, и именуется в форме:ИмяПакета_ИмяМодуля.xml

Второй файл включает множество Модулей из Пакета/Пространства Имён, и именуется в форме: ИмяПакета_All.xml

Базированный на Конфигурации MVC

Базированная на Конфигурации MVC Magento система. Альтернативой для неё будет Конвенционно-Базированая MVC система.

В конвенционно-базированой MVC системе, если вы хотите добавить, скажем, новый Контроллер или может быть новую Модель, вам просто нужно создать файл/класс, и система подхватит его автоматически.

В базированный на конфигурации системе, как Magento, кроме добавления нового файла/класса в кодовую базу, вам также нужно будет явно сказать системе о новом классе, или новой группе классов. В Magento, каждый Модуль имеет файл называющийся config.xml. Этот файл содержит всю конфигурацию соответствующую Модулю Magento. При запуске, все эти файлы будут загружены в одно большое конфигурационное дерево.

Для примера, нам нужно использовать Модели в нашем Модуле? Вам нужно добавить немного кода в config.xml который скажет Magento что вы хотите использовать Модели, а также какое базовое имя класса должно быть для всех ваших Моделей.

<models>
     <packagename>
          <class>Packagename_Modulename_Model</class>
    </packagename>
</models>

Это также относится к Помощникам, Блокам, Маршрутизации для ваших Контроллеров, Обработчиков Событий, и многое другое. Почти всегда, если вы захотите подключиться к мощностям системы Magento, вам нужно будет сделать некоторые изменения или дополнения в вашем файле конфигурации ( config.xml ).

Контроллеры

В любой PHP системе, главной точкой входа является PHP файл. Magento не является исключением, это фаил index.php.

Однако, вы никогда не будете писать код в index.php. В системе MVC, index.php будет содержать код / вызовы, которые делают следующее:

  1. Распознать URL
  2. По некоторым набором правил, превратить этот URL в класс контроллера и метод действия (так называемая Маршрутизация (Routing))
  3. Создать экземпляр класса контроллера и вызвать метод действия (так называемая диспетчеризация)

Это значит, что практической точкой входа в Magento ( или любую MVC систему ) является метод действия в файле Контроллера. Рассмотрим следующий URL:

http://example.com/catalog/category/view/id/25

Каждая часть пути после имени сервера обрабатывается следующим образом.

Front Name - catalog

Первая часть URL называется Front Name. Это, более или менее, говорит Magento, в каком Модуле можно найти Контроллер. В примере выше, Front Name это каталог, который соответствует Модулю расположенному в:

app/code/core/Mage/Catalog

Имя Контроллера - category

Вторая часть URL говорит Magento, какой Контроллер следует использовать. Каждая папка Модуля с Контроллерами имеет специальную директорию называемую 'controllers', которая содержит все Контроллеры для модуля. В примере выше, часть category в URL трансформируется в фаил Контроллера

app/code/core/Mage/Catalog/controllers/CategoryController.php

Который выглядит примерно так

class Mage_Catalog_CategoryController extends Mage_Core_Controller_Front_Action
{
}

Все Контроллеры в приложении корзины в Magento наследуются от Mage_Core_Controller_Front_Action.

Имя Действия - view

Третьей частью в нашем URL является имя действия. В нашем примере это "view". Слово "view" используется для создания Метода Действия. Так, в нашем примере, "view" будет превращен в "viewAction"

class Mage_Catalog_CategoryController extends Mage_Core_Controller_Front_Action
{
    public function viewAction()
    {
        //главная точка входа
    }
}

Люди знакомые с Zend Framework распознают эту конвенцию именования.

Параметр/Значение - id/25

Любая часть пути после имени действия будет рассматриваться как пара ключ/значение GET запроса. Итак, в нашем примере, "id/25" значит что мы получаем GET переменную "id", со значением "25".

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

<frontend>
    <routers>
        <catalog>
            <use>standard</use>
            <args>
                <module>Mage_Catalog</module>
                <frontName>catalog</frontName>
            </args>
        </catalog>
    </routers>
</frontend>

Не беспокойтесь о спецификации сейчас, но обратите внимание на catalog

Это то, что связывает модуль с frontname (лицевой стороной) URL. Большинство модулей Magento выбирают frontname таким же как и имя Модуля, но это не обязательно.

Множественная Маршрутизация

Маршрутизация описанная выше в приложении корзины Magento ( часто называемой лицевой стороной ). Если Magento не найдёт подходящего Контроллера/Действия для URL, он будет пробывать снова, на этот раз используя правила Маршрутизации для Административной секции ( Админки ). Если и там Magento не найдёт подходящего Контроллера/Действия, будет использован специальный Контроллер называемый Mage_Cms_IndexController.

CMS Контроллер проверит Систему Управления Контентом Magento, на предмет содержания какого либо материала для загрузки. Если ничего не будет найдено, то пользователю будет показана 404 Ошибка.

Для примера, главная "index" страница Magento, использующая CMS Контроллер, может вводить новых посетителей в цикл.

Загрузка Модели по Контекстно-базированному URI

Теперь, когда мы во входной точке нашего Действия, мы хотим начать с инстанцирования экземпляров классов, для проделывания некоторых вещей. Magento предлагает создавать экземпляры моделей, помощников и блоки специальным образом, используя методы статической фабрики в глобальном классе Mage. Для примера:

Mage::getModel('catalog/product');
Mage::helper('catalog/product');

Строка 'catalog/product' вызывает Группированное Имя Класса. Это также часто называют URI. Первая часть для любого Сгруппированного Имени Класса ( в данном случае, catalog ), используется для поиска в каком Модуле находится искомый класс. Вторая часть ( 'product' см. выше ) используется для определения какой класс будет загружен.

Таким образом, в обоих приведенных выше примерах 'catalog' определяет Модуль app/code/core/Mage/Catalog

Это означает, что наш класс будет называться Mage_Catalog

Затем, будет добавлен product для поиска окончательного класса.

Mage::getModel('catalog/product');
Mage_Catalog_Model_Product

Mage::helper('catalog/product');
Mage_Catalog_Helper_Product

Эти правила связаны с тем что мы определяем в каждом файле конфигурации отдельного Модуля. Когда вы создаёте свой Модуль, у вас будут свои сгруппированные имена классов для работы с Mage::getModel('myspecialcodefix/modelname'); Вы не должны использовать Группированные Имена Классов для инстанцирования ваших классов. Однако, как мы узнаем позже, в этом есть некоторые преимущества.

Модели в Magento

Magento как и большинство современных фрэймворков нашего времени, предлагает систему Объектно Реляционной Модели (ORM) . ORM избавят вас от написания SQL кода и позволит управлять данными на уровне PHP. Например:

$model = Mage::getModel('catalog/product')->load(27);
$price = $model->getPrice();
$price += 5;
$model->setPrice($price)->setSku('SK83293432');
$model->save();

В приведённом выше примере мы вызываем методы "getPrice" и "setPrice" в нашем Продукте. Однако, класс Mage_Catalog_Model_Product не имеет методов с этими именами. Это потому, что ORM Magento использует магические методы _get и _set в PHP.

Вызов метода $product->getPrice(); "получит" атрибут модели "price".

Вызов $product->setPrice(); "присвоит" атрибуту Модели "price". Всё это означает что класс Модели пока не имеет методов getPrice или setPrice. Если это не так, то магические методы будут пропущены. Если вы заинтересованы в реализации этого поведения, загляните в класс Varien_Object, от которого наследуются все Модели.

Если вы хотите получить все имеющиеся данные в модели, вызовите метод $product->getData();, чтобы получить массив всех доступных атрибутов.

Заметьте, что также возможен вывод методов модели друг за другом ( сцепка ):
$model->setPrice($price)->setSku('SK83293432');

Это возможно благодаря тому что каждый "set" метод возвращает экземпляр Модели. Этот паттерн, как вы скоро увидите, используется в большей части кода Magento.

ORM Magento также позволяет делать выборку данных из разных Объектов через интерфейс Коллекций. Следующий пример вернёт нам коллекцию всех продуктов, которые стоят $ 5,00

$products_collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addFieldToFilter('price','5.00');

Как вы уже заметили, Magento и здесь использует интерфейс сцепки. Коллекции используют стандартную библиотеку PHP для реализации Объектов имеющих свойства массива.

foreach($products_collection as $product) {
    echo $product->getName();
}

Вы можете быть удивлены, что за метод "addAttributeToSelect" ? Magento имеет два типа объектов Модели. Первый это традиционно "Один Объект, Одна Таблица", в стиле Active Record. При создании экземпляра модели, все атрибуты выбираются автоматически.

Второй тип модели это Сущность Атрибут Значение (EAV) модель. EAV модели распределяют данные между несколькими таблицами в базе данных. Это даёт Magento гибкий способ сделать гибкой систему атрибутов продукта без необходимости делать изменения схемы каждый раз при добавлении нового атрибута. При создании коллекции EAV объектов, Magento консервативно относится к числу столбцов из которых будет производиться выборка, поэтому вы можете использовать addAttributeToSelect, для выборки того что вам нужно, или addAttributeToSelect('*') для выборки всех столбцов.

Помощники

Классы помощников в Magento содержат методы, которые позволят вам выполнять обыденные задачи над объектами и переменными. Например:
$helper = Mage::helper('catalog');

Как вы наверное заметили, вторая часть группы названия класса отсутствует. Каждый Модуль имеет стандартный Data Helper класс. Написанное выше эквивалентно следующему:
$helper = Mage::helper('catalog/data');

Большинство Помощников отнаследованы от Mage_Core_Helper_Abstract, который дает вам несколько полезных методов по умолчанию.

$translated_output =  $helper->__('Magento is Great'); //перевод в стиле gettext
if($helper->isModuleOutputEnabled()): //включен или выключен вывод контента модулем ?

Макеты

Итак, мы видели, Контроллеры, Модели и Помощников. В типичной PHP MVC системе, после манипуляций с нашей Моделью мы

  1. Установим несколько переменных для нашего Представления
  2. Система будет загружать стандартный "внешний" HTML шаблон
  3. Затем система будет загружать наше представление, во внешний шаблон

Однако, если взглянуть на типичное действие в Контроллере Magento, вы не увидите этого:

 
/**
 * View product gallery action
 */

public function galleryAction()
{
    if (!$this->_initProduct()) {
        if (isset($_GET['store']) &amp;&amp; !$this->getResponse()->isRedirect()) {
            $this->_redirect('');
        } elseif (!$this->getResponse()->isRedirect()) {
            $this->_forward('noRoute');
        }
        return;
    }
    $this->loadLayout();
    $this->renderLayout();
}

Вместо этого, действие Контроллера оканчивается двумя вызовами

$this->loadLayout();
$this->renderLayout();

Итак, часть "V" в MVC системе Magento уже отличается от той, которую вы вероятно использовали ранее ( в Zend Framework ), тем что, вы должны явно вызывать рендеринг макета.

Также, сам макет тоже отличается. Макет Magento является объектом, который содержит вложенные/древовидные коллекции "Block"(Блок) объектов. Каждый Блок объект отображает свою часть HTML верстки. Объект Блока делает это через комбинацию PHP кода, и подключение .phtml файлов шаблонов.

Объект Блока предназначен для взаимодействия с системой Magento, для получения данных из Моделей, в то время как .phtml файлы шаблонов предоставляют нужный для страницы HTML.

Для примера, Блок заголовка страницы app/code/core/Mage/Page/Block/Html/Head.php использует head.phtml файл page/html/head.phtml

Если думать по другому, то Блок можно представить как маленький мини-контроллер, и .phtml файлы как Представления.

По умолчанию, при вызове:

$this->loadLayout();
$this->renderLayout();

Magento будет загружать Макет с каркасом структуры сайта. Там будет Структура блоков, которая даст вам ваш html, заголовок и контент, а также HTML код для установки одиночного или много колоночного вида. Кроме этого, там будет несколько Контент Блоков для навигации, стандартное сообщение приветствия и т.д.

"Структура" и "Контент" произвольные обозначения в системе Макетов. Блок не должен программно знать Структура это или Контент, но полезно знать что Блок это либо то либо другое.

Чтобы добавить Контент в этот Макет вам нужно сказать системе Magento, что то типо:

"Эй, Magento, добавь эти дополнительные Блоки в "Контент" Блок каркаса"

или

"Эй, Magento, добавь эти дополнительные Блоки в "левую колонку" Блок каркаса"

Это можно сделать программно, в Действии Контроллера:

public function indexAction()
{
    $block = $this->getLayout()->createBlock('adminhtml/system_account_edit')
    $this->getLayout()->getBlock('content')->append($block);
}

но чаще всего ( по крайней мере в приложении корзины), используется XML система Макетов.

XML файлы Макетов в теме позволяют вам, на основе Контроллера, удалять Блоки которые обычно отображаются, или добавить Блоки в эти стандартные области каркаса макета. Например, рассмотрим этот XML файл Макета:

<catalog_category_default>
    <reference name="left">
        <block type="catalog/navigation" name="catalog.leftnav" after="currency" template="catalog/navigation/left.phtml"/>
    </reference>    
</catalog_category_default>

Это говорит нам, что в каталоге Модуля, в Контроллере category, и в стандартном Действии, вставить Блок catalog/navigation в структурный Блок "left", используя catalog/navigation/left.phtml шаблон.

Последняя важная вещь о Блоках. Вы часто будете видеть код в шаблонах который выглядит так:
$this->getChildHtml('order_items')

Это то, как Блок отображает вложенный Блок. Однако, Блок может отображать Блок потомка только, если Блок потомка включен как вложенный Блок в XML файле Макета. В примере ниже наш Блок catalog/navigation не имеет вложенных Блоков. Это означает что любой вызов $this->getChildHtml() в left.phtml отобразит пустоту.

Если, впрочем, у нас есть что то типо этого:

<catalog_category_default>
    <reference name="left">
        <block type="catalog/navigation" name="catalog.leftnav" after="currency" template="catalog/navigation/left.phtml">
            <block type="core/template" name="foobar" template="foo/baz/bar.phtml"
       </block>
    </reference>    
</catalog_category_default>

Из Блока catalog/navigation, мы можем вызвать
$this->getChildHtml('foobar');

Наблюдатели

Как любая хорошая объектно-ориентированная система, Magento реализует паттерн Событий/Наблюдателей для конечных пользователей, чтобы позволить им ставить hook'и. Для определённых действий происходящих во время формирования страницы ( Модель сохранила данные, пользователь вощел в систему и т.д), Magento будет реагировать на это.

При создании собственных модулей, вы сможете "слушать" эти события. Скажем вы хотите получать email каждый раз, когда определённые клиенты вошли в ваш магазин. Вы должны слушать "customer_login" событие ( настраивается в config.xml)

<events>
    <customer_login>
        <observers>
            <unique_name>
                <type>singleton</type>
                <class>mymodule/observer</class>
                <method>iSpyWithMyLittleEye</method>
            </unique_name>
        </observers>
    </customer_login>
</events>

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

class Packagename_Mymodule_Model_Observer
{
    public function iSpyWithMyLittleEye($observer)
    {
        $data = $observer->getData();
        //код для проверки данных наблюдателей для конечного пользователя,
        //и немного действий
    }
}

Переопределение Классов

Ну и наконец, система Magento предоставляет Вам возможность заменять классы Модели, Помощника и Блока из стандартных модулей ядра на ваши собственные. Эта возможность похожа на "Duck Typing" или "Monkey Patching" в таких языках, как Ruby или Python.

Вот пример, чтобы помочь вам понять. Класс Модели для product это Mage_Catalog_Model_Product.

Всякий раз, когда будет вызван этот код, будет создаваться объект Mage_Catalog_Model_Product.

$product = Mage::getModel('catalog/product');

Это паттерн "Фабрика"

Вот что система переопределения классов Magento делает чтобы разрешить вам сказать системе

"Эй, если кто нибудь спросит про catalog/product, вместо того чтобы отдать Mage_Catalog_Model_Product, дай ему Packagename_Modulename_Model_Foobazproduct"

Затем, если вы хотите, ваш класс Packagename_Modulename_Model_Foobazproduct может наследовать оригинальный класс продукта

class Packagename_Modulename_Model_Foobazproduct extends Mage_Catalog_Model_Product
{
}

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

class Packagename_Modulename_Model_Foobazproduct extends Mage_Catalog_Model_Product
{
    public function validate()
    {
        //добавим свой функционал валидации
        return $this;
    }

}

Как вы и ожидали, это переопределение ( или перезапись ) делается в файле config.xml.

<models>
    <!-- говорит системе что у модуля есть модели -->
    <modulename>
        <class>Packagename_Modulename_Model</class>
    </modulename>

    <!-- делает переопределение для catalog/product-->
    <catalog>  
        <rewrite>
            <product>Packagename_Modulename_Model_Foobazproduct</product>
        </rewrite>
    </catalog>          
</models>

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

Оригинал статьи на magentocommerce.com

Статья для SEO, но никак не для людей. Автору выдать почётное звание гугл-переводчика и учебник грамматики.

Может подскажете как сделать статью для людей. Просто это мой первый перевод на данную тематику =)

Вау! Значит, я не человек, а поисковый бот. ;-)
Автору респект и уважуха за проделанную работу. Конечно, заметно, что переводил не профессионал, но для понимания вполне хорош.
А Сергею хочется сказать, что вы бы не других в каментах обкакивали, а предложили бы свою помощь, если уж так руки чешутся.

попробуй сам перевести! не важно - гугл, учебник, ... важно что статья дает людям помощь. побольше таких авторов в РОССИИ!!!!! уважуха и респект автору!!!

Ник, не парься. человек завидует))

Да, статья хоть и видно что переведена кое-где корявенько, но все равно ОЧЕНЬ полезна! Спасибо!

большое спасибо было очень интересно прочитать

ещебы ссылку на оригинал

ай. просмотрел. есть ссылка.

было интересно автору распект

было интересно автору рэспект

Отправить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. If you have a Gravatar account associated with the e-mail address you provide, it will be used to display your avatar.

2012 Artkost. style personalization.