Wprowadzanie zależności do CRUD / Modelu abstrakcyjnego Magento 2

12

Czy możliwe jest wstrzyknięcie zależności do modelu CRUD Magento 2?

To jest - Magento 2 ma bazową klasę abstrakcyjną modelu Magento\Framework\Model\AbstractModel. Jeśli chcesz utworzyć prosty obiekt do tworzenia, odczytu, aktualizacji, usuwania modelu, rozszerz tę klasę o własną klasę.

class Foo extends Magento\Framework\Model\AbstractModel
{
}

Czy możliwe jest wstrzyknięcie zależności do __constructmetody twojego modelu ? Kiedy próbuję, pojawia się następujący błąd.

Błąd krytyczny: nie można utworzyć instancji klasy abstrakcyjnej Magento \ Framework \ Model \ ResourceModel \ AbstractResource

Winowajcą wydaje się być AbstractModel„s __constructmetoda.

public function __construct(
    \Magento\Framework\Model\Context $context,
    \Magento\Framework\Registry $registry,
    \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
    \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
    array $data = []
) {

W tym konstruktorze ( Magento\Framework\Model\ResourceModel\AbstractResource, Magento\Framework\Data\Collection\AbstractDb) istnieją dwie wskazówki dotyczące typów , które nie są interfejsami menedżera obiektów Magento. To są abstrakcyjne klasy. Kiedy rozszerzam tę klasę i próbuję dodać moją wstrzykiwaną zależność

class Foo extends Magento\Framework\Model\AbstractModel
{
    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $data = [],
        \Package\Module\Model\Mine $mine,

    ) {
        //...
        parent::__construct($context, $registry, $resource, $resourceCollection, $data);

    }
}

Magento bailuje, gdy menedżer obiektów próbuje utworzyć instancję klas abstrakcyjnych.

Mogę to naprawić, przenosząc moją zależność od obiektów przed klasy abstrakcyjne

    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,

        \Package\Module\Model\Mine $mine,

        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $data = [],
    ) {  

Zmieniło to jednak kolejność argumentów. W klasie w pełni zarządzanej obiektowo nie byłoby problemu. Jednak fakt, że istnieją te abstrakcyjne wskazówki dotyczące klas, oznacza, że ​​istnieją części systemu Magento, które ręcznie (tj. Nie za pośrednictwem menedżera obiektów lub DI) utworzą obiekty CRUD i przekażą obiekty zgodne z podpowiedziami typu w tej określonej kolejności .

Czy to jest bezpieczne? tj. Czy te abstrakcyjne klasy w konstruktorze abstrakcyjnego modelu są tylko starszym kodem i nie są używane? Czy też części systemu nadal będą z nich korzystać, co oznacza, że ​​nie można wstrzykiwać zależności do modelu CRUD?

Alan Storm
źródło

Odpowiedzi:

9

Przede wszystkim konstruktor jest prywatnym API klasy. Funkcja konstruktora ma specjalne znaczenie i nie musi mieć takiej samej listy / kolejności argumentów jak w klasie nadrzędnej.

Czy możliwe jest wstrzyknięcie zależności do modelu CRUD Magento 2?

Tak oczywiście.

Czy to jest bezpieczne?

Tak, ale Magento Object Manager zakłada, że ​​wszystkie parametry opcjonalne są umieszczane na końcu listy, a wymagane parametry po opcjonalnym nie zostaną rozwiązane.

Argumenty $ resource, $ resourceCollection są starsze, ale nadal są szeroko stosowane w klasach Model. Większość modeli używa takiego kodu do inicjowania klasy zasobów i kolekcji.

protected function _construct() { 
    $this->_init('Magento\AdminNotification\Model\Resource Model\Inbox'); 
}

Dlatego te parametry są opcjonalne. Ale na przykład w teście jednostkowym przekazujemy próbkę zasobów lub kolekcji w konstruktorze, aby umożliwić realizację zamiany.

KAndy
źródło
@Kanday Czy dział inżynierii / architektury Magento kiedykolwiek wydał publiczne oświadczenie, że kolejność konstruktorów dla podstawowych klas jest nieistotna? Czy jest to tylko nadzieja większości ludzi nad tym pracujących?
Alan Storm,
Nie będę tego nazywać „nieistotnym”. Tylko OM przekaże wymagane argumenty do twojego konstruktora i nie zależy to od kolejności w klasie nadrzędnej. Co więcej, IN używa nazw parametrów, więc teraz lepiej nie zmieniać ich (różni się od języka php, w którym można zmieniać nazwy parametrów, jak chcesz)
KAndy
Nie jestem pewien, czy rozumiem, co mówisz. Czy mówisz, że w pewnym momencie kluczowy kod systemu Magento może zacząć traktować kolejność argumentów / parametrów jako znaczącą?
Alan Storm,
Uważam, że nie
KAndy
dzięki jeszcze raz! FWIW i dla Googlersów wydaje się, że powinno to być bezpieczne. Z tego, co mogę powiedzieć, nie ma kodu systemowego Magento, który automatycznie ślepo tworzy instancję modelu przyjmującego kolejność parametrów konstruktora.
Alan Storm,
6

To wydaje się być bezpieczne. Przynajmniej Magento robi to w wielu miejscach. Przykłady metod __construct na poniższej (nie wyłącznej) liście klas

  • \ Magento \ Theme \ Model \ Theme \ File
  • \ Magento \ Theme \ Model \ Design
  • \ Magento \ Sales \ Model \ Order \ Creditmemo

Niestety nie mogę odpowiedzieć na drugą część twojego pytania.

Nathan Toombs
źródło
4
  1. Jak korzystasz ze swojego modelu?
  2. W twoim przypadku $minejest wymagany parametr, podczas $resource, $resourceCollectioni $dataopcjonalne . Parametry opcjonalne powinny zawsze pozostawać na końcu, w przeciwnym razie praca z nimi jest po prostu niemożliwa, jak w przypadku opcji opcjonalnych. Więc wydaje mi się, że powinieneś określić $mineprzed jakimikolwiek parametrami opcjonalnymi.
BuskaMuza
źródło
Tyle że te parametry abstrakcyjne nie są parametrami wstrzykiwanymi w zależności, a jeśli kod systemowy Magento oczekuje, że tam będą, przejście $minena przód kolejki spowoduje błędy. Jeśli kod systemu Magento nie korzysta z nich, to dlaczego one istnieją? Oto pytanie, na które staram się dotrzeć do sedna. To, że mogę używać mojego modelu z przesuniętym parametrem, nie czyni go bezpiecznym.
Alan Storm
Niektóre modele mogą nadal używać tych opcjonalnych parametrów do przekazania niestandardowego modelu zasobów. Na przykład github.com/magento/magento2/blob/develop/app/code/Magento/…
BuskaMuza
Magento używa refleksji, aby ustalić, czy parametr jest opcjonalny, czy nie. PHP uważa, że ​​wszystkie parametry stojące przed wymaganym parametrem są wymagane . Jeśli więc przejdziesz $mineprzed parametrami opcjonalnymi, stają się one naprawdę opcjonalne, a Magento po prostu przekazuje wartości domyślne ( null, array()). Jeśli umieścisz wymagany parametr po parametrach opcjonalnych, PHP uważa parametry opcjonalne za wymagane i Magento próbował je utworzyć (ale nie ma dla nich preferencji).
BuskaMuza,
Chociaż zgadzam się, że wygląda to myląco i być może moglibyśmy ustawić preferencje dla klas abstrakcyjnych zamiast obsługiwać je w klasie modeli. Tak więc prawdziwy przedmiot jest zawsze wstrzykiwany.
BuskaMuza,