Короткий огляд генерації коду в 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); } } }
На відміну від проксі, на цей раз інструмент генерації буде генерувати тільки ті методи, які ви хочете переписати.
Ось і все на сьогодні. Пишіть свої коментарі в формі коментування нижче.