Ce n’est pas facile de se séparer des vieilles habitudes mais certaines doivent cependant être abandonnées. L’utilisation de Registry dans Magento 2 en fait partie. Nous allons voir dans cet article comment s’en passer grâce à des gestionnaires de persistances (Persistor) ou des classes partagées (shared).
L’utilisation de Registry
dans Magento 2 est un héritage de Magento 1. Cependant, elle est aujourd’hui considérée comme une mauvaise pratique. Pourquoi ? Principalement parce qu’elle va à l’encontre des principes d’injection de dépendances (DI) et rend le code plus difficile à tester et à maintenir.
Pourquoi éviter Registry ?
- Couplage fort : En utilisant
Registry
, vous introduisez une dépendance globale qui complexifie les tests unitaires. - Manque de clarté : Le passage de données via une « couche magique » réduit la transparence et nuit à la compréhension du code.
- Non recommandé : L’implémentation actuelle de
Registry
dans Magento 2 est obsolète et devrait être évitée pour des raisons de performance et de fiabilité.
Les alternatives
Utiliser un gestionnaire de persistances
Un gestionnaire de persistances (Persistor dans la langue de Mark Twain) permet de stocker et de récupérer des données temporairement, de manière isolée. Il est particulièrement utile pour des besoins spécifiques comme le stockage entre deux requêtes. Pour y arriver, on va utiliser le gestionnaire de session.
Pour des opérations génériques, vous pouvez utiliser \Magento\Framework\App\Request\DataPersistorInterface comme outil. Vous pouvez également développer le vôtre qui reprend ou pas l’interface \Magento\Framework\App\Request\DataPersistorInterface
Exemple minimaliste d’un Persistor :
namespace Vendor\Module\Model;
use Magento\Framework\Session\SessionManagerInterface;
class MyPersistor implements \Magento\Framework\App\Request\DataPersistorInterface
{
protected $session;
public function __construct(SessionManagerInterface $session)
{
$this->session = $session;
}
/**
* Enregistrer une donnée en session.
*/
public function set($key, $value)
{
$this->session->setData($key, $value);
}
/**
* Récupérer une donnée en session.
*/
public function get($key)
{
return $this->session->getData($key);
}
/**
* Effacer une donnée de la session.
*/
public function clear($key)
{
$this->session->unsetData($key);
}
public function setMyVariable($value)
{
$this->session->set('my_variable', $value);
}
}
PHPRecourir à des classes partagées (shared)
Exemple générique
Dans certains cas, l’utilisation de services partagés (via DI) est plus appropriée. Une classe marquée comme shared dans le di.xml
garantit une instance unique tout au long du cycle de vie du processus.
Configuration dans di.xml
:
<type name="Vendor\Module\Model\SharedService" shared="true" />
XMLExemple de classe :
namespace Vendor\Module\Model;
class SharedService
{
private $data = [];
public function setData($key, $value)
{
$this->data[$key] = $value;
}
public function getData($key)
{
return $this->data[$key] ?? null;
}
}
PHPExemple spécifique
Ensuite, il est possible de l’injecter dans n’importe quelle class pour pouvoir récupérer les données de l’objet partagé. Un exemple récent sur lequel j’ai travaillé est situé dans le projet Makegento d’Opengento. J’avais besoin d’utiliser les interfaces Input et Output de Symfony a différents endroits du code. J’ai créé un service pouvant contenir les objets dont j’avais besoin que j’ai appelé CommandIoProvider. Dans le fichier de déclarations des injections de dépendances (di.xml), j’ai déclaré le type comme shared. Enfin, je peux le peupler dans la commande et le récupérer dès que j’en ai besoin comme par exemple pour le choix de la base de données.
Dans le même projet, j’ai utilisé un type d’objet similaire pour garder en mémoire le module sur lequel l’utilisateur souhaite travailler mais que j’ai agrémenté avec quelques fonctions :
<?php
namespace Opengento\MakegentoCli\Service;
use Opengento\MakegentoCli\Service\Php\NamespaceGetter;
use Opengento\MakegentoCli\Utils\ConsoleModuleSelector;
use Opengento\MakegentoCli\Utils\StringTransformationTools;
/**
* Class CurrentModule
*
* This service is used to store the current module name and path
*
* @package Opengento\MakegentoCli\Service
*/
class CurrentModule
{
private string $moduleName = '';
private string $modulePath = '';
private string $moduleNameSnaked = '';
private string $defaultNamespace = '';
public function __construct(
private readonly NamespaceGetter $namespaceGetter,
private readonly StringTransformationTools $stringTransformationTools
)
{
}
public function setCurrentModule(string $selectedModule, string $modulePath): void
{
$this->moduleName = $selectedModule;
$this->modulePath = $modulePath;
$this->moduleNameSnaked = $this->stringTransformationTools->getSnakeCase(explode('_', $selectedModule)[1]);
}
public function getModuleName(): string
{
return $this->moduleName;
}
public function getModuleVendor(): string
{
return explode('_', $this->moduleName)[0];
}
public function getModuleNameWithoutVendor(): string
{
return explode('_', $this->moduleName)[1];
}
public function getModulePath(): string
{
return $this->modulePath;
}
public function getModuleNamespace(string $path = ''): string
{
if ($this->defaultNamespace === '') {
$this->defaultNamespace = $this->namespaceGetter->getNamespaceFromPath($this->modulePath, $this->moduleName);
}
return $this->namespaceGetter->getNamespace($this->modulePath, $path, $this->moduleName, $this->defaultNamespace);
}
public function getModuleNameSnakeCase(): string
{
return $this->moduleNameSnaked;
}
}
PHPConclusion
En fonction de vos besoins, le Registry peut être remplacé de différentes manières. Par contre, l’obsolescence est annoncée de longue date et personne ne pourra être surpris le jour où ça arrivera.
Laisser un commentaire
Vous devez vous connecter pour publier un commentaire.