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

Last modified by Rystam on Sun, January 22, 2012 23:40
Source|Old Revisions  

ПРОЛОГ

Это всего лишь перевод статьи из серии статей Элана Сторма http://www.magentocommerce.com/knowledge-base/entry/magento-for-dev-part-1-introduction-to-magento.

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

ВВЕДЕНИЕ

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

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

Это первая в серии статей, в которых мы собираемся пройти быстрый курс особенностей программирования в Magento. Не переживайте если вы не поймете все сразу.

Чем вы больше будете изучать систему тем больше в этой статье будет становится понятным и вскоре Вам будут завидовать коллеги застрявшие за работой в более примитивных PHP системах.

КОД РАЗДЕЛЕН ПО МОДУЛЯМ

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

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

Код Magento

Для примера, Вы найдете Контроллеры(Controllers), Модели(Models), Помощники(Helpers), Блоки(Blocks) и т.д. связанные функциональным назначением оформления заказа в

  app/code/core/Mage/Checkout

Вы найдете Контроллеры(Controllers), Модели(Models), Помощники(Helpers), Блоки(Blocks) и т.д. связанные функциональным назначением оформления заказа через Google в

 app/code/core/Mage/GoogleCheckout

Ваш код

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

 app/code/local/Package/Modulename

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

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

 app/etc/modules

В этой папке есть два вида файлов, первый вид активизирует конкретный модуль и называется по формуле: Packagename_Modulename.xml

Второй вид это файл, который активирует множество Модулей из папки Package/Namespace, и называется по формуле: Packagename_All.xml

MVC ОСНОВАННЫЙ НА КОНФИГУРАЦИИ

Magento это система MVC основанная на конфигурации. Альтернатива этому система MVC основанная на соглашениях.

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

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

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

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

  1.    <models>
  2.      <packagename>
  3.           <class>Packagename_Modulename_Model</class>
  4.     <packagename>
  5.    </models>

Тоже самое делается с Помощниками, Блоками, Маршруты для Ваших Контроллеров, Обработчиков Событий и много другого. Едва ли не всегда, когда Вы хотите изменить функционал Magento, Вам необходимо сделать несколько изменений или добавлений в файле конфигурации.

КОНТРОЛЛЕРЫ

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

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

  1. Изучает URL
  2. Основываясь на каком-то наборе правил, направляет этот URL в класс Контроллера и метод Действия (называется маршрутизацией)
  3. Создает класс Контролера и вызывает метод Действия (называется диспетчеризация)

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

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

Каждая составляющая пути после имени сервера разбирается, как объяснено ниже.

Front name - catalog

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

 app/code/core/Mage/Catalog

Controller Name - category

Вторая часть URL говорит Magento какой Контроллер следует использовать. Каждый Модуль с Контроллерами имеет определенную папку называемую ‘controllers’ в которой содержаться все контроллеры для модуля.

В примере выше часть category из URL преобразуется в файл Контроллера

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

Который выглядит так:

  1.    class Mage_Catalog_CategoryController extends Mage_Core_Controller_Front_Action
  2.   {
  3.   }

Все Контроллеры в Magento наследуются от Mage_Core_Controller_Front_Action.

Action Name - view

Третье в нашем URL это action name. В нашем примере это “view”. Слово “view” используется при создании метода Действия. Так что в нашем примере “view” будет преобразован в “viewAction”

  1.    class Mage_Catalog_CategoryController extends Mage_Core_Controller_Front_Action
  2.    {
  3.        public function viewAction()
  4.        {
  5.            //main entry point
  6.        }
  7.    }

Люди хорошо знакомые с Zend Framework узнают в этом соглашение об именовании.

Paramater/Value - id/25

Остальные части после action name будут рассматриваться как ключ/значение переменных GET запроса. Так что в нашем примере “id/25” означает, что будет получена GET переменная “id” со значением “25”.

Как ранее было замечено, если Вы хотите чтобы ваш Модуль использовал Контроллеры, вам необходимо сконфигурировать его.

Ниже представлена конфигурационная цепочка которая активизирует Контроллеры для модуля Catalog

  1.    <frontend>
  2.     <routers>
  3.         <catalog>
  4.             <use>standard</use>
  5.             <args>
  6.                 <module>Mage_Catalog</module>
  7.                 <frontName>catalog</frontName>
  8.             </args>
  9.         </catalog>
  10.     </routers>
  11.    </frontend>

Не беспокойтесь слишком много о специфики на данном этапе, а обратите внимание на <frontName>catalog</frontName>.

Это то, что связывает Модуль с Front Name в URL. Для большинства базовых Модулей в Magento выбрано Front Name таким же как название Модуля, но это не обязательно.

Несколько маршрутизаторов

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

Если Magento не удается найти подходящий Административный Контроллер/Действие, она использует специальный Контроллер называемый Mage_Cms_IndexController.

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

Например, основная “index” страница magento, которая использует CMS Контроллер, новичками частенько бывает зациклена.

КОНТЕКСТНО-ОРИЕНТИРОВАННАЯ ЗАГРУЗКА МОДЕЛИ

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

Magento предлагает специальный способ для создания Моделей, Помощников и Блоков используя статичные встроенные в глобальный класс Mage методы. Например:

  1.    Mage::getModel('catalog/product');
  2.    Mage::helper('catalog/product');

Строка catalog/product называется Групповым Именем класса. Это так же часто называют URI.

Первая часть любого Группового Имени Класса (в нашем случае catalog), используется чтобы выяснить какой класс присущ модулю.

Вторая часть (product) используется для определения какой класс следует загрузить.

Так что в обоих примерах выше above, catalog сообщает что Модуль будет app/code/core/Mage/Catalog.

Это значит что наш класс будет начинаться с Mage_Catalog. Когда же добавим ‘product’ то получим окончательное имя класса

  1.     Mage::getModel('catalog/product');
  2.     Mage_Catalog_Model_Product
  3.    
  4.     Mage::helper('catalog/product');
  5.     Mage_Catalog_Helper_Product

Эти правила обязаны установкам в каждом конфигурационном файле Модуля.

Когда Вы создаете собственный пользовательский Модуль, Вы имеете свое Групповое Имя Класса для работы с Mage::getModel(’myspecialprefix/modelname’);.

Вам нет необходимости использовать Групповое Имя класса для создания своих классов. Однако, как мы узнаем позже есть конкретные преимущества чтобы поступать так.

МОДЕЛИ В MAGENTO

Magento, как большинство фреймворков в наши дни, предлагают систему Объектно-реляционных Сопоставлений (ORM).

ORMs выводит вас из написание SQL логики и позволяет манипулировать хранилищем данных исключительно через PHP код. Например:

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

В примере выше мы вызываем методы “getPrice” и “setPrice”. Однако класс Mage_Catalog_Model_Product не имеет методов с такими именами.

Все это потому что That’s because ORM в Magento использует волшебные методы _get and _set из PHP.

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

Если Вы хотите получить все доступные данные из Модели, вызовите $product→getData(); будет получен массив со всеми атрибутами.

Так же Вы заметили, что возможно сделать цепочку из вызовов нескольких методов set:$model→setPrice($price)→setSku(’SK83293432’);

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

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

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

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

  1.   foreach($products_collection as $product)
  2.   {
  3.      echo $product->getName();
  4.   }

Вы можите задаться вопросом для чего “addAttributeToSelect” метод. В Magento имеется две основных объектных модели. Одна традиционная “Один Объект – Одна Таблица” Активная Модель стиля Записи. Когда вы создаете такие Модели все атрибуты автоматически помечаются.

Второй тип Модели это Объект Атрибут Значение (EAV) Модель. EAV Модели распределяют данные в нескольких раздельных таблицах в базе данных.

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

Когда создается коллекция EAV объектов, Magento консервативен в числе столбцов которые будут запрошены, поэтому Вы можете addAttributeToSelect чтобы получить столбцы нужные Вам или addAttributeToSelect(’*’) чтобы получить все столбцы.

ПОМОЩНИКИ

Классы пощников в Magento содержат полезные методы которые помогают Вам выполнять общие задачи для объектов и переменных. Например:

  1. $helper = Mage::helper('catalog');

Вы заметили что мы отбросили вторую часть Группового Имени Класса. Каждый модуль имеет класс Data Helper по умолчанию. Следующая запись равнозначна предыдущей:

  1. $helper = Mage::helper('catalog/data');

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

  1.   $translated_output$helper->__('Magento is Great'); //gettext style translations
  2.   if($helper->isModuleOutputEnabled()): //is output for this module on or off?

МАКЕТЫ

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

  1. Задали бы несколько переменных для нашей витрины
  2. Система бы загрузила по умолчанию “внешний” HTML макет
  3. Затем система загрузила бы нашу витрину внутрь этого внешнего макета

Однако, если Вы посмотрите на типичное действие в Контроллере Magento, Вы ничего такого не увидите:

  1.   /**
  2.   * View product gallery action
  3.   */
  4.   public function galleryAction()
  5.   {
  6.     if (!$this->_initProduct()) {
  7.         if (isset($_GET['store']) &amp;&amp; !$this->getResponse()->isRedirect()) {
  8.             $this->_redirect('');
  9.         } elseif (!$this->getResponse()->isRedirect()) {
  10.             $this->_forward('noRoute');
  11.         }
  12.         return;
  13.     }
  14.     $this->loadLayout();
  15.     $this->renderLayout();
  16.   }

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

  1.   $this->loadLayout();
  2.   $this->renderLayout();

Итак “V” в MVC от Magento отличается возможно от того что вы использовали, в том что Вы должны явно начать рендеринг макета. Макет сам по себе отличается.

В Magento Макет это объект который содержит вложенную/древовидную коллекцию “Block” объектов. Каждый объект Блока будет представлять маленький специфичный HTML.

Объекты Блоков создаются из комбинации PHP кода, и внедрения PHP шаблонов из .phtml файлов.

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

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

  1.   $this->loadLayout();
  2.   $this->renderLayout();

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

Вдобавок там будет несколько Блоков Контента для навигации, сообщения приветствия по умолчанию и т.д.

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

Чтобы добавить Контент в Макет Вам необходимо сообщить Magento что-то типа этого

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

или

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

Это может быть сделано программно в Контроллере действия

  1.   public function indexAction()
  2.   {
  3.       $block = $this->getLayout()->createBlock('adminhtml/system_account_edit')
  4.       $this->getLayout()->getBlock('content')->append($block);
  5.   }

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

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

Например, рассмотрим этот XML файл Макета:

  1.   <catalog_category_default>
  2.     <reference name="left">
  3.         <block type="catalog/navigation" name="catalog.leftnav" after="currency" template="catalog/navigation/left.phtml"/>
  4.     </reference>
  5.   </catalog_category_default>

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

Еще одна важная вещь о Блоках. Часто вы можете видеть код в шаблонах похожий на:

  1. $this->getChildHtml('order_items')

Это так Блок выводит вложенный Блок. Однако, Блок может выводить только Блок потомок, если Блок потомок включен как вложенный Блок в XML файле Макета.

В примере выше наш Блок ‘catalog/navigation’ не имеет вложенных Блоков. Это значит что любой вызов $this→getChildHtml() в left.phtml будет выведен как пустота.

Если мы будем иметь что-то типа этого:

  1.   <catalog_category_default>
  2.     <reference name="left">
  3.         <block type="catalog/navigation" name="catalog.leftnav" after="currency" template="catalog/navigation/left.phtml">
  4.             <block type="core/template" name="foobar" template="foo/baz/bar.phtml"
  5.         </block>
  6.     </reference>   
  7.   </catalog_category_default>

Из Блока ‘catalog/navigation’, мы сможем вызвать $this→getChildHtml(’foobar’);

ОБОЗРЕВАТЕЛИ

Как любая хорошая объектно-ориентированная система, Magento реализует модель Событие/Обозреватель для конечных пользователей.

Как только некоторое действие происходит во время запроса Страницы (сохранение Модели, пользователь авторизуется и т.д.), Magento производит сигнал о событии.

При создании Ваших собственных Модулей, Вы можете “слушать” эти события. Скажем Вы хотите получать email каждый раз когда конкретный пользователь авторизуется в магазине.

Вам следует слушать “customer_login” событие (установленное в config.xml)

  1.   <events>
  2.     <customer_login>
  3.         <observers>
  4.             <unique_name>
  5.                 <type>singleton</type>
  6.                 <class>mymodule/observer</class>
  7.                 <method>iSpyWithMyLittleEye</method>
  8.             </unique_name>
  9.         </observers>
  10.     </customer_login>
  11.   </events>

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

  1.   class Packagename_Mymodule_Model_Observer
  2.   {
  3.       public function iSpyWithMyLittleEye($observer)
  4.       {
  5.           $data = $observer->getData();
  6.           //code to check observer data for out user,
  7.           //and take some action goes here
  8.       }
  9.   }

ПЕРЕОПРЕДЕЛЕНИЕ КЛАССОВ

Наконец, Magento предлагает Вам возможность заменять классы Моделей, Помощников и Блоков из базовых модулей своими собственными.

Эта особенность похожа на “Duck Typing” или “Monkey Patching” в таких языках как Ruby или Python.

Этот пример будет полезен для понимания. Класс Модели для продукта это Mage_Catalog_Model_Product.

Всякий раз когда следующий код вызывается объект Mage_Catalog_Model_Product создается

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

Это “заводской” образец. То, что делает система переопределения класса в Magento, позволяют Вам говорить систему

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

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

  1.   class Packagename_Modulename_Model_Foobazproduct extends Mage_Catalog_Model_Product
  2.   {
  3.   }

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

  1.   class Packagename_Modulename_Model_Foobazproduct extends Mage_Catalog_Model_Product
  2.   {
  3.       public function validate()
  4.       {
  5.           //add custom validation functionality here
  6.           return $this;
  7.       }
  8.   }

Как Вы и могли ожидать это переопределение делается в файле config.xml.

  1.   <models>
  2.     <!-- tells the system this module has models -->
  3.     <modulename>
  4.         <class>Packagename_Modulename_Model</class>
  5.     </modulename>
  6.     <!-- does the override for catalog/product-->
  7.     <catalog> 
  8.         <rewrite>
  9.             <product>Packagename_Modulename_Model_Foobazproduct</product>
  10.         </rewrite>
  11.     </catalog>         
  12.   </models>

Одна вещь, которую важно отметить. Конкретные классы в Вашем Модуле переопределяют конкретные классы в других Модулях.

Тем не менее вы не переопределяете весь Модуль. Это позволяет Вам изменять поведение специфических методов, не переживая что о том что делает остальная часть Модуля.

ЗАКЛЮЧЕНИЕ

Мы надеемся что этот беглый обзор по некоторым возможностям которые система электронной коммерции Magento предлагает разработчикам был полезным.

Может быть это немного ошеломительно для начала, особенно, если это Ваш первый опыт использования современной объектно-ориентированной PHP системы.

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

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




 

Magento 2 GitHub Repository

Magento Job Board - Some sort of tag line goes here

Latest Posts| View all Jobs