Il modo migliore per caricare un modello personalizzato in Magento 2


15

Perché è stato difficile per me trovare la strada giusta, di seguito puoi trovare la migliore pratica che ho fatto mio. Divertiti, correggi il mio inglese se necessario e dimmi che sbaglio se lo sono. :)

Modifica: ... e ho scoperto che mi sbagliavo su alcuni aspetti. Così ho aggiornato il post originale dopo che le risposte di Raffaello mi hanno aiutato a capire di più. Grazie a lui !

Concetto utilizzato di seguito :

Sarà più facile per te comprendere i codici e le spiegazioni di seguito se ti senti a tuo agio con questi concetti:

  • Dipendenza da iniezione (poiché $this->variablevengono iniettate tutte le variabili nei codici)
  • Contratto di servizio e deposito
  • Fabbrica

Contesto :

Giusto per avere più contesto, immagina di avere un modulo correttamente costruito con:

  • una classe di blocco CustomBlock contenente un metodo getCustomModel($id),
  • questo metodo restituisce un oggetto CustomModel basato sull'id passato in param,
  • Il tipo CustomModel corrisponde al modello in \Vendor\Module\Model\CustomModel
  • Questo modello viene fornito con il suo modello di risorsa (in \Vendor\Module\Model\ResourceModel\CustomModel)
  • e con il suo repository (in \Vendor\Module\Model\CustomModelRepository).

Domanda :

  • Qual è la migliore pratica per consentire a tutto il caricamento di un oggetto CustomModel?

Non è possibile utilizzare l' load()oggetto da un oggetto CustomModel poiché questo metodo è obsoleto.

La buona pratica afferma che è necessario utilizzare il contratto di assistenza CustomModel. I contratti di assistenza sono interfacce dati (ad es. CustomModelInterface) e interfacce di servizio (ad es. CustomModelRepositoryInterface). Quindi il mio blocco è simile al seguente:

/ ** @var SlideRepositoryInterface * /
protetto $ slideRepository;

/ **
 * Costruttore CustomBlock
 * ...
 * @param CustomModelRepositoryInterface $ customModelRepository
 * ...
 * /
funzione pubblica __construct (
...
CustomModelRepositoryInterface $ customModelRepository
...
) {
    $ this-> customModelRepository = $ customModelRepository;
}

funzione pubblica getCustomModel ($ id) {
    return $ this-> customModelRepository-> get ($ id);
}

Prima di tutto, iniettiamo l' CustomModelRepositoryInterfaceoggetto nel costruttore e lo usiamo nel nostro getCustomModel()metodo.

In classe Api\CustomModelRepositoryInterfacenon c'è molto. In generale (ma nulla impedisce di fare diversamente) si dichiara metodi di base: get, getList, save, delete, deleteById. Ai fini di questo argomento, di seguito è riportata solo la getdichiarazione del metodo:

/**
 * Get info by id
 *
 * @param int $id
 * @return Data\CustomModelInterface
 * @throws \Magento\Framework\Exception\NoSuchEntityException
 */
public function get($id);

Ok, ma se la mia interfaccia CustomModel viene chiamata dall'iniezione di dipendenza nel mio costruttore di blocchi, dov'è il codice? Per rispondere a questa domanda devi spiegare a Magento dove trovare la classe che implementa questa interfaccia. Nel file etc / di.xml del modulo, devi aggiungere:

<preference for="Vendor\Module\Api\CustomModelRepositoryInterface" type="Vendor\Module\Model\CustomModelRepository" />

Quindi la CustomModelRepositoryInterfaceclasse è un'interfaccia di servizio. Nella sua attuazione dovrai implementare anche le interfacce dati (almeno Vendor\Module\Api\Data\CustomModelInterfacee Vendor\Module\Api\Data\CustomModelSearchResultsInterface). Il tuo modello dovrà implementare Vendor\Module\Api\Data\CustomModelInterfacee aggiungere <preference ... />linee per ciascuna delle tue interfacce. Infine, in qualsiasi momento utilizzi il contratto di assistenza, non pensare mySomethingInterfacepiù a mySomething: lascia che magento usi il di.xmlmeccanismo delle preferenze.

Ok, cosa viene dopo? Quando iniettiamo CustomModelRepositoryInterfacenel costruttore di blocchi, otteniamo un CustomModelRepositoryoggetto. CustomModelRepositorydeve implementare il metodo dichiarare in CustomModelRepositoryInterface. Quindi abbiamo questo in Vendor\Module\Model\CustomModelRepository:

funzione pubblica get ($ id) {
    $ customModel = $ this-> customModelFactory-> create ();
    $ CustomModel-> load ($ id);
    if (! $ customModel-> getId ()) {
      lancia new NoSuchEntityException (__ ('CustomModel con ID "% 1" non esiste.', $ id));
    }
    return $ customModel;
}

Cosa stiamo facendo ? Creiamo un CustomModeloggetto vuoto grazie alla fabbrica. Successivamente cariciamo i dati CustomModelutilizzando il metodo del modello di caricamento. Quindi restituiamo a NoSuchEntityExceptionse non siamo riusciti a caricare CustomModell'ID con i parametri. Ma se tutto va bene, restituiamo l'oggetto modello e la vita continua.

Ma wow ...! In questo esempio che cos'è?

$customModel->load($id);

Lo stesso loadmetodo deprecato non è all'inizio? Sì. Penso che sia un peccato, ma devi usarlo poiché in questo metodo load () ci sono alcuni eventi inviati e lo sviluppatore potrebbe ascoltarli (vedi la risposta di Raphael sotto).

In futuro, saremo salvati da Entity Manager. È un'altra storia come un nuovo concetto di Magento 2, ma se vuoi dare un'occhiata, Entity Manager è già implementato nel modello di risorsa della pagina CMS (v2.1):

public function load(AbstractModel $object, $value, $field = null)
{
    $pageId = $this->getPageId($object, $value, $field);
    if ($pageId) {
        $this->entityManager->load($object, $pageId);
    }
    return $this;
}

Risposte:


16

Best practice: tramite il contratto di servizio

La migliore pratica è sempre quella di utilizzare il contratto di assistenza ogni volta che è possibile. Puoi trovare l'elenco dei motivi qui: Magento 2: quali sono i vantaggi dell'utilizzo dei contratti di servizio?

Per dettagli su come implementare un contratto di servizio, ti suggerisco di consultare questo argomento: Come implementare un contratto di servizio per un modulo personalizzato in Magento 2?

Se nessun contratto di servizio disponibile

Se non è disponibile alcun contratto di assistenza, è necessario utilizzare il getmetodo di repository di modelli . Usando questo metodo, puoi beneficiare del sistema di memorizzazione nella cache di magento, ad esempio per la CategoryRepositoryclasse:

public function get($categoryId, $storeId = null)
{
    $cacheKey = null !== $storeId ? $storeId : 'all';
    if (!isset($this->instances[$categoryId][$cacheKey])) {
        /** @var Category $category */
        $category = $this->categoryFactory->create();
        if (null !== $storeId) {
            $category->setStoreId($storeId);
        }
        $category->load($categoryId);
        if (!$category->getId()) {
            throw NoSuchEntityException::singleField('id', $categoryId);
        }
        $this->instances[$categoryId][$cacheKey] = $category;
    }
    return $this->instances[$categoryId][$cacheKey];
}

load()Metodo obsoleto

Magento 2 si sta lentamente allontanando dal sistema CRUD standard rilasciando il sistema di ereditarietà e implementandolo tramite la composizione usando il nuovo EntityManager 2.1, puoi trovare i dettagli qui: Magento 2.1: utilizzando il gestore entità

Inoltre ti suggerisco di leggere questo interessante argomento sui metodi CRUD obsoleti: metodi di salvataggio e caricamento obsoleti in Modello astratto

Perché non utilizzare il caricamento del modello di risorsa

Il motivo principale è che se si utilizza il loadmetodo del modello di risorsa , si salterà alcune parti importanti del sistema di caricamento implementate nel loadmetodo del modello , vedere Magento\Framework\Model\AbstractModel:

public function load($modelId, $field = null)
{
    $this->_beforeLoad($modelId, $field);
    $this->_getResource()->load($this, $modelId, $field);
    $this->_afterLoad();
    $this->setOrigData();
    $this->_hasDataChanges = false;
    $this->updateStoredData();
    return $this;
}

La chiamata loaddiretta del metodo del modello di risorsa avrà il seguente impatto:

  • _beforeLoad non viene chiamato: pertanto il carico del modello prima che gli eventi non vengano inviati
  • _afterLoad non viene chiamato: pertanto il carico del modello dopo gli eventi non viene inviato
  • i dati memorizzati non vengono aggiornati, il che può causare vari problemi (ad esempio se si chiama prepareDataForUpdateda Magento\Framework\Model\ResourceModel\Db\AbstractDb)

Grazie Raffaello, ogni cosa che dici ha senso e completa la mia conoscenza. Ma non capisco perché KAndy commenta (sotto la sua risposta) che Marius può usare il metodo load () del suo modello di risorsa del modulo personalizzato? È in [ magento.stackexchange.com/questions/114929/… metodi di salvataggio e caricamento in Modello astratto). Qualche idea ?
Nicolas PERNOT,

@NicolasPERNOT sostanzialmente KAndy spiega che l'obiettivo è avere SL (Service Layer) per ogni modulo e che questo è ciò che deve essere usato ogni volta che è necessario caricare un'entità. Ti suggerisco di commentarlo menzionandolo, forse sarà in grado di illuminarti dato che è un dipendente di Magento Inc, credo
Raffaello al Pianismo digitale,

Bene, ho finalmente aggiornato il mio post originale. Grazie Raffaello per il tuo aiuto.
Nicolas PERNOT,

Vedo che almeno in Magento 2.2 quell'importante è incluso nel carico di ResourceModel, quindi non è OK usare direttamente i metodi ResourceModel, giusto?
Jānis Elmeris,

Attualmente, possiamo caricare in modo sicuro Model utilizzando il load()metodo Resource Model . Il modello di risorsa chiama i metodi del modello dal proprio load()metodo: $model->beforeLoad() { $this->_beforeLoad() }e$model->afterLoad() { $this->_afterLoad() }
sergei.sss,

-2

Penso che la seguente affermazione non sia valida ora.

Why not using the resource model load

possiamo trovare Magento\Framework\EntityManager\Observercartella tutti gli eventi.

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.