И так, давай начнём 😎
Введение
На продакшен окружении, Magento должна работать на файловой системе сконфигурированной только для чтения, это рекомендуется с точки зрения безопасности.
На запись доступны только следующие каталоги:
- app/etc
- pub/static
- pub/media
- var
Важное замечание: папка с сгенерированными классами была перемещена с var/generation в generated/code. Сейчас, эта папка не доступна на запись в продакшене. Эти папки имеют аналогичные разрешения на запись в облачной инфраструктуре Magento.
Итак, если ты добавишь зависимость неправильно, то Magento может поломаться.
Класс в точке доступа
Разработчик пишет класс в точке доступа и добавляет в конструктор зависимость на генерируемую фабрику.
<?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:
<?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
<?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
Неправильное добаление зависимости
Неправильное добавление зависимости на генерируемый класс в существующий класс. Например, следующий код будет корректно работать в режиме разработчика, но завершиться неудачей в продакшен режиме на файловой система только для чтения.
<?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:
<?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