Design patterns dans Magento - factory, singleton et registry

applications internet utilitaires

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com
Entre le monde du PHP et celui d'autre langages il y a encore un fosse. Surtout en ce qui concerne les règles du codage. Très laxiste et parfois incohérent entre de différents projets, le PHP a encore un grand pas à franchir. Mais malgré cet environnement défavorable, l'un des acteurs PHP, Magento, a donné un exemple comment intégrer de bonnes pratiques du codage dans une application PHP.

A travers cet article on verra l'utilisation de quelques design patterns dans Magento. Ici on se focalisera sur 3 patrons de conception : factory, singleton et registry. Les autres seront présentés dans les articles suivants.

Design pattern : factory
Ce modèle de conception s'occupe de créer des objets. Il permet de garder une meilleure évolutivité de l'architecture avec, par exemple, l'ajout de nouveaux objets.

Afin d'illustrer ce principe, on peut se baser sur l'analogie avec une usine qui fabrique des produits en fer et en bois. Les deux vont avoir de méthodes de fabrication différentes. Mais ils vont quand même garder les mêmes étapes de production. Dans le code cela se présentera ainsi :


interface Product
{
public function setComponents($components);
public function assemblyComponents();
}

class IronProduct implements Product
{
public function setComponents($components)
{
$this->components = $components;
}
public function assemblyComponents()
{

}
}

class WoodProduct implements Product
{
public function setComponents($components)
{
$this->components = $components;
}
public function assemblyComponents()
{

}
}

class ProductFactory
{
public static function startProduction($type)
{
if(class_exists($type)) return new $type();
throw new \Exception("Product class was not found");
}
}

$product = ProductFactory::startProduction("IronProduct");
var_dump($product);


Dans Magento la fabrique est utilisée, par exemple, dans l'initialisation des modèles, helpers et blocks. Cette solution a été implémentée dans le but de permettre aux développeurs de surcharger les classes.

Toute la configuration du Magento est contenu dans un fichier XML. Cela facilite l'héritage des classes issus du package Mage dans le développement des modules tiers. Il suffit alors de mettre cette définition dans le fichier de configuration de son module :

<catalog>
<rewrite>
<product>Devel_Mymod_Model_Mymodproduct</product>
</rewrite>
</catalog>

Elle indique au Magento que la classe product sera surchargée par la classe Mymodproduct.

Design pattern : singleton
Un autre design pattern utilisé dans Magento, singleton, sert surtout à limiter le nombre d'initialisations d'une classe à un objet. L'accès à cet objet doit être global.

On peut illustrer ce patron avec le cas d'une classe qui gère les utilisateurs connectés. Imaginons la situation où l'on veut préciser l'age de notre utilisateur. Mais entre l'initialisation de la classe et l'appel de la méthode finale setAge() on va faire d'autres opérations. Pour se servir toujours du même objet, on utilisera singleton :


class User
{
private static $instance = null;
protected $age = 0;

public static function getInstance()
{
if(self::$instance == null) return new User;
return self::$instance;
}

public function setAge($age)
{
$this->age = $age;
}

public function getAge()
{
return $this->age;
}

}

$user = User::getInstance();
echo $user->getAge();
echo "
";
// ... do some other stuff
$user->setAge(29);
echo $user->getAge();
echo "
";


Magento utilise singleton pour gérer les sessions et garder cohérence des données qu'elles stockent tout au long de l'action.

Design pattern : registry
Ce patron de conception ressemble beaucoup aux variables globales. Accessible de partout, il aide à protéger contre sa surcharge. On peut le comparer aux $_GLOBALS du monde PHP qui contiendrait les objets à la portée globale. Cependant, cette approche a quelques limitations (comme par exemple l'absence de la gestion des exceptions ou l'impossibilité d'adapter l'interface des objets sans modifier l'objet en lui-même).

Voici l'exemple d'un registre qui contient quelques instances et valeurs :

class Registry
{
private static $registred = array();
private static $request = null;
private static $response = null;

public static function setValue($key, $value)
{
self::$registred[$key] = $value;
}
public static function getValue($key)
{
return self::$registred[$key];
}
/**
* Request
*/
public static function setRequest(Request $request)
{
self::$request = $request;
}
public static function getRequest()
{
if(self::$request == null) throw new \Exception("Request was not found");
return self::$request;
}
/**
* Response
*/
public static function setResponse(Response $response)
{
self::$response = $response;
}
public static function getResponse()
{
if(self::$response == null) throw new \Exception("Response was not found");
return self::$response;
}

}

class Request
{
// empty class, just for the use case
}

try
{
Registry::setValue("test", "Lorem ipsum");
Registry::setRequest(new Request);
var_dump(Registry::getRequest());
echo "
";
var_dump(Registry::getResponse());
echo "
";
}
catch(\Exception $e)
{
echo $e->getMessage();
echo "
";
}
echo Registry::getValue("test");


Sous Magento, registry est utilisé pour faciliter la communication entre les contrôlleurs et les vues. Dans le contrôlleur on peut appeler Mage::register("key", "value"); afin de récupérer cette information dans la classe du block (Mage::registry("key")). Cela évite des problèmes de redondance avec la méthode traditionnelle ($this->getLayout()->getBlock('content')->setKey($value)) dont l'usage est limité à un seul block.

Les trois premiers design patterns sous Magento ont été preséntés à travers cet article. Cependant, ce système e-commerce en contient beaucoup plus. L'occasion de les présenter sera la 2e partie de l'article au sujet des design patterns sous Magento.
Bartosz KONIECZNY 24-04-2012 18:40 applications web
Moi

Développeur d'applications Internet et journaliste passionné par l'adjectif français. Un aigle polonais orienté vers la progression, volant très haut et écoutant du zouk après les matches du foot français.

Vous appréciez mon travail ?

Pour contribuer au développement de ce site, ou pour remercier pour des articles rédigés, vous pouvez faire un don.

Un conseil Zend Framework

Comment faciliter le travail entre notre application et l'Ajax ?

L'un des moyens est l'utilisation du ContextSwitch. Il permet de définir le type de réponse renvoyé.