Come implementare il contratto di servizio per un modulo personalizzato in Magento 2?


42

Come visto in questo post: metodi di salvataggio e caricamento obsoleti nel modello astratto i metodi savee loadsono deprecati nel ramo di sviluppo di Magento 2.

Pertanto, la buona prassi è ora quella di attuare contratti di servizio per trattare con entità CRUD.

Qual è il processo passo-passo che devo seguire per implementare i contratti di servizio per le mie entità del modulo personalizzato?

NB: So che ci possono essere migliaia di metodi nei miei modelli CRUD, sto solo chiedendo i metodi ovvi come indicato qui: http://devdocs.magento.com/guides/v2.0/extension-dev-guide /service-contracts/design-patterns.html :

  • get
  • save
  • getList
  • delete
  • deleteById

Risposte:


90

Vorrei dare un po 'più di dettagli oltre all'ottima risposta di @ryanF.

Vorrei riassumere i motivi per aggiungere un repository per entità personalizzate, fornire esempi su come farlo e anche spiegare come esporre quei metodi di repository come parte dell'API Web.

Disclaimer: sto solo descrivendo un approccio pragmatico su come farlo per i moduli di terze parti: i team principali hanno i loro standard che seguono (o meno).

In generale, lo scopo di un repository è nascondere la logica relativa all'archiviazione.
Un client di un repository non dovrebbe preoccuparsi se l'entità restituita è tenuta in memoria in un array, viene recuperata da un database MySQL, recuperata da un'API remota o da un file.
Suppongo che il core team di Magento abbia fatto questo in modo che possano cambiare o sostituire l'ORM in futuro. In Magento l'ORM attualmente è costituito da modelli, modelli di risorse e raccolte.
Se un modulo di terze parti utilizza solo i repository, Magento può cambiare il modo e la posizione in cui sono archiviati i dati e il modulo continuerà a funzionare, nonostante questi profondi cambiamenti.

Repository hanno generalmente metodi come findById(), findByName(), put()o remove().
In questi Magento comunemente sono chiamati getbyId(), save()e delete(), nemmeno facendo finta che stanno facendo altro che operazioni CRUD DB.

I metodi di repository Magento 2 possono essere facilmente esposti come risorse API, rendendoli utili per integrazioni con sistemi di terze parti o istanze senza testa di Magento.

"Devo aggiungere un repository per la mia entità personalizzata?".

Come sempre, la risposta è

"Dipende".

Per farla breve, se le tue entità saranno utilizzate da altri moduli, allora sì, probabilmente vorrai aggiungere un repository.

C'è un altro fattore che viene preso in considerazione qui: in Magento 2, i repository possono essere facilmente esposti come API Web - ovvero REST e SOAP - risorse.

Se questo è interessante per te a causa di integrazioni di sistema di terze parti o di un'installazione senza testa di Magento, allora di nuovo sì, probabilmente vorrai aggiungere un repository per la tua entità.

Come faccio ad aggiungere un repository per la mia entità personalizzata?

Supponiamo che tu voglia esporre la tua entità come parte dell'API REST. Se ciò non è vero, puoi saltare la parte imminente sulla creazione delle interfacce e andare direttamente a "Crea il repository e l'implementazione del modello di dati" di seguito.

Creare il repository e le interfacce del modello dati

Crea le cartelle Api/Data/nel tuo modulo. Questa è solo una convenzione, potresti usare una posizione diversa, ma non dovresti.
Il repository va nella Api/cartella. La Data/sottodirectory è per dopo.

In Api/, crea un'interfaccia PHP con i metodi che vuoi esporre. Secondo le convenzioni di Magento 2, tutti i nomi di interfaccia finiscono nel suffisso Interface.
Ad esempio, per Hamburgerun'entità, vorrei creare l'interfaccia Api/HamburgerRepositoryInterface.

Creare l'interfaccia del repository

I repository Magento 2 fanno parte della logica di dominio di un modulo. Ciò significa che non esiste un insieme fisso di metodi che un repository deve implementare.
Dipende interamente dallo scopo del modulo.

Tuttavia, in pratica tutti i repository sono abbastanza simili. Sono wrapper per la funzionalità CRUD.
La maggior parte hanno i metodi getById, save, deletee getList.
Potrebbero essercene altri, ad esempio CustomerRepositoryha un metodo get, che recupera un cliente via e-mail, per cui getByIdviene utilizzato per recuperare un cliente per ID entità.

Ecco un'interfaccia di repository di esempio per un'entità hamburger:

<?php

namespace VinaiKopp\Kitchen\Api;

use Magento\Framework\Api\SearchCriteriaInterface;
use VinaiKopp\Kitchen\Api\Data\HamburgerInterface;

interface HamburgerRepositoryInterface
{
    /**
     * @param int $id
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function getById($id);

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\HamburgerInterface $hamburger
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerInterface
     */
    public function save(HamburgerInterface $hamburger);

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\HamburgerInterface $hamburger
     * @return void
     */
    public function delete(HamburgerInterface $hamburger);

    /**
     * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface
     */
    public function getList(SearchCriteriaInterface $searchCriteria);

}

Importante! Ecco a voi le scadenze!
Ci sono alcuni trucchi che sono difficili da eseguire il debug se si sbagliano:

  1. NON utilizzare tipi di argomenti scalari PHP7 o tipi restituiti se si desidera collegarlo all'API REST!
  2. Aggiungi annotazioni PHPDoc per tutti gli argomenti e il tipo restituito a tutti i metodi!
  3. Usa i nomi di classe pienamente qualificati nel blocco PHPDoc!

Le annotazioni vengono analizzate da Magento Framework per determinare come convertire i dati da e verso JSON o XML. Le importazioni di classe (ovvero usedichiarazioni) non vengono applicate!

Ogni metodo deve avere un'annotazione con qualsiasi tipo di argomento e il tipo restituito. Anche se un metodo non accetta argomenti e non restituisce nulla, deve avere l'annotazione:

/**
 * @return void
 */

Tipi scalari ( string, int, floate bool) devono anche essere specificato, sia per gli argomenti e come valore di ritorno.

Si noti che nell'esempio sopra, anche le annotazioni per i metodi che restituiscono oggetti sono specificate come interfacce.
Le interfacce del tipo restituito si trovano tutte nella Api\Datadirectory namespace /.
Questo per indicare che non contengono alcuna logica aziendale. Sono semplicemente sacchi di dati.
Dobbiamo creare queste interfacce successivamente.

Creare l'interfaccia DTO

Penso che Magento chiama queste interfacce "modelli di dati", un nome che non mi piace affatto.
Questo tipo di classe è comunemente noto come Data Transfer Object o DTO .
Queste classi DTO hanno solo getter e setter per tutte le loro proprietà.

Il motivo per cui preferisco utilizzare DTO sul modello dati è che è meno facile confonderlo con i modelli di dati ORM, i modelli di risorse o i modelli di visualizzazione ... troppe cose sono già modelli in Magento.

Le stesse restrizioni in materia di tipizzazione PHP7 che si applicano ai repository si applicano anche ai DTO.
Inoltre, ogni metodo deve avere un'annotazione con tutti i tipi di argomento e il tipo restituito.

<?php

namespace VinaiKopp\Kitchen\Api\Data;

use Magento\Framework\Api\ExtensibleDataInterface;

interface HamburgerInterface extends ExtensibleDataInterface
{
    /**
     * @return int
     */
    public function getId();

    /**
     * @param int $id
     * @return void
     */
    public function setId($id);

    /**
     * @return string
     */
    public function getName();

    /**
     * @param string $name
     * @return void
     */
    public function setName($name);

    /**
     * @return \VinaiKopp\Kitchen\Api\Data\IngredientInterface[]
     */
    public function getIngredients();

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\IngredientInterface[] $ingredients
     * @return void
     */
    public function setIngredients(array $ingredients);

    /**
     * @return string[]
     */
    public function getImageUrls();

    /**
     * @param string[] $urls
     * @return void
     */
    public function setImageUrls(array $urls);

    /**
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface|null
     */
    public function getExtensionAttributes();

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface $extensionAttributes
     * @return void
     */
    public function setExtensionAttributes(HamburgerExtensionInterface $extensionAttributes);
}

Se un metodo recupera o restituisce un array, il tipo di elementi nell'array deve essere specificato nell'annotazione PHPDoc, seguito da una parentesi quadra di apertura e chiusura [].
Questo vale sia per i valori scalari (ad es. int[]) Sia per gli oggetti (ad es IngredientInterface[].).

Nota che sto usando un Api\Data\IngredientInterfaceesempio per un metodo che restituisce una matrice di oggetti, non aggiungerò il codice degli ingredienti a questo post difficile.

ExtensibleDataInterface?

Nell'esempio sopra il HamburgerInterfaceestende il ExtensibleDataInterface.
Tecnicamente questo è necessario solo se si desidera che altri moduli siano in grado di aggiungere attributi alla propria entità.
In tal caso, devi anche aggiungere un'altra coppia getter / setter, per convenzione chiamata getExtensionAttributes()e setExtensionAttributes().

La denominazione del tipo restituito di questo metodo è molto importante!

Il framework Magento 2 genererà l'interfaccia, l'implementazione e la factory per l'implementazione se li nominerai nel modo giusto. I dettagli di questi meccanismi non rientrano nell'ambito di questo post.
Basta sapere se viene chiamata l'interfaccia dell'oggetto che si desidera rendere estensibile \VinaiKopp\Kitchen\Api\Data\HamburgerInterface, quindi deve essere il tipo di attributi di estensione \VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface. Quindi la parola Extensiondeve essere inserita dopo il nome dell'entità, subito prima del Interfacesuffisso.

Se non si desidera che il soggetto per essere estensibile, quindi l'interfaccia DTO non deve estendere qualsiasi altra interfaccia, e le getExtensionAttributes()e setExtensionAttributes()metodi può essere omesso.

Abbastanza per ora l'interfaccia DTO, è ora di tornare all'interfaccia del repository.

GetList () restituisce il tipo SearchResults

Il metodo repository getListrestituisce ancora un altro tipo, ovvero SearchResultsInterfaceun'istanza.

getListOvviamente il metodo potrebbe semplicemente restituire una matrice di oggetti corrispondente a quella specificata SearchCriteria, ma restituire SearchResultsun'istanza consente di aggiungere alcuni metadati utili ai valori restituiti.

Puoi vedere come funziona di seguito nell'implementazione del getList()metodo repository .

Ecco l'interfaccia di risultato della ricerca di hamburger di esempio:

<?php

namespace VinaiKopp\Kitchen\Api\Data;

use Magento\Framework\Api\SearchResultsInterface;

interface HamburgerSearchResultInterface extends SearchResultsInterface
{
    /**
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerInterface[]
     */
    public function getItems();

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\HamburgerInterface[] $items
     * @return void
     */
    public function setItems(array $items);
}

Tutto ciò che questa interfaccia fa è sovrascrive i tipi per i due metodi getItems()e setItems()per l'interfaccia genitore.

Riepilogo delle interfacce

Ora abbiamo le seguenti interfacce:

  • \VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface
  • \VinaiKopp\Kitchen\Api\Data\HamburgerInterface
  • \VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface

L'archivio si estende nulla,
la HamburgerInterfaceestende la \Magento\Framework\Api\ExtensibleDataInterface,
e la HamburgerSearchResultInterfaceestende il \Magento\Framework\Api\SearchResultsInterface.

Creare il repository e le implementazioni del modello dati

Il prossimo passo è creare le implementazioni delle tre interfacce.

Il repository

In sostanza, il repository utilizza l'ORM per fare il proprio lavoro.

I getById(), save() e delete()metodi sono abbastanza semplice.
La HamburgerFactoryviene iniettato nella repository come argomento del costruttore, come si può vedere un po 'più avanti.

public function getById($id)
{
    $hamburger = $this->hamburgerFactory->create();
    $hamburger->getResource()->load($hamburger, $id);
    if (! $hamburger->getId()) {
        throw new NoSuchEntityException(__('Unable to find hamburger with ID "%1"', $id));
    }
    return $hamburger;
}

public function save(HamburgerInterface $hamburger)
{
    $hamburger->getResource()->save($hamburger);
    return $hamburger;
}

public function delete(HamburgerInterface $hamburger)
{
    $hamburger->getResource()->delete($hamburger);
}

Ora alla parte più interessante di un repository, il getList()metodo.
Il getList()metodo deve tradurre le SerachCriteriacondizioni in chiamate di metodo sulla raccolta.

La parte difficile di ciò è ottenere le condizioni ANDe ORper i filtri giusti, soprattutto perché la sintassi per impostare le condizioni sulla raccolta è diversa a seconda che si tratti di un EAV o di un'entità tabella piatta.

Nella maggior parte dei casi, getList()può essere implementato come illustrato nell'esempio seguente.

<?php

namespace VinaiKopp\Kitchen\Model;

use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Api\SortOrder;
use Magento\Framework\Exception\NoSuchEntityException;
use VinaiKopp\Kitchen\Api\Data\HamburgerInterface;
use VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface;
use VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterfaceFactory;
use VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface;
use VinaiKopp\Kitchen\Model\ResourceModel\Hamburger\CollectionFactory as HamburgerCollectionFactory;
use VinaiKopp\Kitchen\Model\ResourceModel\Hamburger\Collection;

class HamburgerRepository implements HamburgerRepositoryInterface
{
    /**
     * @var HamburgerFactory
     */
    private $hamburgerFactory;

    /**
     * @var HamburgerCollectionFactory
     */
    private $hamburgerCollectionFactory;

    /**
     * @var HamburgerSearchResultInterfaceFactory
     */
    private $searchResultFactory;

    public function __construct(
        HamburgerFactory $hamburgerFactory,
        HamburgerCollectionFactory $hamburgerCollectionFactory,
        HamburgerSearchResultInterfaceFactory $hamburgerSearchResultInterfaceFactory
    ) {
        $this->hamburgerFactory = $hamburgerFactory;
        $this->hamburgerCollectionFactory = $hamburgerCollectionFactory;
        $this->searchResultFactory = $hamburgerSearchResultInterfaceFactory;
    }

    // ... getById, save and delete methods listed above ...

    public function getList(SearchCriteriaInterface $searchCriteria)
    {
        $collection = $this->collectionFactory->create();

        $this->addFiltersToCollection($searchCriteria, $collection);
        $this->addSortOrdersToCollection($searchCriteria, $collection);
        $this->addPagingToCollection($searchCriteria, $collection);

        $collection->load();

        return $this->buildSearchResult($searchCriteria, $collection);
    }

    private function addFiltersToCollection(SearchCriteriaInterface $searchCriteria, Collection $collection)
    {
        foreach ($searchCriteria->getFilterGroups() as $filterGroup) {
            $fields = $conditions = [];
            foreach ($filterGroup->getFilters() as $filter) {
                $fields[] = $filter->getField();
                $conditions[] = [$filter->getConditionType() => $filter->getValue()];
            }
            $collection->addFieldToFilter($fields, $conditions);
        }
    }

    private function addSortOrdersToCollection(SearchCriteriaInterface $searchCriteria, Collection $collection)
    {
        foreach ((array) $searchCriteria->getSortOrders() as $sortOrder) {
            $direction = $sortOrder->getDirection() == SortOrder::SORT_ASC ? 'asc' : 'desc';
            $collection->addOrder($sortOrder->getField(), $direction);
        }
    }

    private function addPagingToCollection(SearchCriteriaInterface $searchCriteria, Collection $collection)
    {
        $collection->setPageSize($searchCriteria->getPageSize());
        $collection->setCurPage($searchCriteria->getCurrentPage());
    }

    private function buildSearchResult(SearchCriteriaInterface $searchCriteria, Collection $collection)
    {
        $searchResults = $this->searchResultFactory->create();

        $searchResults->setSearchCriteria($searchCriteria);
        $searchResults->setItems($collection->getItems());
        $searchResults->setTotalCount($collection->getSize());

        return $searchResults;
    }
}

I filtri all'interno di a FilterGroupdevono essere combinati utilizzando un operatore OR .
Gruppi di filtri separati vengono combinati utilizzando l' operatore AND logico .

Uff
Questo è stato il più grande po 'di lavoro. Le altre implementazioni dell'interfaccia sono più semplici.

Il DTO

Magento inizialmente intendeva che gli sviluppatori implementassero il DTO come classi separate, distinte dal modello di entità.

Il team principale lo ha fatto solo per il modulo cliente ( \Magento\Customer\Api\Data\CustomerInterfaceè implementato da \Magento\Customer\Model\Data\Customer, non \Magento\Customer\Model\Customer).
In tutti gli altri casi il modello di entità implementa l'interfaccia DTO (ad esempio \Magento\Catalog\Api\Data\ProductInterfaceè implementato da \Magento\Catalog\Model\Product).

Ho chiesto ai membri del nucleo centrale di questo durante le conferenze, ma non ho avuto una risposta chiara su cosa debba essere considerato una buona pratica.
La mia impressione è che questa raccomandazione sia stata abbandonata. Sarebbe bello avere una dichiarazione ufficiale su questo però.

Per ora ho preso la decisione pragmatica di utilizzare il modello come implementazione dell'interfaccia DTO. Se ritieni che sia più pulito utilizzare un modello di dati separato, sentiti libero di farlo. Entrambi gli approcci funzionano bene nella pratica.

Se l'interfaccia DTO si estende a Magento\Framework\Api\ExtensibleDataInterface, il modello deve estendersi Magento\Framework\Model\AbstractExtensibleModel.
Se non ti interessa l'estensibilità, il modello può semplicemente continuare ad estendere la classe base del modello ORM Magento\Framework\Model\AbstractModel.

Poiché l'esempio si HamburgerInterfaceestende, il ExtensibleDataInterfacemodello di hamburger si estende AbstractExtensibleModel, come si può vedere qui:

<?php

namespace VinaiKopp\Kitchen\Model;

use Magento\Framework\Model\AbstractExtensibleModel;
use VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface;
use VinaiKopp\Kitchen\Api\Data\HamburgerInterface;

class Hamburger extends AbstractExtensibleModel implements HamburgerInterface
{
    const NAME = 'name';
    const INGREDIENTS = 'ingredients';
    const IMAGE_URLS = 'image_urls';

    protected function _construct()
    {
        $this->_init(ResourceModel\Hamburger::class);
    }

    public function getName()
    {
        return $this->_getData(self::NAME);
    }

    public function setName($name)
    {
        $this->setData(self::NAME, $name);
    }

    public function getIngredients()
    {
        return $this->_getData(self::INGREDIENTS);
    }

    public function setIngredients(array $ingredients)
    {
        $this->setData(self::INGREDIENTS, $ingredients);
    }

    public function getImageUrls()
    {
        $this->_getData(self::IMAGE_URLS);
    }

    public function setImageUrls(array $urls)
    {
        $this->setData(self::IMAGE_URLS, $urls);
    }

    public function getExtensionAttributes()
    {
        return $this->_getExtensionAttributes();
    }

    public function setExtensionAttributes(HamburgerExtensionInterface $extensionAttributes)
    {
        $this->_setExtensionAttributes($extensionAttributes);
    }
}

L'estrazione dei nomi delle proprietà in costanti consente di mantenerli in un unico posto. Possono essere utilizzati dalla coppia getter / setter e anche dallo script Setup che crea la tabella del database. Altrimenti non c'è alcun vantaggio nell'estrarli in costanti.

SearchResult

Il SearchResultsInterfaceè il più semplice dei tre interfacce per implementare, dal momento che può ereditare tutto quanto di funzionalità da una classe quadro.

<?php

namespace VinaiKopp\Kitchen\Model;

use Magento\Framework\Api\SearchResults;
use VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface;

class HamburgerSearchResult extends SearchResults implements HamburgerSearchResultInterface
{

}

Configurare le preferenze dell'ObjectManager

Anche se le implementazioni sono complete, non possiamo ancora utilizzare le interfacce come dipendenze di altre classi, poiché il gestore oggetti di Magento Framework non sa quali implementazioni usare. Dobbiamo aggiungere una etc/di.xmlconfigurazione per con le preferenze.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" type="VinaiKopp\Kitchen\Model\HamburgerRepository"/>
    <preference for="VinaiKopp\Kitchen\Api\Data\HamburgerInterface" type="VinaiKopp\Kitchen\Model\Hamburger"/>
    <preference for="VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface" type="VinaiKopp\Kitchen\Model\HamburgerSearchResult"/>
</config>

Come può il repository essere esposto come risorsa API?

Questa parte è davvero semplice, è la ricompensa per aver svolto tutto il lavoro creando le interfacce, le implementazioni e collegandole insieme.

Tutto quello che dobbiamo fare è creare un etc/webapi.xmlfile.

<?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
    <route method="GET" url="/V1/vinaikopp_hamburgers/:id">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="getById"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
    <route method="GET" url="/V1/vinaikopp_hamburgers">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="getList"/>
        <resources>
            <resource ref="anonymouns"/>
        </resources>
    </route>
    <route method="POST" url="/V1/vinaikopp_hamburgers">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="save"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
    <route method="PUT" url="/V1/vinaikopp_hamburgers">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="save"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
    <route method="DELETE" url="/V1/vinaikopp_hamburgers">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="delete"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
</routes>

Si noti che questa configurazione non solo consente l'utilizzo del repository come endpoint REST, ma espone anche i metodi come parte dell'API SOAP.

Nel primo percorso esempio <route method="GET" url="/V1/vinaikopp_hamburgers/:id">, il segnaposto :iddeve corrispondere al nome dell'argomento al metodo mappato, public function getById($id).
I due nomi devono corrispondere, ad esempio /V1/vinaikopp_hamburgers/:hamburgerIdnon funzionerebbe, poiché il nome della variabile dell'argomento del metodo è $id.

Per questo esempio ho impostato l'accessibilità su <resource ref="anonymous"/>. Ciò significa che la risorsa è esposta pubblicamente senza alcuna restrizione!
Per rendere una risorsa disponibile solo per un cliente connesso, utilizzare <resource ref="self"/>. In questo caso, la parola speciale menell'URL dell'endpoint della risorsa verrà utilizzata per popolare una variabile argomento $idcon l'ID del cliente attualmente connesso.
Dai un'occhiata al cliente Magento etc/webapi.xmle CustomerRepositoryInterfacese ne hai bisogno.

Infine, <resources>può anche essere utilizzato per limitare l'accesso a una risorsa a un account utente amministratore. Per fare ciò imposta <resource>ref su un identificatore definito in un etc/acl.xmlfile.
Ad esempio, <resource ref="Magento_Customer::manage"/>limiterebbe l'accesso a qualsiasi account amministratore che ha il privilegio di gestire i clienti.

Una query API di esempio che utilizza l'arricciatura potrebbe apparire così:

$ curl -X GET http://example.com/rest/V1/vinaikopp_hamburgers/123

Nota: scrivere questo è iniziato come una risposta a https://github.com/astorm/pestle/issues/195 Dai
un'occhiata al pestello , acquista Commercebug e diventa un patreon di @alanstorm


1
Grazie per questa ottima risposta. Scusa forse mi manca qualcosa, ma che senso ha avere un'interfaccia pulita per un'entità quando alla fine deve estendersi da AbstractModel che ha il metodo setData che significa che puoi aggiungere qualsiasi cosa all'oggetto indipendentemente dall'interfaccia?
LDusan,

Una classe può implementare un numero qualsiasi di interfacce e aggiungere anche metodi aggiuntivi. L'importante è che qualsiasi altra classe dipenda solo dai metodi di interfaccia e quindi non sia a conoscenza di nessuno degli altri. Ciò rende i dettagli di implementazione dei metodi non di interfaccia, che possono essere modificati in qualsiasi momento senza interrompere le classi esterne. Questa è l'idea alla base dell'inversione di dipendenza. Sia la classe che i client dipendono dall'interfaccia e non conoscono i dettagli dell'implementazione. Ciò chiarisce?
Vinai,

Grazie per la risposta, capisco cosa intendi. Il fatto è che setData è un metodo pubblico, quindi non sono sicuro che possa essere considerato come un dettaglio dell'implementazione. Se è pensato per essere usato come metodo pubblico, come possiamo essere sicuri che non cambierà nulla di esterno quando viene cambiato?
LDusan,

3
Chiedo scusa. Quello che stai descrivendo è un punto di vista comune. La meccanica delle dipendenze non è intuitiva e poiché PHP consente la chiamata di metodi che non fanno parte dell'interfaccia dipendente, e anche dal momento che non ha bisogno di essere compilata, rende il modo in cui le dipendenze funzionano ancora più sfocato e difficile da vedere chiaramente . Ciò può essere osservato anche nel core di Magento 2, dove ci sono molti posti in cui vengono chiamati metodi di implementazione che non fanno parte dell'interfaccia dipendente. Questi servono da cattivi esempi e rendono ancora più difficile ottenere una comprensione chiara e solida.
Vinai,


35

@Raphael presso Digital Pianism:

Fare riferimento alla seguente struttura del modulo di esempio:

app/
   code/
  |    Namespace/
  |   |    Custom/
  |   |   |    Api/
  |   |   |   |    CustomRepositoryInterface.php
  |   |   |   |    Data/
  |   |   |   |   |    CustomInterface.php
  |   |   |   |   |    CustomSearchResultsInterface.php
  |   |   |    etc/
  |   |   |   |    di.xml
  |   |   |   |    module.xml
  |   |   |    Model/
  |   |   |   |    Custom.php
  |   |   |   |    CustomRepository.php
  |   |   |   |    ResourceModel/
  |   |   |   |   |    Custom.php
  1. Creare l'interfaccia del repository (contratto di servizio)
    Namespace/Custom/Api/CustomRepositoryInterface.php: http://codepad.org/WognSKnH

  2. Crea SearchResultsInterface
    Namespace/Custom/Api/Data/CustomSearchResultsInterface.php: http://codepad.org/zcbi8X4Z

  3. Crea interfaccia personalizzata (contenitore dati)
    Namespace/Custom/Api/Data/CustomInterface.php: http://codepad.org/Ze53eT4o

  4. Crea CustomRepository (Concrete Repository)
    Namespace/Custom/Model/CustomRepository.php: http://codepad.org/KNt5QAGZ
    Questo è dove la "magia" accade. Tramite il costruttore DI, si passa al modello di risorsa / factory di raccolta per il modulo personalizzato; Per quanto riguarda il metodo di salvataggio CRUD in questo repository, a causa di CustomRepositoryInterface, è necessario passare un parametro di CustomInterface. Di.xml del modulo ha una preferenza per sostituire un'interfaccia di questo tipo con un modello di entità. Il modello di entità viene passato nel modello di risorsa e viene salvato.

  5. Impostare le preferenze in
    Namespace/Custom/etc/di.xml: http://codepad.org/KmcoOUeV

  6. Modello di entità che implementa l'interfaccia personalizzata (contenitore dati)
    Namespace/Custom/Model/Custom.php: http://codepad.org/xQiBU7p7 .

  7. Modello di risorsa
    Namespace/Custom/Model/ResourceModel/Custom.php: http://codepad.org/IOsxm9qW

Alcune cose da notare:

  • Diniego !!! Ho usato "Namespace" al posto del nome del fornitore personalizzato, nome dell'agenzia, ecc ... qualunque sia il nome utilizzato per raggruppare i moduli insieme ... l'uso effettivo di "Namespace" è del tutto non valida in PHP ... così il know che l'ho fatto per motivi di convenienza e che non penso che funzionerà, né lo consiglio in alcun modo.

  • @Ryan Street mi ha insegnato questo ... quindi non voglio prendermi tutto il merito

  • Modificare chiaramente l'implementazione del repository in base alle proprie esigenze

  • Implementate l'interazione con i vostri modelli di entità personalizzati / modelli di risorse / raccolte nel repository concreto ...

  • So che non ho affrontato tutti i metodi che hai elencato nella tua domanda, ma questo è un ottimo inizio e dovrebbe colmare il divario tra i documenti e l'implementazione effettiva.


Ryan, i metodi menzionati nei Contratti di servizio sono obbligatori per eventuali API di sapone personalizzate che creiamo, ad esempio save (), delete () ecc?
Sushivam,

Potresti darmi un'idea di come creare API di sapone personalizzate in Magento 2?
Sushivam,

@SachinS Sfortunatamente, non ho alcuna idea da offrire riguardo a SOAP. Non l'ho ancora esaminato, né l'ho ancora implementato. Il meglio che potrei suggerire sarebbe quello di aprire una nuova domanda qui a riguardo. Direi di controllare anche i documenti, ma purtroppo non è sempre il miglior modo di agire (potrebbero mancare). Puoi sempre dare un'occhiata alla base di codice principale o a un'estensione di terze parti e vedere se c'è qualche intuizione lì. In bocca al lupo! Se trovi la tua risposta potrebbe essere utile aggiungere il link qui. Grazie
ryanF il

Grazie per la risposta @ryan, comunque ho implementato il mio modulo usando REST, dato che è leggero rispetto a SOAP ... Se implemento lo stesso in SOAP,
pubblicherò

3
@ryanF Grazie per questa risposta molto utile. So che non dovrebbe essere il codice di lavoro copia / incolla, ma ecco alcuni errori di battitura a beneficio di altri che seguono. Nel repository, CustomSearchResultsInterfaceFactory dovrebbe essere CustomSearchResultsFactory. $ searchResults-> setCriteria dovrebbe essere $ searchResults-> setSearchCriteria. $ Dogana [] nel foreach dovrebbe essere $ dogana []. Penso che sia a questo proposito.
tetranz,

3

file completi di utilizzo dei contratti di assistenza

Custom / modulo / registration.php

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Custom_Module',
    __DIR__
);

../etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Custom_Module" setup_version="1.0.0" />
</config>

../Setup/InstallSchema.php

<?php
namespace Custom\Module\Setup;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\DB\Ddl\Table;
class InstallSchema implements InstallSchemaInterface {
    public function install( SchemaSetupInterface $setup, ModuleContextInterface $context ) {
        $installer = $setup;
        $installer->startSetup();
        $table = $installer->getConnection()->newTable(
            $installer->getTable( 'ad_shipping_quote' )
        )->addColumn(
            'entity_id',
            Table::TYPE_SMALLINT,
            null,
            [ 'identity' => true, 'nullable' => false, 'primary' => true ],
            'Post ID'
        )->addColumn(
            'product_id',
            Table::TYPE_SMALLINT,
            255,
            [ ],
            'Post ID'
        )
            ->addColumn(
            'customer_name',
            Table::TYPE_TEXT,
            255,
            [ 'nullable' => false ],
            'Post Title'
        )

            ->addColumn(
            'customer_email',
            Table::TYPE_TEXT,
            '2M',
            [ ],
            'Post Content'
        ) ->addColumn(
                'customer_comments',
                Table::TYPE_TEXT,
                255,
                [ 'nullable' => false ],
                'Post Title'
            )->addColumn(
                'date_added',
                Table::TYPE_TEXT,
                255,
                [ 'nullable' => false ],
                'Post Title'
            )->addColumn(
                'date_updated',
                Table::TYPE_TEXT,
                255,
                [ 'nullable' => false ],
                'Post Title'
            )
            ->setComment(
            'Ad Shipping Quote Table'
        );
        $installer->getConnection()->createTable( $table );
        $installer->endSetup();
    }
}

../etc/di.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Custom\Module\Api\ModelRepositoryInterface"
                type="Custom\Module\Model\ModelRepository" />
    <preference for="Custom\Module\Api\Data\ModelInterface"
                type="Custom\Module\Model\Model" />
    <preference for="Custom\Module\Api\Data\ModelSearchResultsInterface"
                type="Custom\Module\Model\ModelSearchResults" />
</config>

../etc/webapi.xml

  <?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">

    <route method="GET" url="/V1/model/:id">
        <service class="Custom\Module\Api\ModelRepositoryInterface" method="getById"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>


    <route method="GET" url="/V1/model">
        <service class="Custom\Module\Api\ModelRepositoryInterface" method="getList"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
</routes>

../Api/ModelRepositoryInterface.php

  <?php
namespace Custom\Module\Api;

use \Custom\Module\Api\Data\ModelInterface;
use \Magento\Framework\Api\SearchCriteriaInterface;

interface ModelRepositoryInterface
{
    /**
     * @api
     * @param \Custom\Module\Api\Data\ModelInterface $model
     * @return \Custom\Module\Api\Data\ModelInterface
     */
    public function save(ModelInterface $model);

    /**
     * @api
     * @param \Custom\Module\Api\Data\ModelInterface $model
     * @return \Custom\Module\Api\Data\ModelInterface
     */
    public function delete(ModelInterface $model);

    /**
     * @api
     * @param \Custom\Module\Api\Data\ModelInterface $id
     * @return void
     */
    public function deleteById($id);

    /**
     * @api
     * @param int $id
     * @return \Custom\Module\Api\Data\ModelInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function getById($id);

    /**
     * @api
     * @param \Magento\Framework\Api\SearchCriteriaInterface $criteria
     * @return \Custom\Module\Api\Data\ModelSearchResultsInterface
     */
    public function getList(SearchCriteriaInterface $criteria);
}

../Api/Data/ModelInterface.php

<?php
namespace Custom\Module\Api\Data;

interface ModelInterface
{
    /**
     * Return the Entity ID
     *
     * @return int
     */
    public function getEntityId();

    /**
     * Set Entity ID
     *
     * @param int $id
     * @return $this
     */
    public function setEntityId($id);

    /**
     * Return the Product ID associated with Quote
     *
     * @return int
     */
    public function getProductId();

    /**
     * Set the Product ID associated with Quote
     *
     * @param int $productId
     * @return $this
     */
    public function setProductId($productId);

    /**
     * Return the Customer Name
     *
     * @return string
     */
    public function getCustomerName();

    /**
     * Set the Customer Name
     *
     * @param string $customerName
     * @return $this
     */
    public function setCustomerName($customerName);

    /**
     * Return the Customer Email
     *
     * @return string
     */
    public function getCustomerEmail();

    /**
     * Set the Customer Email
     *
     * @param string $customerEmail
     * @return $this
     */
    public function setCustomerEmail($customerEmail);

    /**
     * Return the Customer Comments
     *
     * @return string
     */
    public function getCustomerComments();

    /**
     * Set the Customer Comments
     *
     * @param string $customerComments
     * @return $this
     */
    public function setCustomerComments($customerComments);

    /**
     * Return the Date and Time of record added
     *
     * @return string
     */
    public function getDateAdded();

    /**
     * Set the Date and Time of record added
     *
     * @param string $date
     * @return $this
     */
    public function setDateAdded($date);

    /**
     * Return the Date and Time of record updated
     *
     * @return string
     */
    public function getDateUpdated();

    /**
     * Set the Date and Time of record updated
     *
     * @param string $date
     * @return $this
     */
    public function setDateUpdated($date);
}

..Api / dati / ModelSearchResultsInterface.php

<?php

namespace Custom\Module\Api\Data;

use Magento\Framework\Api\SearchResultsInterface;

interface ModelSearchResultsInterface extends SearchResultsInterface
{
    /**
     * @return \Custom\Module\Api\Data\ModelInterface[]
     */
    public function getItems();

    /**
     * @param \Custom\Module\Api\Data\ModelInterface[] $items
     * @return $this
     */
    public function setItems(array $items);
}

../Model/Model.php

    <?php

namespace Custom\Module\Model;

use Custom\Module\Api\Data\ModelInterface;

class Model extends \Magento\Framework\Model\AbstractModel implements
    \Custom\Module\Api\Data\ModelInterface
{
    protected function _construct()
    {
        $this->_init('Custom\Module\Model\ResourceModel\Model');
    }

    /**
     * @inheritdoc
     */
    public function getEntityId()
    {
        return $this->_getData('entity_id');
    }

    /**
     * @inheritdoc
     */
    public function setEntityId($id)
    {
        $this->setData('entity_id', $id);
    }

    /**
     * @inheritdoc
     */
    public function getProductId()
    {
        return $this->_getData('product_id');
    }

    /**
     * @inheritdoc
     */
    public function setProductId($productId)
    {
        $this->setData('product_id', $productId);
    }

    /**
     * @inheritdoc
     */
    public function getCustomerName()
    {
        return $this->_getData('customer_name');
    }

    /**
     * @inheritdoc
     */
    public function setCustomerName($customerName)
    {
        $this->setData('customer_name', $customerName);
    }

    /**
     * @inheritdoc
     */
    public function getCustomerEmail()
    {
        return $this->_getData('customer_email');
    }

    /**
     * @inheritdoc
     */
    public function setCustomerEmail($customerEmail)
    {
        $this->setData('customer_email', $customerEmail);
    }

    /**
     * @inheritdoc
     */
    public function getCustomerComments()
    {
        return $this->_getData('customer_comments');
    }

    /**
     * @inheritdoc
     */
    public function setCustomerComments($customerComments)
    {
        $this->setData('customer_comments', $customerComments);
    }

    /**
     * @inheritdoc
     */
    public function getDateAdded()
    {
        return $this->_getData('date_added');
    }

    /**
     * @inheritdoc
     */
    public function setDateAdded($date)
    {
        $this->setData('date_added', $date);
    }

    /**
     * @inheritdoc
     */
    public function getDateUpdated()
    {
        return $this->_getData('date_updated');
    }

    /**
     * @inheritdoc
     */
    public function setDateUpdated($date)
    {
        $this->setData('date_updated', $date);
    }
}

../Model/ResourceModel/Model.php

<?php

namespace Custom\Module\Model\ResourceModel;

class Model extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
    protected $_idFieldName = 'entity_id';

    protected function _construct()
    {
        $this->_init('ad_shipping_quote','entity_id');
    }
}

../Model/ResourceModel/Model/Collection.php

<?php

namespace Custom\Module\Model\ResourceModel\Model;

class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
    protected $_idFieldName = 'entity_id';
    protected $_eventPrefix = 'ad_shipping_quote_collection';
    protected $_eventObject = 'quote_collection';

    protected function _construct()
    {
        $this->_init('Custom\Module\Model\Model', 'Custom\Module\Model\ResourceModel\Model');
    }
}

../Model/ModelRepository.php

 <?php
    namespace Custom\Module\Model;

    use \Custom\Module\Api\Data\ModelInterface;
    use \Custom\Module\Model\ResourceModel\Model as ObjectResourceModel;
    use \Magento\Framework\Api\SearchCriteriaInterface;
    use \Magento\Framework\Exception\CouldNotSaveException;
    use \Magento\Framework\Exception\NoSuchEntityException;
    use \Magento\Framework\Exception\CouldNotDeleteException;

    class ModelRepository implements \Custom\Module\Api\ModelRepositoryInterface
    {
        protected $objectFactory;

        protected $objectResourceModel;

        protected $collectionFactory;

        protected $searchResultsFactory;

        public function __construct(
            \Custom\Module\Model\ModelFactory $objectFactory,
            ObjectResourceModel $objectResourceModel,
            \Custom\Module\Model\ResourceModel\Model\CollectionFactory $collectionFactory,
            \Magento\Framework\Api\SearchResultsInterfaceFactory $searchResultsFactory
        ) {
            $this->objectFactory        = $objectFactory;
            $this->objectResourceModel  = $objectResourceModel;
            $this->collectionFactory    = $collectionFactory;
            $this->searchResultsFactory = $searchResultsFactory;
        }

        public function save(ModelInterface $object)
        {
            $name = $object->getCustomerName();
            $hasSpouse = $object->getSpouse();
            if ($hasSpouse == true) {
                $name = "Mrs. " . $name;
            } else {
                $name = "Miss. " . $name;
            }
            $object->setCustomerName($name);
            try {
                $this->objectResourceModel->save($object);
            } catch (\Exception $e) {
                throw new CouldNotSaveException(__($e->getMessage()));
            }
            return $object;
        }

        /**
         * @inheritdoc
         */
        public function getById($id)
        {
            $object = $this->objectFactory->create();
            $this->objectResourceModel->load($object, $id);
            if (!$object->getId()) {
                throw new NoSuchEntityException(__('Object with id "%1" does not exist.', $id));
            }
            return $object;
        }

        public function delete(ModelInterface $object)
        {
            try {
                $this->objectResourceModel->delete($object);
            } catch (\Exception $exception) {
                throw new CouldNotDeleteException(__($exception->getMessage()));
            }
            return true;
        }

        public function deleteById($id)
        {
            return $this->delete($this->getById($id));
        }

        /**
         * @inheritdoc
         */
        public function getList(SearchCriteriaInterface $criteria)
        {
            $searchResults = $this->searchResultsFactory->create();
            $searchResults->setSearchCriteria($criteria);
            $collection = $this->collectionFactory->create();
            foreach ($criteria->getFilterGroups() as $filterGroup) {
                $fields = [];
                $conditions = [];
                foreach ($filterGroup->getFilters() as $filter) {
                    $condition = $filter->getConditionType() ? $filter->getConditionType() : 'eq';
                    $fields[] = $filter->getField();
                    $conditions[] = [$condition => $filter->getValue()];
                }
                if ($fields) {
                    $collection->addFieldToFilter($fields, $conditions);
                }
            }
            $searchResults->setTotalCount($collection->getSize());
            $sortOrders = $criteria->getSortOrders();
            if ($sortOrders) {
                /** @var SortOrder $sortOrder */
                foreach ($sortOrders as $sortOrder) {
                    $collection->addOrder(
                        $sortOrder->getField(),
                        ($sortOrder->getDirection() == SortOrder::SORT_ASC) ? 'ASC' : 'DESC'
                    );
                }
            }
            $collection->setCurPage($criteria->getCurrentPage());
            $collection->setPageSize($criteria->getPageSize());
            $objects = [];
            foreach ($collection as $objectModel) {
                $objects[] = $objectModel;
            }
            $searchResults->setItems($objects);
            return $searchResults;
        }
    }

../Model/ModelSearchResults.php

namespace Custom\Module\Model;

use \Magento\Framework\Api\SearchResults;
use \Custom\Module\Api\Data\ModelSearchResultsInterface;


class ModelSearchResults extends SearchResults implements ModelSearchResultsInterface
{

}

../Controller/Index/Save.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Save extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelFactory;
    /**
     * @var
     */
    private $modelRepository;


    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelFactory $modelFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelFactory $modelFactory,
        \Custom\Module\Model\ModelRepository $modelRepository
) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelFactory = $modelFactory;
        $this->modelRepository = $modelRepository;
        return parent::__construct($context);


    }

    /**
     * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $data = [

            "product_id" => 201,
            "customer_name" => "Katrina",
            "customer_email" => "karina@kapoor.com",
            "spouse" => 1
        ];

        $obj = $this->modelFactory->create();
        $this->modelRepository->save($obj->addData($data)); // Service Contract


        //$obj->addData($data)->save(); // Model / Resource Model

        $this->resultFactory->create("raw");
    }
}

../Controller/Index/Getlist.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Getlist extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelFactory;
    /**
     * @var
     */
    private $modelRepository;
    /**
     * @var
     */
    private $searchCriteriaBuilder;


    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelRepository $modelRepository,
        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelRepository = $modelRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        return parent::__construct($context);
    }

    /**
     * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $_filter = $this->searchCriteriaBuilder
            ->addFilter("customer_name", "%na%", "like")->create();
        $list = $this->modelRepository->getList($_filter);
        $results = $list->getItems();
        foreach ($results as $result) {
            echo $result->getCustomerName() . "<br>";
        }




        $this->resultFactory->create("raw");
    }
}

../Controller/Index/Getbyid.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Getbyid extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelRepository;

    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelRepository $modelRepository

) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelRepository = $modelRepository;
        return parent::__construct($context);
    }

    public function execute()
    {

        $search = $this->modelRepository->getById(1);
        print_r($search->getData());

        $this->resultFactory->create("raw");
    }
}

../Controller/Index/Deletebyid.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Deletbyid extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelRepository;

    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelRepository $modelRepository

) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelRepository = $modelRepository;
        return parent::__construct($context);
    }

    public function execute()
    {

        $this->modelRepository->deleteById(1);

        $this->resultFactory->create("raw");
    }
}

../Controller/Index/Del.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Del extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelRepository;

    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelFactory $modelFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelFactory $modelFactory,
        \Custom\Module\Model\ModelRepository $modelRepository

) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelFactory = $modelFactory;
        $this->modelRepository = $modelRepository;
        return parent::__construct($context);
    }

    public function execute()
    {
        $obj = $this->modelFactory->create()->load(2);
         $this->modelRepository->delete($obj);

        $this->resultFactory->create("raw");
    }
}
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.