• Magento
  • Développement

La recette pour un bon modèle de données Magento 2- partie 1

kevin_2234efd45f
Kevin Weyhaupt, Développeur back-end
Le 22 mars 2018
cooking_magento_1_b74e280d27
  • ecommerce

Lecture :11 minutes

EDIT : Le contenu de cet article peut ne plus être d'actualité suite aux nouvelles bonnes pratiques suggérées par Magento.

Intro

 

Chaque début d’année peut se résumer par une succession de bonnes recettes bien gourmandes, malgrés toutes les résolutions autour des régimes et de la perte de poids. Après la galette des rois, les crêpes de la chandeleur et les beignets, je vous propose une recette afin de réaliser de bons modèles de données pour vos futurs projets sous Magento 2. S'agissant d'une grosse recette, elle se déroulera en plusieurs étapes. En voici la liste d’ingrédients et de préparations à réaliser :



Pour cet article je vais utiliser les deux entités suivantes, « Student » et « Teacher » afin d’avoir une table associative (étudiant à plusieurs professeurs et inversement). Avant tout je tiens à préciser deux choses. Premièrement, les exemples de code n’ont pas de PHP Doc pour un gain de place. Mais bien évidemment c’est une pratique que tout bon développeur doit mettre en place. (Le code complet et commenté est disponible ici https://github.com/blackbird-agency/magento-2-data-model-sample).Et deuxièmement cet article ne concerne que les modèles de données “classiques” (c’est à dire avec différentes entitées et des relations entre elles) et non le modèle Entity Attribute Value (EAV).
schéma tables

Partie 1: Préparation des principaux ingrédients

Un beau morceau du Service Contract …

Avant toute chose qu’est-ce que le « Service Contract » ? Le « Service Contract » est le contrat entre le développeur et le code de l’application. Pour le définir simplement, c’est un ensemble d’interfaces qui, par exemple, va permettre de définir l’ensemble des services et structures des différents modèles de données... Pour notre recette nous en utiliserons une bonne partie, sans pour autant tout y voir. (Probablement le sujet d’un futur article).

Définition de nos modèles

Tout d’abord les interfaces du « Service Contract » se définissent dans un dossier nommé « Api » à la racine de notre module concerné. Et dans ce même dossier nous allons créer un dossier « Data » où nous y mettrons nos interfaces faisant référence à chacun de nos modèles avec les accesseurs et les propriétés statiques tels que les noms de champs dans la base afin de pouvoir les modifier simplement, sans avoir à parcourir tout notre code.
Ici le tag @api de la PHPDoc indique que la classe fait bien partie de l’api et qu’on peut ainsi lui faire confiance.

<?php
namespace MyVendor\MyModule\Api\Data;
/**
* Student Interface
* @api
*/
interface StudentInterface
{
  const ID = 'student_id';
  const NAME = 'name';
  public function getId();
  public function getName();
  public function setId($id);
  public function setName($name);
}


La réalisation du modèle

Une fois nos interfaces du service contract prêtes, nous pouvons les implémenter dans MyVendor\MyModule\Model.

Implémentation des modèles

Le but ici est de simplement implémenter les accesseurs en utilisant les propriétés de classe définies dans les interfaces. Notre modèle va hériter d’Abstract Model pour plusieurs raisons :

  • Faire appel à la méthode “_init” dans le constructeur afin de faire directement le lien avec le “resource model” et ainsi faire la relation entre notre objet et la base de données. (Le “resource model” sera expliqué dans la seconde partie)
  • Gérer les attributs de notre objet avec par exemple :
    • setData/getData: permet de définir ou récupérer la valeur d’un attribut.
    • setOrigData/getOrigData: permet de récupérer les données de notre objet au moment de son instanciation, c’est à dire les données initiales provenant de la base de données.
    • --Et ainsi Magento va uniquement mettre à jour les données qui ont été modifiées.
  • Utiliser les méthodes magiques, c’est à dire les méthodes commencant par set, get, uns ou encore has + le nom de l’attribut (en camelCase) pour gérer un attribut, si l’objet lui même n’a pas encore de méthode pour y accéder.

Dans le cas où notre objet est plutôt simpliste et n’est utile que pour de la manipulation de données (et éventuellement gérer la mise à jour dans la base en passant par des services) il est plus intéressant d’hériter d’AbstractSimpleObject car il est plus léger en offrant uniquement les méthodes get/setData et __toArray. Si en plus d’un objet simple nous souhaitons utiliser les collections, sans pour autant hériter du AbstractModel, nous pouvons utiliser le DataObject.

<?php
namespace MyVendor\MyModule\Model;
use Magento\Framework\Model\AbstractModel;
use MyVendor\MyModule\Api\Data\StudentInterface;
class Student extends AbstractModel implements StudentInterface
{
protected function _construct()
{
    parent::construct();
$this->_init(\MyVendor\MyModule\Model\ResourceModel\Student::class)
;
}
  public function getId()
  {
    return $this->_getData(self::ID);
  }
 
  public function getName()
  {
    return $this->_getData(self::NAME);
  }

  public function setId($id)
  {
    return $this->setData(self::ID, $id);
  }

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


L’assaisonnement à la sauce « Injection de dépendance »

L’injection de dépendance est un principe utilisé dans plusieurs frameworks. Celui ci permet de définir les dépendances entre modules et se charge de l’instanciation et de l’injection des paramètres q’on lui passe.
Magento 2 fonctionnant avec ce principe, l'intérêt ici est de faire le lien entre nos interfaces du « service contract » avec la balise « preference ». Cela va donc permettre ici de dire que dès qu’on appelle notre interface “Student”, de l’API, ce sera la classe concrète du modèle qui sera utilisée. Donc pour respecter les bonnes pratiques, si vous souhaitez utiliser le modèle il faudra passer par l’interface de l’API. 

Cette bonne pratique facilite la maintenance du code mais améliore aussi sa flexibilité.

<?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="MyVendor\MyModule\Api\Data\StudentInterface" 
type="MyVendor\MyModule\Model\Student"/>
  <preference for="MyVendor\MyModule\Api\StudentRepositoryInterface" 
type="MyVendor\MyModule\Model\StudentRepository"/>
</config>

Bien évidemment l’injection de dépendance ne se limite pas uniquement à ce petit morceau de code. Plus vous avancerez dans cette recette, plus vous en saurez !  

La première partie est désormais finie. Une recette a souvent besoin de laisser un peu reposer les préparations, allez prendre un petit café et revenez vite pour la seconde partie : Apporter de la saveur. Car c’est bien beau d’avoir des objets mais pour l’instant ils sont encore un peu fades non ?


>>> Lire la Partie 2 : Apporter de la saveur.

Nos articles

Découvrir aussi

Abonnez-vous au blog pour ne rien louper