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?

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.


@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.


4
  1. Jak korzystasz ze swojego modelu?
  2. W twoim przypadku $minejest wymagany parametr, podczas $resource, $resourceCollectioni $datasą opcjonalne . 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.

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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.