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

Короткий огляд генерації коду в 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);
  }
 }
}

 

 

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

 

 

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

 



Напишіть тут свою думку/питання

Ваша пошта не публікуватиметься. Обов’язкові поля позначені *