AOP

A voir en préambule :

Comment utiliser l’AOP dans it.rocks

Vous pouvez utiliser l’AOP pour intervenir dans le comportement des modules logiciels existant en exécutant du code :

  • avant l’exécution d’une méthode,
  • après l’exécution d’une méthode,
  • à la place de l’exécution d’une méthode,
  • au moment où la valeur d’une propriété est consultée,
  • au moment où la valeur d’une propriété est modifiée,
  • également avant, après, à la place de l’exécution d’une fonction.

Le tissage, par le biais de la déclaration des aspects, se réalise dans la méthode register des plugins enregistrables, par le biais du tisseur de liens AOP $register->aop fourni par cette méthode.

Les greffons déclarés lors de l’enregistrement de votre plugins seront actifs pour toute votre application à partir du moment où votre plugin est déclaré dans votre fichier de configuration : il n’est pas possible de rajouter des aspects ailleurs que dans la méthode register des plugins enregistrables.

Implémentation de vos points de coupe

Comme vu en introduction, aucune déclaration particulière nécessaire pour indiquer les points de coupe potentiels : toutes les propriétés, toutes les méthodes de classes, interfaces ou traits, toutes les fonctions que vous avez développé sous projet it.rocks sont des points de coupe que vous pouvez employer.

Exemple de point de coupe : la méthode Email\Sender::send() du framework :

	/**
	 * Send an email using its account connection information
	 * or the default SMTP account configuration.
	 *
	 * @param $email  Email
	 * @return boolean|string true if sent, error message if string
	 */
	public function send(Email $email)
	{
		// .. here is the code
		return true;
	}

Implémentation de vos greffons

Toute méthode ou fonction peut être utilisée comme greffon. Toutefois ses arguments doivent respecter un certain nombre de conventions de nommage, votre greffon doit donc être compatible avec le ou les points de coupes auxquels il peut s’appliquer.

Exemple de greffon qui écrit en base de données un email, pris dans la classe Email\Archive du framework :

	/**
	 * @param $email Email
	 */
	public function save(Email $email)
	{
		Dao::write($email);
	}

On a pris soin ici de nommer l’argument avec le même nom que l’argument de la méthode d’origine pour lequel l’aspect sera tissé. C’est par le nom des arguments que le tisseur d’aspects fait le lien entre les arguments, ce qui est surtout utile lorsque votre point de coupe a plusieurs arguments mais que seulement certains vous intéressent : votre greffon peut en effet proposer une liste restreinte d’arguments, dans un ordre différent.

Certains noms d’arguments sont réservés aux mécanismes de l’AOP, et ne peuvent pas être capturés directement du point de coupe. Si jamais l’un d’entre-eux était employé par le point de coupe, vous pourrez toujours utiliser ces arguments par le biais de le l’argument $joinpoint.

  • $result : la valeur retournée par le point de coupe.
  • $object : l’objet contexte dans lequel la méthode point de coupe doit être exécutée
  • $joinpoint : cet objet de classe Joinpoint contient toutes les informations concernant le point de coupe, le point de jonction, et le greffon.

Exemple de greffon dont la tâche serait de sauvegarder un objet passé en argument nommé $object dans le point de coupe. On ne peut pas récupérer directement cet argument, mais on le retrouve par le biais de l’argument réservé $joinpoint :

	/**
	 * @param $joinpoint Method_Joinpoint
	 */
	public function save(Method_Joinpoint $joinpoint)
	{
		Dao::write($joinpoint->object);
	}

Exemple de greffon qui modifie la valeur de retour de notre point de coupe send() vu en exemple plus haut :

	/**
	 * @param $result boolean The cut point result, modified by this advice
	 */
	public function save(&$result)
	{
		$result = false;
	}

Si vous n’avez pas besoin de consulter la valeur de retour d’origine en fin de votre point de coupe, vous pouvez également retourner cette valeur de retour modifiée :

	/**
	 * return boolean
	 */
	public function save()
	{
		return false;
	}

Comment écrire vos aspects

Code minimal d’une classe plugin enregistrable :

<?php
namespace Author\Project\My_Plugin;
 
use ITRocks\Framework\Plugin\Register;
use ITRocks\Framework\Plugin\Registerable;
 
/**
 * My really first registerable plugin
 */
class My_Plugin implements Registerable
{
 
	/**
	 * Registration code for the plugin
	 *
	 * @param $register Register
	 */
	public function register(Register $register)
	{
		// Aspect weaving will come here
	}
 
}

Pour tisser un aspect : dans notre exemple le greffon save() a été programmé dans la classe du plugin, mais on pourrait très bien appeler une méthode d’un autre objet, une méthode statique, une fonction :

	/**
	 * Registration code for the plugin
	 *
	 * @param $register Register
	 */
	public function register(Register $register)
	{
		$register->aop->afterMethod([Email\Sender::class, 'send'], [$this, 'save']);
	}

L’appel à afterMethod déclare donc au tisseur d’aspect :

  • le point de coupe : après chaque appel à la méthode Email\Sender::send()
  • le greffon appelé : la méthode My_Plugin::save()

Activez vos plugins pour activez vos aspects

Vos aspects ne seront tissés et actifs que si vos plugins sont activés dans votre fichier de configuration.

Exemple de fichier de configuration minimal avec la ligne de déclaration d’utilisation du plugin Email Archive :

<?php
namespace Author\Project;
 
use ITRocks\Framework;
use ITRocks\Framework\Configuration;
 
global $loc;
require __DIR__ . '/../../loc.php';
require __DIR__ . '/../../itrocks/framework/config.php';
 
$config['Author/Project'] = [
	Configuration::APP         => Application::class,
	Configuration::EXTENDS_APP => 'ITRocks/Framework',
 
	Priority::NORMAL => [
		Framework\Email\Archive::class
	]
];

Documentation de référence : voir aussi

Consultez ces documentations pour avoir les explications et exemples pour chaque cas d’utilisation :

Montrer l'historique