Injizieren von Abhängigkeiten in ein Magento 2 CRUD / Abstract-Modell

12

Ist es möglich, eine Abhängigkeit in ein Magento 2 CRUD-Modell zu injizieren?

Das ist - Magento 2 hat eine Basis abstrakte Modellklasse: Magento\Framework\Model\AbstractModel. Wenn Sie ein einfaches Modellobjekt erstellen, lesen, aktualisieren, löschen möchten, erweitern Sie diese Klasse mit Ihrer eigenen Klasse.

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

Ist es möglich, Abhängigkeiten in die __constructMethode Ihres Modells einzufügen? Wenn ich es versuche, erhalte ich den folgenden Fehler.

Schwerwiegender Fehler: Abstrakte Klasse Magento \ Framework \ Model \ ResourceModel \ AbstractResource kann nicht instanziiert werden

Der Täter scheint der zu sein , AbstractModel‚s - __constructMethode.

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 = []
) {

In diesem Konstruktor ( Magento\Framework\Model\ResourceModel\AbstractResource, Magento\Framework\Data\Collection\AbstractDb) gibt es zwei Typhinweise , die keine Magento-Objektmanager-Schnittstellen sind. Sie sind abstrakte Klassen. Wenn ich diese Klasse erweitere und versuche, meine injizierte Abhängigkeit hinzuzufügen

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 wird beendet, wenn der Objektmanager versucht, die abstrakten Klassen zu instanziieren.

Ich kann dies "beheben", indem ich meine Objektabhängigkeit vor die abstrakten Klassen stelle

    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 = [],
    ) {  

Dies änderte jedoch die Argumentreihenfolge. In einer Klasse, die vollständig von Objekten verwaltet wurde, wäre dies kein Problem. Die Tatsache, dass diese abstrakten Klassentyphinweise vorhanden sind, impliziert jedoch, dass es Teile des Magento-Systems gibt, die CRUD-Objekte manuell (dh nicht über den Objektmanager oder DI) instanziieren und Objekte übergeben, die den Typhinweisen in dieser bestimmten Reihenfolge entsprechen .

Ist das sicher? Sind diese abstrakten Klassen im Konstruktor eines abstrakten Modells nur Legacy-Code und werden sie nicht verwendet? Oder werden Teile des Systems diese weiterhin verwenden, was bedeutet, dass es nicht möglich ist, Abhängigkeiten in ein CRUD-Modell einzufügen?

Alan Storm
quelle

Antworten:

9

Zuallererst ist der Konstruktor eine private API der Klasse. Konstruktorfunktionen haben eine besondere Bedeutung und müssen nicht dieselbe Liste / Reihenfolge von Argumenten wie in der übergeordneten Klasse aufweisen.

Ist es möglich, eine Abhängigkeit in ein Magento 2 CRUD-Modell zu injizieren?

Ja natürlich.

Ist das sicher?

Ja, aber der Magento Object Manager geht davon aus, dass alle optionalen Parameter am Ende der Liste stehen und die erforderlichen Parameter nach optional nicht aufgelöst werden.

$ resource, $ resourceCollection-Argumente sind Legacy-Argumente, werden jedoch in Model-Klassen immer noch häufig verwendet. Die meisten Modelle verwenden diesen Code, um Ressourcen und Auflistungsklassen zu initialisieren.

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

Deshalb ist dieser Parameter optional. Zum Beispiel übergeben wir im Komponententest einen Ressourcen- oder Sammlungs-Mock im Konstruktor, um die Realisierung eines Ersatzes zu ermöglichen.

KAndy
quelle
@Kanday Hat die Ingenieur- / Architekturabteilung von Magento jemals öffentlich erklärt, dass die Reihenfolge der Konstruktoren für Kernklassen irrelevant ist? Oder ist das nur die Hoffnung der meisten Leute, die daran arbeiten?
Alan Storm
Ich werde es nicht als "irrelevant" bezeichnen. Nur OM übergibt die erforderlichen Argumente an Ihren Konstruktor und dies hängt nicht von der Reihenfolge in der übergeordneten Klasse ab. Außerdem benutze IN die Namen der Parameter, deshalb ist es jetzt besser, sie nicht zu ändern (es ist anders als in der PHP-Sprache, wo du die Namen der Parameter nach
Belieben
Ich bin nicht sicher, ob ich verstehe, was du sagst. Wollen Sie damit sagen, dass der Kern-Magento-Systemcode zu einem späteren Zeitpunkt möglicherweise die Argument- / Parameterreihenfolge wieder als signifikant behandelt?
Alan Storm
Ich glaube, dass nein
KAndy
Danke noch einmal! FWIW und für die Googler scheint dies eine sichere Sache zu sein. Soweit ich weiß, gibt es keinen Magento-Systemcode, der automatisch ein Modell instanziiert, das die Reihenfolge der Konstruktorparameter annimmt.
Alan Storm
6

Dies scheint sicher zu sein. Zumindest macht Magento dies an einer Reihe von Orten. Beispiele finden Sie in den __construct-Methoden in der folgenden (nicht exklusiven) Klassenliste

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

Leider kann ich den anderen Teil Ihrer Frage nicht beantworten.

Nathan Toombs
quelle
4
  1. Wie benutzt du dein Modell?
  2. In Ihrem Fall $mineist ein erforderlicher Parameter, während $resource, $resourceCollectionund $datasind optional . Optionale Parameter sollten immer an letzter Stelle stehen, sonst ist es einfach unmöglich, mit ihnen zu arbeiten, wie mit optional. Daher erscheint es mir in Ordnung, dass Sie $minevor optionalen Parametern angeben sollten .
BuskaMuza
quelle
Mit der Ausnahme, dass diese abstrakten Parameter keine abhängigkeitsabhängigen Parameter sind. Wenn der Magento-Kernsystemcode davon ausgeht, dass sie sich $minean der Spitze der Warteschlange befinden, werden Fehler erzeugt. Wenn der Magento-Kernsystemcode sie nicht verwendet, warum gibt es sie dann? Das ist die Frage, der ich auf den Grund gehen will. Nur weil ich mein Modell mit verschobenem Parameter verwenden kann, ist es nicht sicher.
Alan Storm
Einige Modelle verwenden möglicherweise weiterhin diese optionalen Parameter, um ein benutzerdefiniertes Ressourcenmodell zu übergeben. Beispiel: github.com/magento/magento2/blob/develop/app/code/Magento/…
BuskaMuza
Magento verwendet Reflection, um zu bestimmen, ob der Parameter optional ist oder nicht. Und PHP betrachtet alle Parameter, die vor dem erforderlichen Parameter stehen, als erforderlich . Wenn Sie also $minevor den optionalen Parametern stehen, werden diese wirklich optional und Magento übergibt nur die Standardwerte ( null, array()). Wenn Sie einen erforderlichen Parameter nach einem optionalen setzen, betrachtet PHP optionale Parameter als erforderlich und Magento hat versucht, sie zu instanziieren (aber es gibt keine Einstellungen für sie).
BuskaMuza
Obwohl ich zustimme, dass es verwirrend aussieht und wir vielleicht einfach eine Präferenz für die abstrakten Klassen einrichten könnten, anstatt sie innerhalb der Modellklasse zu behandeln. So wird immer ein reales Objekt eingespritzt.
BuskaMuza