Modèles métiers

Définition

Un modèle métier est un patron de conception utilisé pour respecter les règles de traitement propres à un métier. Ce modèle définit des tâches, où chaque tâche est précise et répond à la solution d'une demande métier.

Le Business Object (BO ou objet métier)

Un objet métier, plus connu sous l'acronyme BO, est une instance d'une classe métier. Comme vu dans la définition, le métier regroupe des traitements qui lui sont spécifiques et qui répondent à ses besoins.

Prenons par exemple la classe métier UserManagerBo (les classes métiers avec AF sont toujours suffixées par Bo), qui consiste à gérer les utilisateurs de l'application. Cette classe proposerait alors les méthodes d'action suivantes :

Remarquons que les méthodes d'action sont toujours suffixées par Action. Cette pratique se retrouve souvent sur d'autres frameworks tels que Zend Framework, Symfony... La différence avec le framework Adventy, réside dans le nom de la classe. Cette dernière est suffixée par Bo au lieu de Controller.

Le Controller Remplacé par le BO

Le framework Adventy a automatisé la couche controller, et donc le développeur n'aura plus à créer de classes controllers, mais des classes métiers à la place.

Cette pratique est en réalité une stratégie technique pour :

  1. améliorer la productivité en développant moins de code ;
  2. avoir une meilleure qualité de code et visibilité du code ;
  3. réduire les anomalies.

Contrairement à la couche controller, la couche métier s'oriente vers la modularité et la réutilisabilité des BO, ce qui va faciliter par la même occasion le développement des tests unitaires (qui seront véritablement unitaires). Cette technique combinée avec l'AOP va apporter de l'élégance dans le code, mais aussi et surtout une ouverture vers un genre nouveau d'architecture. Ce sujet sera traité plus loin dans la documentation dans la partie Programmation Orientée Aspect.

Ce qu'il faut retenir avec le BO, c'est le développement orienté module métier. Chaque module est spécialisé, et ne traite qu'une seule tâche et une seule.

Le chemin et le nom d'une classe métier

Le nom d'une classe métier est dépendant de l'URI de la page dynamique à laquelle la classe est rattachée. Il prend le nom du dernier dossier de l'URI, et la dernière partie de l'URI désigne l'action.

Par exemple, si l'URI est /get-user, alors nous aurons à définir les fichiers suivants :

  1. les propriétés de page (optionnelles) : /application/meta/get-user.meta.php
  2. le corps de page : /application/view/page/get-user.body.php
  3. le CSS de page (optionnel) : /application/view/css/get-user.css.php
  4. le JS de page (optionnel) : /application/view/js/get-user.js.php
  5. la classe métier : /application/model/bo/IndexBo.class.php qui doit implémenter la méthode action public function getUserAction() (optionnelle si page statique). Notons que le nom de classe métier (en upper camel case) est suffixé par Bo, et que l'action (en camel case) est suffixée par Action. Dans cet exemple, le dossier racine des BO étant /application/model/bo/, par défaut, il est assimilé au nom de dossier index, d'où le nom de la classe IndexBo.

Un autre exemple où l'application de la règle sur le dernier nom de classe serait plus évidente. Soit l'URI /my-folder/get-user, alors les fichiers à créer seraient :

  1. les propriétés de page (optionnelles) : /application/meta/my-folder/get-user.meta.php
  2. le corps de page : /application/view/page/my-folder/get-user.body.php
  3. le CSS de page (optionnel) : /application/view/css/my-folder/get-user.css.php
  4. le JS de page (optionnel) : /application/view/js/my-folder/get-user.js.php
  5. la classe métier : /application/model/bo/MyFolderBo.class.php, sans oublier l'implémentation de la méthode action public function getUserAction() (optionnelle si page statique).

Et voici un dernier exemple avec l'URI /my-folder/my-subfolder/get-user :

  1. les propriétés de page (optionnelles) : /application/meta/my-folder/my-subfolder/get-user.meta.php
  2. le corps de page : /application/view/page/my-folder/my-subfolder/get-user.body.php
  3. le CSS de page (optionnel) : /application/view/css/my-folder/my-subfolder/get-user.css.php
  4. le JS de page (optionnel) : /application/view/js/my-folder/my-subfolder/get-user.js.php
  5. la classe métier : /application/model/bo/my-folder/MySubfolderBo.class.php avec l'implémentation de la méthode action public function getUserAction() (optionnelle si page statique).

La création d'une classe métier

Les classes métiers sont définies dans le dossier /application/model/bo/. Le nom de la classe métier (en upper camel case) porte le nom du dernier dossier de l'URI, suffixé par Bo, excepté si ce dossier est le dossier racine des BO. Dans ce cas, le nom de la classe métier est par défaut IndexBo.

En respectant cette règle de nommage, il ne reste plus qu'à créer la classe métier dans le dossier souhaité. Si nous prenons un exemple plus concret avec l'URI /application/meta/my-manager/my-user/get-user.meta.php, alors le fichier de la classe métier à créer sera /application/model/bo/my-manager/MyUserBo.class.php.

Et voici son contenu :

<?php 
namespace model\bo\myManager;

/**
 * My business model class suffixed by Bo.
 * @author xxx
 * @version 0.1
 * @package model.bo.my-manager
 */
class MyUserBo extends \org\adventy\model\bo\AbstractBo {
	...
	/**
	 * Display user data.
	 * @return void
	 * @uses /my-manager/my-user/get-user?userId=369
	 */
	public function getUserAction() {
		//Retrieve parameters from $_GET and $_POST
		$parameters = &$this->_parameters;
		...
		//Prepare user filter: set primary key
		$filters = array('userId' => &$parameters['userId']);
		
		//Retrieve user data: store result in view variable $this->userData
		//xxxDs is a data source (ex: database)
		$this->tuserData = $this->xxxDs->userDao->get($filters);
		...
	}
	...
}
?>

Notons que la classe MyUserBo étend la classe abstraite \org\adventy\model\bo\AbstractBo.

Nous expliquerons ce qu'est une source de données (Data Source) dans la partie Accès aux données.

Les variables de vue

Dans l'exemple ci-dessus, la méthode MyUserBo::getUserAction introduit 2 nouvelles notions :

  1. l'utilisation d'un DAO ($this->xxxDs->userDao), qui est un patron de conception permettant d'accéder aux données. Les DAO sont utilisées dans les BO. C'est un sujet qui sera abordé juste après les modèles métiers.
  2. la création d'une variable de vue, ici $this->userData qui récupère les données de l'utilisateur ayant l'identifiant userId=369. Cette variable de vue peut également être récupérée depuis le tableau associatif des variables de vue $this->_viewData de la façon suivante : $this->_viewData['userData'].

Pour le framework Adventy, il faut savoir que les variables de vue sont assimilées à des attributs de portée public des classes BO. Le framework nomme les propriétés de classe selon leur portée, en utilisant la règle suivante :

Les variables de vue sont de type public, et ne devraient donc pas être préfixées par le caractère "_". Si cela devait arriver malgré tout, le nommage de ces variables devra être différents des noms d'attributs déjà réservés :

  1. _acceptEncoding
  2. _actionName
  3. _aop
  4. _boName
  5. _boPath
  6. _cleanFilter
  7. _dataSources
  8. _formData
  9. _i18n
  10. _metadata
  11. _parameters
  12. _request
  13. _requestType
  14. _response
  15. _templateFile
  16. _uri
  17. _viewData
  18. _viewPath
  19. _viewUri

Toutes les variables de vue sont stockées et peuvent être récupérées depuis le tableau associatif $this->_viewData.

L'utilisation des variables de vue dans la vue

La vue /application/view/page/my-manager/my-user/get-user.body.php peut accéder à toutes les propriétés et méthodes de la classe \org\adventy\request\PageRequest, y compris les attributs créés dynamiquement depuis les méthodes d'action du BO. Ces attributs sont appelés variables de vue, et sont utilisés avec $this pour faire référence à l'instance courante de la requête de page \org\adventy\request\PageRequest.

Voici un exemple de contenu de la vue /application/view/page/my-manager/my-user/get-user.body.php :

<?php
//Retrieve view variable
$userData = &$this->userData;

//Or $userData = &$this->_viewData['userData'];
?>
<table>
	<tbody>
		<tr>
			<td>UserId</td>
			<td><?= $userData['userId']?></td>
		</tr>
		<tr>
			<td>First name</td>
			<td><?= $userData['firstname']?></td>
		</tr>
		<tr>
			<td>Last name</td>
			<td><?= $userData['lastname']?></td>
		</tr>
	</tbody>
</table>

Les variables de vue sont :

  1. accessibles individuellement par $this-><variableName> (ex : $this->userData) ;
  2. ou récupérables depuis le tableau associatif $this->_viewData regroupant toutes les variables de vue (ex : $this->_viewData['userData']).