Cosa e perché è il modo corretto di caricare un modello


9

Ho molta esperienza con Magento ma mi sono reso conto che non capisco quale modo di caricare un modello sia quello corretto e perché. Ho letto tutto quello che potevo sull'argomento, ma le persone che spiegano cose come questa non sono mai abbastanza approfondite da spiegare, perché usare questo metodo specifico invece di un altro. Supponiamo che non ci siano repository per il modello che voglio caricare.

Fino ad ora usavo sempre il modello nel costruttore e poi semplicemente lo caricavo.

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

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

E ha sempre funzionato come previsto, sono anche abbastanza sicuro che sia o almeno sia stato usato comunemente nel core.

Ma poi ho visto usare uno dei miei colleghi

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

Per quanto ho capito, le fabbriche vengono utilizzate per creare una nuova entità, ad esempio, se volessi creare un nuovo prodotto, posso creare la fabbrica, popolarla con i dati e salvarla. Ma poi di nuovo, ho iniziato a fare ricerche sull'argomento e ho visto degli esempi di Fabian Schmengler ( Quando dovremmo usare un repository e una fabbrica in Magento 2? ) Che stava caricando il modello in questo modo e scoraggiando anche altri dal semplice caricamento dei modelli, non ha fatto Spiego perché, oltre a dire che "non fa parte del contratto di servizio". Per quanto ho capito, i repository fanno parte dei contratti di servizio, quindi non vedo alcuna connessione qui quando si tratta di caricare modelli che non sono disponibili tramite un repository.

Per aggiungere un po 'più di confusione, ho anche trovato un modo per caricare il modello ottenendo il modello di risorsa dal modello modelFactory creato, è stato presentato da Vinai Kopp ( Come implementare il contratto di servizio per un modulo personalizzato in Magento 2? ) E ora sono completamente perso poiché ho sempre letto che non avrei dovuto usare direttamente i modelli di risorse.

Quindi sì, qualcuno potrebbe dirmi qual è il modo corretto e perché dovrei usarlo al posto di tutti gli altri metodi?


Sto letteralmente collegando questa discussione come contenente esempi confusi, hai mai letto il mio post?
CZ

1
Bella domanda, proverò a trovare il tempo per rispondere in dettaglio più avanti. Posso già dirti così tanto: è un caso diverso se carichi i tuoi modelli (esempio di Vinai) o modelli dei moduli core o di terze parti (la mia risposta). Inoltre, l'iniezione del modello tramite il costruttore ti darà sempre la stessa istanza, il che potrebbe portare a effetti collaterali indesiderati.
Fabian Schmengler,

Risposte:


12

Bene, il primo passo che dovresti verificare per il modello in questione è: esiste un contratto di servizio di deposito? In tal caso, utilizzalo perché i Contratti di servizio sono vincolati al controllo delle versioni semantico e continueranno a comportarsi come dovrebbero fare fino alla pubblicazione di Magento 3.x. Inutile dire che quando crei i tuoi moduli con modelli che richiedono persistenza, dovresti anche scrivere il repository per quello.

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

Se non è presente alcun repository, utilizzare il modello di risorsa . Si noti che i modelli di risorse non contengono uno stato: utilizzano la persistenza per i loro modelli "normali". Pertanto non è necessario includerli utilizzando una fabbrica:

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);
}

"Quindi quale vantaggio porta un contratto di servizio / repository rispetto a un modello di risorsa?" potresti chiedere. Bene, in teoria un modello di risorsa dovrebbe essere responsabile solo della persistenza di un modello di dati , mentre un repository tiene conto anche delle attività aggiuntive coinvolte nel salvataggio di un'entità. Pensa all'aggiornamento degli indici, alla creazione di relazioni con altre entità, ecc. Questa è la teoria, sebbene nella vita reale queste linee tendano a confondersi abbastanza spesso. Ma è bene che te lo ricordi.

Si consiglia di non utilizzare il modello diretta save(), load()ecc -metodi. Sono deprecati perché è semantico errato. Pensaci in modo SOLIDO:

  • (Dati) I modelli dovrebbero essere responsabili solo del contenimento dei dati.
  • I modelli di risorse dovrebbero essere responsabili della persistenza di tali dati.
  • I repository dovrebbero essere responsabili della comunicazione all'interno e all'esterno del modulo per le azioni di persistenza.

Ed è l'ultimo punto che fa la differenza: quando si comunica con altri moduli, in un mondo ideale non si dovrebbe mai fare affidamento sulla logica persistente interna di quei moduli (o su uno qualsiasi dei suoi metodi pubblici per quella materia, ma questa è un'altra discussione), ma utilizza solo quella funzionalità fornita dai Contratti di servizio dei moduli .

In conclusione

Per rispondere alla tua domanda: in ordine di preferenza. Il modo corretto di caricare un modello è:

  • Se esiste un repository, caricarlo utilizzando il repository.
  • Solo se non esiste un repository, utilizzare il modello di risorsa (in combinazione con una fabbrica).

1
Ok, quindi se seguo correttamente - quando voglio modificare / aggiungere nuovi dati e salvarli nel database, allora dovrei usare il modello di risorsa e quando voglio caricare i dati in memoria, allora dovrei usare Factory? Quindi c'è qualche situazione in cui dovrei usare direttamente il modello regolare (come nell'uso di una classe Model nel costruttore)?
CZ

@czs Hai ragione, ho aggiunto un esempio più descrittivo per il caricamento del modello per lo stesso.
Milind Singh,

2
  • Modelssono Data Interface vengono utilizzati per contenere solo i dati negli oggetti, ovvero a sete getdati per una riga.
  • ResourceModelssono un meccanismo responsabile della persistenza di tali dati, ovvero eseguire la query SQL in realtà saveo i loaddati Modelnell'oggetto.

Il modo corretto per loade savedovrebbe essere creando un repository o caricando da una risorsa come segue:

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;
    }
}

Qui, \MyVendor\MyModule\Api\Data\QueueInterfaceè implorato dal Queuemodello.

Quindi, dietro le quinte, stiamo effettivamente creando un Modeloggetto, quindi loadingl' ResourceModeloggetto. Questo è il modo corretto di caricare o salvare.

        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.