Je voudrais donner un peu plus de détails en plus de l'excellente réponse de @ryanF.
J'aimerais résumer les raisons d'ajouter un référentiel pour les entités personnalisées, de donner des exemples sur la manière de le faire et d'expliquer également comment exposer ces méthodes de référentiel dans le cadre de l'API Web.
Avertissement: je décris seulement une approche pragmatique de la manière de procéder pour les modules tiers - les équipes principales ont leurs propres normes qu’elles respectent (ou non).
En général, l'objectif d'un référentiel est de masquer la logique liée au stockage.
Un client d'un référentiel ne doit pas se soucier de savoir si l'entité retournée est conservée en mémoire dans un tableau, est extraite d'une base de données MySQL, extraite d'une API distante ou d'un fichier.
Je suppose que l'équipe principale de Magento a agi de la sorte pour pouvoir changer ou remplacer l'ORM à l'avenir. Dans Magento, l'ORM comprend actuellement les modèles, les modèles de ressources et les collections.
Si un module tiers utilise uniquement les référentiels, Magento peut modifier comment et où les données sont stockées et le module continuera à fonctionner malgré ces profonds changements.
Référentiels ont généralement des méthodes telles que findById()
, findByName()
, put()
ou remove()
.
Dans ces Magento communément sont appelés getbyId()
, save()
et delete()
, même pas prétendre qu'ils font quoi que ce soit d' autre que les opérations CRUD DB.
Les méthodes de référentiel Magento 2 peuvent facilement être exposées en tant que ressources API, ce qui les rend très utiles pour les intégrations avec des systèmes tiers ou les instances sans tête de Magento.
"Dois-je ajouter un référentiel pour mon entité personnalisée?".
Comme toujours, la réponse est
"Ça dépend".
En résumé, si vos entités seront utilisées par d'autres modules, alors oui, vous voudrez probablement ajouter un référentiel.
Il existe un autre facteur qui entre en ligne de compte: dans Magento 2, les référentiels peuvent facilement être exposés sous forme d’API Web - c’est-à-dire REST et SOAP - ressources.
Si cela vous intéresse, en raison d’intégrations système tierces ou d’une configuration Magento sans tête, alors oui, vous souhaitez probablement ajouter un référentiel pour votre entité.
Comment ajouter un référentiel pour mon entité personnalisée?
Supposons que vous souhaitiez exposer votre entité dans le cadre de l'API REST. Si ce n'est pas le cas, vous pouvez ignorer la partie suivante sur la création des interfaces et aller directement à "Créer l'implémentation du référentiel et du modèle de données" ci-dessous.
Créer le référentiel et les interfaces de modèle de données
Créez les dossiers Api/Data/
dans votre module. Ce n'est que convention, vous pouvez utiliser un emplacement différent, mais vous ne devriez pas.
Le référentiel va dans le Api/
dossier. Le Data/
sous-répertoire est pour plus tard.
Dans Api/
, créez une interface PHP avec les méthodes que vous souhaitez exposer. Selon les conventions de Magento 2, tous les noms d'interface se terminent par le suffixe Interface
.
Par exemple, pour une Hamburger
entité, je créerais l'interface Api/HamburgerRepositoryInterface
.
Créer l'interface de référentiel
Les référentiels Magento 2 font partie de la logique de domaine d'un module. Cela signifie qu’il n’existe pas d’ensemble de méthodes qu’un référentiel doit implémenter.
Cela dépend entièrement de l'objectif du module.
Cependant, dans la pratique, tous les référentiels sont assez similaires. Ce sont des wrappers pour la fonctionnalité CRUD.
La plupart ont des méthodes getById
, save
, delete
et getList
.
Il peut y en avoir davantage, par exemple, CustomerRepository
une méthode get
, qui récupère un client par courrier électronique, getById
est utilisée pour extraire un client par ID d'entité.
Voici un exemple d'interface de référentiel pour une 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);
}
Important! Ici être timesinks!
Il existe quelques pièges difficiles à résoudre si vous vous trompez:
- NE PAS utiliser PHP7 types d'argument scalaire ou les types de retour si vous voulez accrocher ceci dans l'API REST!
- Ajoutez des annotations PHPDoc pour tous les arguments et le type de retour à toutes les méthodes!
- Utilisez des noms de classe entièrement qualifiés dans le bloc PHPDoc!
Les annotations sont analysées par le framework Magento pour déterminer comment convertir les données en JSON ou XML. Les importations de classe (c'est-à-dire les use
instructions) ne sont pas appliquées!
Chaque méthode doit avoir une annotation avec tous les types d'argument et le type de retour. Même si une méthode ne prend aucun argument et ne renvoie rien, elle doit avoir l'annotation suivante:
/**
* @return void
*/
Types scalaires ( string
, int
, float
et bool
) doivent également être spécifié, à la fois pour les arguments et en tant que valeur de retour.
Notez que dans l'exemple ci-dessus, les annotations des méthodes renvoyant des objets sont également spécifiées en tant qu'interfaces.
Les interfaces de type de retour sont toutes dans l' Api\Data
espace de noms / répertoire.
Cela indique qu'ils ne contiennent aucune logique métier. Ce sont simplement des sacs de données.
Nous devons ensuite créer ces interfaces.
Créer l'interface DTO
Je pense que Magento appelle ces interfaces "modèles de données", un nom que je n’aime pas du tout.
Ce type de classe est communément appelé objet de transfert de données ou DTO .
Ces classes DTO ne disposent que de getters et de setters pour toutes leurs propriétés.
La raison pour laquelle je préfère utiliser DTO par rapport à un modèle de données est qu'il est moins facile de confondre avec les modèles de données ORM, les modèles de ressources ou les modèles de vue ... trop de choses sont déjà des modèles dans Magento.
Les mêmes restrictions concernant le typage PHP7 qui s'appliquent aux référentiels s'appliquent également aux DTO.
De plus, chaque méthode doit avoir une annotation avec tous les types d'argument et le type de retour.
<?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);
}
Si une méthode récupère ou retourne un tableau, le type des éléments du tableau doit être spécifié dans l'annotation PHPDoc, suivi d'un crochet entre deux crochets []
.
Cela vaut tant pour les valeurs scalaires (par exemple int[]
) que pour les objets (par exemple IngredientInterface[]
).
Notez que j'utilise Api\Data\IngredientInterface
un exemple pour une méthode renvoyant un tableau d'objets, je ne vais pas ajouter le code des ingrédients à cette publication difficile.
ExtensibleDataInterface?
Dans l'exemple ci-dessus, la HamburgerInterface
étend la ExtensibleDataInterface
.
Techniquement, cela n’est requis que si vous voulez que d’autres modules puissent ajouter des attributs à votre entité.
Si c'est le cas, vous devez également ajouter une autre paire de getter / setter, appelée par convention getExtensionAttributes()
et setExtensionAttributes()
.
La dénomination du type de retour de cette méthode est très importante!
Le framework Magento 2 générera l'interface, l'implémentation et l'usine pour l'implémentation si vous les nommez juste. Les détails de ces mécanismes sont hors de portée de ce post si.
Sachez simplement que si l'interface de l'objet que vous souhaitez rendre extensible est appelée \VinaiKopp\Kitchen\Api\Data\HamburgerInterface
, le type d'attribut d'extension doit être \VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface
. Donc, le mot Extension
doit être inséré après le nom de l'entité, juste avant le Interface
suffixe.
Si vous ne souhaitez pas que votre entité soit extensible, l'interface de DTO n'a pas besoin d'étendre une autre interface et les méthodes getExtensionAttributes()
et setExtensionAttributes()
peuvent être omises.
Assez parlé de l'interface DTO pour l'instant, il est temps de revenir à l'interface du référentiel.
Le type de retour getList () SearchResults
La méthode repository getList
renvoie encore un autre type, à savoir une SearchResultsInterface
instance.
La méthode getList
pourrait bien sûr simplement renvoyer un tableau d'objets correspondant à l'objet spécifié SearchCriteria
, mais le retour d'une SearchResults
instance permet d'ajouter des métadonnées utiles aux valeurs renvoyées.
Vous pouvez voir comment cela fonctionne ci-dessous dans l' getList()
implémentation de la méthode de référentiel .
Voici l'exemple d'interface de résultat de recherche hamburger:
<?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);
}
Toute cette interface ne remplace les types des deux méthodes getItems()
et setItems()
de l'interface parent.
Résumé des interfaces
Nous avons maintenant les interfaces suivantes:
\VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface
\VinaiKopp\Kitchen\Api\Data\HamburgerInterface
\VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface
Le référentiel n’étend rien,
le HamburgerInterface
s'étend \Magento\Framework\Api\ExtensibleDataInterface
,
et le HamburgerSearchResultInterface
étend \Magento\Framework\Api\SearchResultsInterface
.
Créer les implémentations du référentiel et du modèle de données
L'étape suivante consiste à créer les implémentations des trois interfaces.
Le référentiel
Essentiellement, le référentiel utilise l'ORM pour effectuer son travail.
Le getById()
, save()
et les delete()
méthodes sont assez simples.
Le HamburgerFactory
est injecté dans le référentiel en tant qu'argument constructeur, comme on peut le voir un peu plus loin.
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);
}
Passons maintenant à la partie la plus intéressante d’un référentiel, la getList()
méthode.
La getList()
méthode doit traduire les SerachCriteria
conditions en appels de méthodes sur la collection.
La difficulté consiste à définir correctement les conditions AND
et OR
pour les filtres, d’autant plus que la syntaxe de définition des conditions de la collection diffère selon qu’il s’agit d’une entité EAV ou d’une table à plat.
Dans la plupart des cas, getList()
peuvent être implémentés comme illustré dans l'exemple ci-dessous.
<?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;
}
}
Les filtres dans un FilterGroup
doivent être combinés à l'aide d'un opérateur OU .
Des groupes de filtres distincts sont combinés à l'aide de l' opérateur logique AND .
Ouf
C'était le plus gros travail. Les autres implémentations d'interface sont plus simples.
Le DTO
Magento avait initialement prévu que les développeurs implémentent le DTO en tant que classes distinctes, distinctes du modèle d'entité.
Cependant, l’équipe principale n’a fait cela que pour le module client (elle \Magento\Customer\Api\Data\CustomerInterface
est mise en œuvre par \Magento\Customer\Model\Data\Customer
, pas \Magento\Customer\Model\Customer
).
Dans tous les autres cas, le modèle d'entité implémente l'interface DTO (par exemple, \Magento\Catalog\Api\Data\ProductInterface
est implémenté par \Magento\Catalog\Model\Product
).
J'ai posé des questions à ce sujet aux membres de l'équipe principale lors de conférences, mais je n'ai pas reçu de réponse claire sur ce qui doit être considéré comme une bonne pratique.
J'ai l'impression que cette recommandation a été abandonnée. Ce serait bien d’obtenir une déclaration officielle à ce sujet.
Pour le moment, j'ai pris la décision pragmatique d'utiliser le modèle comme implémentation d'interface DTO. Si vous estimez qu'il est préférable d'utiliser un modèle de données distinct, n'hésitez pas à le faire. Les deux approches fonctionnent bien dans la pratique.
Si l’interface DTO étend la Magento\Framework\Api\ExtensibleDataInterface
, le modèle doit s’étendre Magento\Framework\Model\AbstractExtensibleModel
.
Si l'extensibilité ne vous intéresse pas, le modèle peut simplement continuer à étendre la classe de base du modèle ORM Magento\Framework\Model\AbstractModel
.
Comme l'exemple HamburgerInterface
s'étend, le ExtensibleDataInterface
modèle hamburger étend le AbstractExtensibleModel
, comme on peut le voir ici:
<?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);
}
}
Extraire les noms de propriétés en constantes permet de les conserver au même endroit. Ils peuvent être utilisés par la paire getter / setter et également par le script d'installation qui crée la table de base de données. Sinon, il ne sert à rien de les extraire en constantes.
Le résultat de recherche
La SearchResultsInterface
plus simple des trois interfaces à implémenter, car elle peut hériter de toutes ses fonctionnalités d'une classe d'infrastructure.
<?php
namespace VinaiKopp\Kitchen\Model;
use Magento\Framework\Api\SearchResults;
use VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface;
class HamburgerSearchResult extends SearchResults implements HamburgerSearchResultInterface
{
}
Configurer les préférences d'ObjectManager
Même si les implémentations sont terminées, nous ne pouvons toujours pas utiliser les interfaces comme dépendances d'autres classes, car le gestionnaire d'objets de Magento Framework ne sait pas quelles implémentations utiliser. Nous devons ajouter une etc/di.xml
configuration pour avec les préférences.
<?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>
Comment le référentiel peut-il être exposé en tant que ressource API?
Cette partie est très simple, c'est la récompense d'avoir parcouru tout le travail de création d'interfaces, d'implémentations et de câblage.
Tout ce que nous avons à faire est de créer un etc/webapi.xml
fichier.
<?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>
Notez que cette configuration permet non seulement d'utiliser le référentiel en tant que points de terminaison REST, mais qu'elle expose également les méthodes dans le cadre de l'API SOAP.
Dans le premier exemple de route, <route method="GET" url="/V1/vinaikopp_hamburgers/:id">
l'espace réservé :id
doit correspondre au nom de l'argument à la méthode cartographié, public function getById($id)
.
Les deux noms doivent correspondre, par exemple /V1/vinaikopp_hamburgers/:hamburgerId
, ne fonctionneraient pas, car le nom de variable d'argument de méthode est $id
.
Pour cet exemple, j'ai défini l'accessibilité sur <resource ref="anonymous"/>
. Cela signifie que la ressource est exposée publiquement sans aucune restriction!
Pour qu'une ressource ne soit disponible que pour un client connecté, utilisez <resource ref="self"/>
. Dans ce cas, le mot spécial me
dans l'URL du noeud final de la ressource sera utilisé pour renseigner une variable d'argument $id
avec l'ID du client actuellement connecté.
Regardez le client Magento etc/webapi.xml
et CustomerRepositoryInterface
si vous en avez besoin.
Enfin, le <resources>
peut également être utilisé pour restreindre l'accès à une ressource à un compte d'utilisateur admin. Pour ce faire, définissez la <resource>
référence sur un identifiant défini dans un etc/acl.xml
fichier.
Par exemple, <resource ref="Magento_Customer::manage"/>
limiterait l'accès à tout compte administrateur disposant du privilège de gérer des clients.
Un exemple de requête d'API utilisant curl pourrait ressembler à ceci:
$ curl -X GET http://example.com/rest/V1/vinaikopp_hamburgers/123
Remarque: l'écriture de ceci a commencé comme une réponse à https://github.com/astorm/pestle/issues/195
Découvrez un pilon , achetez Commercebug et devenez un patron de @alanstorm
@Raphael at Digital Pianism:
Veuillez vous référer à l'exemple de structure de module suivant:
Créer une interface de référentiel (contrat de service)
Namespace/Custom/Api/CustomRepositoryInterface.php
: http://codepad.org/WognSKnHCréez SearchResultsInterface
Namespace/Custom/Api/Data/CustomSearchResultsInterface.php
: http://codepad.org/zcbi8X4ZCréer une interface personnalisée (conteneur de données)
Namespace/Custom/Api/Data/CustomInterface.php
: http://codepad.org/Ze53eT4oCréer un référentiel personnalisé (référentiel concret)
Namespace/Custom/Model/CustomRepository.php
: http://codepad.org/KNt5QAGZC'est ici que se passe la "magie". Via le constructeur DI, vous transmettez la fabrique de modèles / collections de ressources pour votre module personnalisé; En ce qui concerne la méthode de sauvegarde CRUD dans ce référentiel, en raison de votre CustomRepositoryInterface, vous devez transmettre un paramètre de CustomInterface. Le di.xml de votre module a une préférence pour remplacer une interface de ce type par un modèle d'entité. Le modèle d'entité est transmis au modèle de ressource et est enregistré.
Définir la préférence dans
Namespace/Custom/etc/di.xml
: http://codepad.org/KmcoOUeVModèle d'entité implémentant une interface personnalisée (conteneur de données)
Namespace/Custom/Model/Custom.php
: http://codepad.org/xQiBU7p7 .Modèle de ressource
Namespace/Custom/Model/ResourceModel/Custom.php
: http://codepad.org/IOsxm9qWQuelques points à noter:
Avertissement!!! J'ai utilisé "Namespace" à la place de votre nom de fournisseur personnalisé, nom de l'agence, etc ... quel que soit le nom que vous utilisez pour regrouper vos modules ... l'utilisation réelle de "Namespace" n'est pas valide dans Php ... alors sachez que je l'ai fait pour des raisons de commodité, et que je ne pense pas que cela fonctionnera, et je ne le suggère en aucune manière.
@Ryan Street m'a appris cela ... alors je ne veux pas prendre tout le crédit
Modifiez clairement la mise en œuvre du référentiel en fonction de vos besoins
Vous implémentez l'interaction avec vos modèles d'entités personnalisés / modèles de ressources / collections dans le référentiel concret ...
Je sais que je n’ai pas abordé toutes les méthodes que vous avez énumérées dans votre question, mais c’est un bon début et il convient de combler le fossé entre la documentation et la mise en œuvre réelle.
la source
dossiers complets d'utilisation des contrats de service
Personnalisé / Module / registration.php
../etc/module.xml
../Setup/InstallSchema.php
../etc/di.xml
../etc/webapi.xml
../Api/ModelRepositoryInterface.php
../Api/Data/ModelInterface.php
..Api / Data / ModelSearchResultsInterface.php
../Model/Model.php
../Model/ResourceModel/Model.php
../Model/ResourceModel/Model/Collection.php
../Model/ModelRepository.php
../Model/ModelSearchResults.php
../Controller/Index/Save.php
../Controller/Index/Getlist.php
../Controller/Index/Getbyid.php
../Controller/Index/Deletebyid.php
../Controller/Index/Del.php
la source