Короткий огляд генерації коду в Magento 2

З появою Magento 2 багато питань вимагають пояснення. Сьогодні черга дійшла до розбору процесу генерації коду в системі, як однієї з нових ключових концепцій в Magento 2. Вас коли-небудь хвилювало питання, коли і чому створюється код в папці var/generation і який процес за це відповідає? Якщо це так, тоді ця стаття для вас.

 

 

Генерація коду – короткий огляд

Генерація коду може бути викликана двома способами:

  • На льоту. Ви повідомляєте клас із зрозумілим ім’ям, яке слідує певному патерну. Коли система намагається автозавантажити клас і не знаходить його, цей клас буде згенеровано. Це дуже корисно в режимі розробки, оскільки система робить все сама, вам не потрібно запускати в консолі команду генерації знову і знову. Однак це уповільнює роботу системи.
  • Командний рядок. Коли ви запускаєте генерацію коду з командного рядка, система перевірить код і згенерує всі необхідні класи. Даний спосіб корисний для сайту он-лайн, оскільки він не навантажує систему.

 

Для другого способу вам потрібно запускати команду:

magento setup:di:compile  

 

щоб створити необхідні файли. Обидва варіанти ведуть до створення класів в папці var/generation.

 

 

Які класи генеруються?

Існує кілька типів класів, які генеруються системою. Ми зупинимося на 3-х найважливіших:

  • Фабричні
  • Проксі
  • Плагіни

 

А тепер давайте по порядку.

 

Фабричні

Фабричні класи використовуються для створення об’єктів, які не можуть бути вставлені автоматично. Наприклад, об’єкт товару повинен бути завантажений з бази даних, але для контейнера ін’єкції залежностей недостатньо інформації для створення цього об’єкта. Ось чому використовуються фабрики.



 

Давайте подивимося на існуючий клас в app/code/Magento/Catalog/Model/Product/Copier.php

 

/**  * @param CopyConstructorInterface $copyConstructor  * @param \Magento\Catalog\Model\ProductFactory $productFactory  */  public function __construct(    CopyConstructorInterface $copyConstructor,    \Magento\Catalog\Model\ProductFactory $productFactory  ) {    $this->productFactory = $productFactory;    $this->copyConstructor = $copyConstructor;  }  

 

Пояснення робочого процесу:

  • Розробник оголошує залежність від фабрики в конструкторі ($productFactory)
  • Менеджер об’єктів вводить цю залежність
  • Розробник може отримати доступ до методу create() (єдиному методу на фабричному об’єкті) для створення якомога більшої кількості екземплярів Product.

 

 

Ось як ви, як розробник, можете використовувати фабрики. У фоновому режимі система згенерує файл, розташований в /var/generation/Magento/Catalog/Model/ProductFactory.php, який виглядає так (спрощено):

<?php  namespace Magento\Catalog\Model;    class ProductFactory  {   public function __construct(    \Magento\Framework\ObjectManagerInterface $objectManager, $instanceName = '\\Magento\\Catalog\\Model\\Product'   )   {    $this->_objectManager = $objectManager;    $this->_instanceName = $instanceName;   }     public function create(array $data = array())   {    return $this->_objectManager->create($this->_instanceName, $data);   }  }  

 

Як ми бачимо, єдиною метою фабричних класів є делегування інстанціювання об’єктів об’єктним менеджерам.

 

 

Проксі

Magento 2 використовує конструктор ін’єкцій, в якому вказуються всі необхідні залежності. Ви не можете створювати об’єкти без оголошення всіх залежностей. Що робити, якщо ви хочете мати додаткові залежності? Для цього існують проксі.

 

<config>   <type name="Magento\Catalog\Model\Resource\Product\Collection">    <arguments>     <argument name="customerSession" xsi:type="object">       Magento\Customer\Model\Session\Proxy     </argument>    </arguments>   </type>  </config>  

 

 

Пояснення робочого процесу:

  • Розробник ніколи не чіпає PHP файли для використання проксі, він використовує тільки файл di.xml
  • Зверніть увагу на ключове слово Proxy, додане в Magento\Customer\Model\Session\. Залежності, відмічені таким чином, є необов’язковими залежностями.

 

 

У фоновому режимі система згенерує файл, розташований в /var/generation/Magento/Customer/Model/Session/Proxy.php, який виглядає так (спрощено):

 

<?php  namespace Magento\Customer\Model\Session;    class Proxy extends \Magento\Customer\Model\Session  {   protected function _getSubject()   {    if (!$this->_subject) {     $this->_subject = true === $this->_isShared     ? $this->_objectManager->get($this->_instanceName)     : $this->_objectManager->create($this->_instanceName);    }    return $this->_subject;   }   ...  }  

 

 

Як ми бачимо, це розширює вихідний клас і перевизначає кожен метод, який делегує виклик до вихідного зразка. Це означає, що при першому виклику проксі методу вихідний екземпляр створюється з усіма його залежностями. Тому єдиною метою проксі є відтермінування створення екземпляра (і його залежностей) до самого першого використання.

 

 

Плагіни (перехоплювачі)

Простіше кажучи, плагіни є основними механізмами кастомізації Magento 2. Більше не потрібно перезаписувати клас. Плагін дозволяє вам підключатися і робити щось до, після або навколо будь-якого public методу додатка.

Давайте подивимося на системний плагін:

 

<?php  namespace Magento\Store\App\Action\Plugin;    class StoreCheck  {   public function aroundDispatch(    \Magento\Framework\App\Action\Action $subject,    \Closure $proceed,    \Magento\Framework\App\RequestInterface $request   ) {    if (!$this->_storeManager->getStore()->getIsActive()) {     throw new \Magento\Framework\Exception\State\InitException(     __('Current store is not active.')    );    }    return $proceed($request);   }  }  

 

 

Пояснення робочого процесу:

  • Розробник пише клас плагіна в залежності від вимог (ознайомтеся з офіційною документацією)
  • Розробник реєструє плагін в файлі di.xml, наприклад, так:

 

<config>   <type name="Magento\Framework\App\Action\Action">    <plugin name="storeCheck"     type="Magento\Store\App\Action\Plugin\StoreCheck"     sortOrder="10"/>   </type>  </config>  

 

 

В результаті система згенерує клас Interceptor в /var/generation/Magento/Framework/App/Action/Interceptor.php

 

<?php  namespace Magento\Framework\App\Action\Action;    class Interceptor extends \Magento\Framework\App\Action\Action  {   public function dispatch(\Magento\Framework\App\RequestInterface $request)   {    $pluginInfo = $this->pluginList->getNext('\\Magento\\Framework\\App\\Action\\Action', 'dispatch');    if(!$pluginInfo) {     return parent::dispatch($request);    } else {     return $this->__callPlugins('dispatch', func_get_args(), $pluginInfo);    }   }  }  

 

 

На відміну від проксі, на цей раз інструмент генерації буде генерувати тільки ті методи, які ви хочете переписати.

 

 

Ось і все на сьогодні. Пишіть свої коментарі в формі коментування нижче.