Ін’єкції залежностей в Magento 2 – основи їх використання

Ін’єкції залежностей в Magento 2 – основи їх використання



Однією з найбільших змін у Magento 2 (у порівнянні із версіями 1.х) є використання патерну ін’єкцій залежностей. Через цей шаблон проектування в базі коду багато чого було змінено та було введено багато нових елементів. Сьогоднішня стаття покликана пояснити початківцям саму основу цього шаблону проектування та використання ін’єкцій залежностей в Magento 2.

 

Насамперед розглянемо основну ідею використання цього патерну (шаблону проектування). Виконуючи ін’єкцію залежностей, вам потрібно запитувати залежні ресурси під час створення об’єкта, замість створення ресурсів, коли вони потрібні. Це дозволить досягти ізоляції класу і незалежної розробки, так як і простого тестування через легкість згладжування необхідних об’єктів. Перш ніж продовжувати, дозвольте продемонструвати невеличкий приклад:

 

class A
{
 ...
 public function read()
 {
  $dbh = new DatabaseConnection(); // уникайте такого
  $dbh->query('SELECT ...');
  ...
 }
 ...
}

 

Попередній приклад демонструє простий клас А з методом read(). У цьому методі нам потрібен об’єкт для з’єднання з базою даних, який створюється в першому рядку методу. Це те, до чого більшість з нас звикла, і це дещо схоже на те, що використовується в Magento 1.x (фабричний патерн). Наступний приклад реалізує ту ж саму логіку, але за патерном ін’єкції залежностей:

 

class A
{
 protected $_dbh;
 ...
 public function __construct(DatabaseConnection $connection)
 {
  $this->_dbh = $connection;
 }
 ...
 public function read()
 {
  $this->_dbh->query('SELECT ...');
 ...
 }
 ...
}

 

У цьому прикладі об’єкт з’єднання з базою даних був переданий класу А через конструктор, а не створювався в межах методу read(). Незважаючи на те, що це не єдиний спосіб передачі залежностей об’єкту, така реалізація використовується в Magento 2. Отже, що саме це нам дає?



Клас А може бути розроблений незалежно від класу DatabaseConnection, оскільки ми можемо завжди підробляти зв’язок для цілей розробки. Він не залежить від реалізації DatabaseConnection і в такий спосіб набагато простіше перевірити наш код.

Одним із недоліків є те, що другий приклад коду трохи більший за перший. І це правда, для прикладу Magento\Catalog\Model\Product має конструктор, який займає більше 50 рядків коду. Крім того, якщо ви спробуєте налагодити цей код, ви побачите, що це дуже важке завдання. На щастя, тут на допомогу приходить тестування.

Для ініціалізації таких великих об’єктів ін’єкції залежностей мають контейнер для ін’єкцій залежностей, а в Magento 2 він називається ObjectManager. Цей контейнер відповідає за розбір та створення залежностей після створення об’єктів. Давайте розглянемо, як це працює на простому прикладі:

 

class A
{
 public function __construct(B $b)
 {
  $this->_b = $b;
 }
}

 

При створенні об’єкта з класу А відбувається таке:

  • викликається ObjectManager->create('A')
  • розглядається Конструктор А
  • створюється Клас B і використовується для створення A

 

У цих кількох кроках ObjectManager створив об’єкт із класу. Але на даний момент не будемо вважати це таким простим і уявимо собі, що в нас є декілька реалізацій класу B. Це ставить питання, яку реалізацію буде використано? І відповідь на це питання можна знайти в одному з файлів di.xml, які розташовані в наступних місцях:

  • {папка_модуля}/etc/(область_коду)/di.xml
  • {папка_модуля}/etc/di.xml
  • app/etc/di/*.xml

 

У цих файлах ви можете знайти/вказати такі налаштування:

  • Визначення класів: тип і кількість залежностей. На щастя, Magento 2 використовує підпис конструктора для автоматичної компіляції
  • Конфігурація екземпляра. Визначення способу інстанціювання об’єктів. Це передбачає встановлення types та virtualTypes
  • Розробка карти абстракції-впровадження: це дозволяє вибрати потрібну імплементацію інтерфейсу. Це щось подібне до перевизначення (rewrite) в Magento 1.x.

 

Ще одна річ, яку потрібно пояснити, — тип об’єктів для ін’єкції. У Magento 2 вони розділені на дві групи: ін’єкційні та неін’єкційні. Спочатку розглянемо неін’єкційні об’єкти. Після цього ви самі впізнаєте ін’єкційні об’єкти.

Наприклад, давайте розглянемо сторінку товару, на якій ви хочете відобразити поточний товар та деякі пов’язані товари. Якщо ви передаєте модель товару до свого контролера, спершу вам потрібно буде викликати завантаження цього товару, щоб отримати поточний товар. Але як тільки цей об’єкт буде використовуватись, де ви отримаєте інформацію про інші товари? Тож тут ми усвідомлюємо, що модель товару – це один з об’єктів, що не є ін’єкційними. Насправді, всі об’єкти, які мають певний тип ідентичності, можуть бути неін’єкційними: товари, замовлення, елементи кошика, користувачі, …

Щоб використовувати в коді неін’єкційні об’єкти, ви повинні подати запит на їх фабрику (factory). Наприклад, якщо ви намагаєтеся завантажити декілька товарів, ваш код буде залежати від фабрики товару, і через цей об’єкт ви будете викликати метод create() з ідентифікацією товарів, які ви намагаєтеся завантажити. Проксі (proxies) призначені, головним чином, для відкладеного завантаження необов’язкових або «важких» залежностей.

 

 

 

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

 



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

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