Що і чому є правильним способом завантаження моделі


9

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

До цього моменту я завжди використовував модель в конструкторі, а потім просто завантажував її.

public function __construct(
    \Vendor\Module\Model\Something $somethingModel
) {
    $this->somethingModel = $somethingModel;
}

public function getTestById($id) {
    return $this->somethingModel->load($id);
}

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

Але потім я побачив, як хтось із колег використовує

modelFactory->create()->load($id)

Наскільки я розумію, фабрики використовуються для створення нового об'єкта, наприклад, якщо я хотів створити новий продукт, то я можу створити фабрику, заповнити її даними і потім зберегти. Але потім я знову почав досліджувати цю тему, і побачив приклад Фабіана Шменглера ( Коли ми повинні використовувати сховище та завод у Magento 2? ), Який завантажував модель таким чином, а також відштовхував інших від просто завантаження моделей, він не став ' t поясніть, чому, окрім того, що сказати, що це "не є частиною договору на послуги". Наскільки я розумію, сховища є частиною контрактів на обслуговування, тому я не бачу тут ніякого зв'язку, коли мова заходить про завантаження моделей, недоступних через сховище.

Щоб додати ще трохи плутанини, я також знайшов спосіб завантаження моделі, отримуючи resourceModel зі створеної моделіFactory, її представив Vinai Kopp ( Як реалізувати контракт на обслуговування користувацького модуля в Magento 2? ), І тепер я повністю втрачений, оскільки я завжди читав, що я не повинен безпосередньо використовувати моделі ресурсів.

Так так, невже хтось може сказати мені, що це правильний спосіб, і чому я повинен використовувати його замість усіх інших методів?


Я буквально пов'язую цей потік як такий, що містить заплутаний приклад, ти навіть читав мій пост?
czs

1
Хороше запитання, я спробую знайти час, щоб детально відповісти пізніше. Я вже можу вам сказати так багато: це інший випадок, якщо ви завантажуєте власні моделі (наприклад, Vinai) або моделі основних або сторонніх модулів (моя відповідь). Крім того, введення моделі через конструктор дасть вам кожен і той же примірник, що може призвести до небажаних побічних ефектів.
Фабіан Шменглер

Відповіді:


12

Що ж, перший крок, який ви повинні перевірити на відповідну модель, це: чи є договір на обслуговування сховища? Якщо це так, використовуйте це, оскільки Контракти на обслуговування пов'язані з семантичною версією та продовжуватимуть діяти так, як слід, до появи Magento 3.x. Зайве говорити, що при створенні власних модулів з моделями, які потребують стійкості, ви також повинні написати для цього сховище.

public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
) {
    $this->productRepository = $productRepository;
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $this->productRepository->save($product);
}

Якщо репозиторію немає, використовуйте модель ресурсу . Зауважте, що моделі ресурсів не містять стану: вони використовують наполегливість для своїх "звичайних" моделей. Тому не потрібно включати їх на заводі:

public function __construct(
    \Magento\Catalog\Model\ResourceModel\Product $productResource,
    \Magento\Catalog\Model\ProductFactory $productFactory
) {
    $this->productResource = $productResource;
    $this->productFactory = $productFactory;
    ...
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $product = $this->productFactory->create();
    $this->productResource->save($product);
}

"Отже, яка вигода приносить контракт на послугу / сховище для моделі ресурсів?" ви можете запитати. Ну, теоретично модель ресурсів повинна відповідати лише за збереження моделі даних , тоді як репозиторій також враховує додаткові завдання, пов'язані із збереженням сутності. Подумайте про оновлення індексів, створення відносин з іншими сутностями тощо. Це теорія, хоча в реальному житті ці рядки мають тенденцію розмиватися досить часто. Але для себе добре мати це на увазі.

Ви не повинні використовувати моделі прямої save(), load()і т.д. -Методи. Вони застаріли, оскільки це семантично неправильно. Подумайте про це ТВЕРДО:

  • (Дані) Моделі повинні відповідати лише за вміст даних.
  • Моделі ресурсів повинні відповідати за збереження таких даних.
  • Репозиторії повинні нести відповідальність за зв'язок всередині та зовні модуля за постійні дії.

І саме цей останній момент має значення: під час спілкування з іншими модулями в ідеальному світі ніколи не слід покладатися на внутрішню стійку логіку цього модуля (або будь-який з його публічних методів з цього питання, але це інша дискусія), але використовувати лише ту функціональність, яку надають модулі " Контракти на обслуговування" .

У висновку

Щоб відповісти на ваше запитання: у порядку уподобань. Правильний спосіб завантаження моделі:

  • Якщо є сховище, завантажте його за допомогою сховища.
  • Тільки якщо немає сховища, використовуйте модель ресурсів (у поєднанні з фабрикою).

1
Гаразд, тому якщо я дотримуюся правильно - коли я хочу змінити / додати нові дані та зберегти їх у базі даних, тоді я повинен використовувати Модель ресурсів і wen Я хочу завантажити дані в пам'ять, тоді я повинен використовувати Factory? Так чи є ситуація, в якій я повинен використовувати звичайну модель безпосередньо (як при використанні класу Model у конструкторі)?
czs

@czs Ви праві, я додав більш описовий приклад завантаження моделі для тієї ж.
Мілінд Сінгх

2
  • Modelsє Інтерфейс передачі даних використовується тільки зберігати дані в об'єктах, тобто до setі getданих для рядка.
  • ResourceModels- це механізм, який відповідає за збереження таких даних, тобто виконує запит SQL фактично saveабо loadданих в Modelоб'єкт.

Правильний шлях до loadта saveповинен бути шляхом створення сховища або завантаження з ресурсу наступним чином:

namespace MyVendor\MyModule\Model;

class QueueRepository impliments \MyVendor\MyModule\Api\QueueRepositoryInterface
{

    /** @var \MyVendor\MyModule\Model\ResourceModel\Queue  */
    public $resource;

    /** @var \MyVendor\MyModule\Model\QueueFactory  */
    public $modelFactory;

    public function __construct(
        \MyVendor\MyModule\Model\ResourceModel\Queue $resource,
        \MyVendor\MyModule\Model\QueueFactory $modelFactory
    ) {
        $this->resource = $resource;
        $this->modelFactory = $modelFactory;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @return $queue
     * @throws \Exception
     */
    public function save(\MyVendor\Integrator\Api\Data\QueueInterface $queue)
    {
        $this->resource->save($queue);
        return $queue;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @param int $id
     * @return $queue
     * @throws \Exception
     */
    public function load(\MyVendor\MyModule\Api\Data\QueueInterface $queue, $id)
    {
        $this->resource->load($queue, $id);
        return $queue;
    }

    public function getById($id)
    {
        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
    }
}

Ось, \MyVendor\MyModule\Api\Data\QueueInterfaceпоширюється Queueмодель.

Отже, за лаштунками ми фактично створюємо Modelоб'єкт, а потім loadingйого ResourceModelоб'єктом. Це правильний спосіб завантаження або збереження.

        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.