Як додати нові залежності до класів

Іноді нам потрібно додати нові залежності до класів, і нам потрібно це зробити зворотно сумісним. У цій статті я маю намір описати як це зробити. Я також розповім про типові помилки.

Що ж, давай почнемо 😎

Вступ

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

На запис доступні лише такі каталоги:

  • app/etc
  • pub/static
  • pub/media
  • var

Важливе зауваження: папка зі згенерованими класами була переміщена з var/generation у generated/code. Зараз, ця папка не доступна для запису в продакшені. Ці папки мають аналогічні дозволи на запис у хмарній інфраструктурі Magento.

Отже, якщо ти додаси неправильно залежність, то Magento може поламатися.

Клас у точці доступу

Розробник пише клас у точці доступу і додає в конструктор залежність на фабрику, що генерується.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
use YourVendor\SomeModule\Model\GeneratedFactory;

require realpath(__DIR__) . '/../app/bootstrap.php';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);

class SomeClass
{
    private $generatedFactory;

    public function __construct(GeneratedFactory $generatedFactory)
    {
        $this->generatedFactory = $generatedFactory;
    }

    // Some code here...
}

$someObject = $bootstrap->getObjectManager()->create(SomeClass::class);

// There is some code that uses $someObject

Цей приклад буде працювати в режимі розробника, GeneratedFactory генеруватиметься на льоту. Але в режимі продакшен, на файловій системі тільки для читання, ти зіткнешся з помилкою, що GeneratedFactory не може бути збережена в каталозі generateted/code.

Це відбувається тому, що Magento не сканує точку входу під час роботи команди bin/magento setup:di:compile. І якщо точка входу містить визначення класів, що генеруються, то вони будуть проігноровані.

Є два шляхи, як це виправити.

Як це виправити?

Перший шлях - це створити реальний клас фабрики у файловій системі.

Другий шлях - це перемістити клас SomeClass у папку app/code/YourVendor/SomeModule. Тоді сканер коду Magento знайде в класі SomeClass залежність на фабрику, що генерується GeneratedFactory, і генератор коду згенерує цю фабрику.

Приклад класу SomeClass:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php
namespace YourVendor\SomeModule;

use YourVendor\SomeModule\Model\GeneratedFactory;

class SomeClass
{
    private $generatedFactory;

    public function __construct(GeneratedFactory $generatedFactory)
    {
        $this->generatedFactory = $generatedFactory;
    }

    // Some code here...
}

Редагуємо точку входу my_api/index.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php

use YourVendor\SomeModule\SomeClass;

require realpath(__DIR__) . '/../app/bootstrap.php';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);

$someObject = $bootstrap->getObjectManager()->create(SomeClass::class);

// There is some code that uses $someObject

Неправильне додавання залежності

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<?php
namespace YourVendor\SomeModule;

use YourVendor\SomeModule\Model\GeneratedFactory;
use Magento\Framework\App\ObjectManager;

class SomeClass
{
    private $generatedFactory;
    private $someParam;

    public function __construct($someParam)
    {
        $this->someParam = $someParam;
        $this->generatedFactory = ObjectManager::getInstance()->get(GeneratedFactory::class);
    }

    // Some code here...
}

Як це виправити?

Подібний підхід іноді використовується для додавання залежностей та збереження зворотної сумісності. Але цей підхід має ту саму проблему, що й приклад вищий. Під час роботи команди bin/magento setup:di:compile, клас, що генерується, не буде згенерований.

Тут також є два способи, як це виправити.

Перший шлях - це створити реальний клас фабрики у файловій системі.

Другий шлях - це трохи змінити конструктор SomeClass

Приклад класу SomeClass:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<?php
namespace YourVendor\SomeModule;

use YourVendor\SomeModule\Model\GeneratedFactory;
use Magento\Framework\App\ObjectManager;

class SomeClass
{
    private $generatedFactory;
    private $someParam;

    public function __construct($someParam, GeneratedFactory $generatedFactory = null)
    {
        $this->someParam = $someParam;
        $this->generatedFactory = $generatedFactory ?: ObjectManager::getInstance()->get(GeneratedFactory::class);
    }

    // Some code here...
}

В цьому випадку:

  • ми додали нову залежність
  • ми зберегли зворотну сумісність
  • генерований клас буде згенерований
  • Magento коректно працює в режимі продакшен на файловій системі тільки для читання.

Якщо у тебе є якісь питання чи коментарі - пиши, з радістю відповім 😉

Ти можеш знайти приклад неправильного DI в модулі Magento в цьому репозиторії: https://github.com/BaDos/example-wrong-di

comments powered by Disqus
Створено з Hugo
Тема Stack, дизайн Jimmy