Accès aux données

Le DAO

Le framework Adventy pratique le patron de conception DAO (Objet d'Accès aux Données) pour accéder aux données (bases de données, fichiers, annuaires). Les DAO sont utilisés dans les BO à travers les sources de données. Le fait de distinguer le DAO du BO permet de séparer les problématiques :

  1. le DAO est une abstraction sur l'échange des données avec les sources de données au niveau des objets métiers ;
  2. le BO s'occupe des règles de gestion métier. Donc si une règle métier venait à être modifiée, cela n'impactera nullement le DAO.

Dans le cadre de la connexion à une base de données, le DAO est étroitement lié à la notion de table. Cela revient tout simplement à dire qu'un DAO est une représentation abstraite d'une table. Ainsi, l'accès aux données de la table s'effectue en appelant les méthodes du DAO. Cette association est identifiée par le suffixe du DAO qui est en fait le nom de la table. Par exemple, pour la la table USER_ACCESS, le DAO associé serait UserAccessDao (nom de classe en upper camel case).

Pour les exemples qui vont suivre, la base de données MySQL/MariaDB sera utilisée. A ce jour, le framework Adventy n'a pas encore implémenté de DAO pour d'autres bases de données autre que MySQL/MariaDB, mais le principe reste le même.

L'accès à la base de données MySQL/MariaDB

Le framework Adventy dispose d'une classe DAO par type de base de données. Par exemple, pour la base de données MySQL/MariaDB, il y a la classe /model/dao/MySqlDao.class.php.
Pour utiliser MySqlDao afind'accéder à la base de données MySQL/MariaDB, chaque table devra être associée à une classe DAO. Chacune de ces classes sera de type MySqlDao, et sera créée dans le dossier des DAO /application/mode/dao/ prévu à cet effet. Ce dossier ne contiendra pas de sous-dossier.

En reprenant notre exemple avec la table USER_ACCESS, le fichier de la classe UserAccessDao à créer sera donc /application/model/dao/UserAccessDao.class.php.

Et voici ce que ce fichier contient :

<?php 
namespace model\dao;

/**
 * DAO class for "user_access" table.
 *
 * @author Adventy generator
 * @version 0.1
 * @package model.dao
 */
class UserAccessDao extends \org\adventy\model\dao\MySqlDao {
	/**
	 * Constructor.
	 * @param integer $connection Database connection.
	 * @return void
	 */
	public function __construct($connection) {
		parent::__construct(
			//Data source connection
			$connection,

			//Table name
			'user_access',

			//Table description
			array(
				'userAccessId' => self::INTEGER_FIELD_TYPE,
				'userId' => self::INTEGER_FIELD_TYPE,
				'accessId' => self::INTEGER_FIELD_TYPE
			),

			//Primary key definition
			array('userAccessId')
		);
	}
		
	/**
	 * (non-PHPdoc)
	 * @see AbstractDao::insert()
	 */
	public function insert(array &$data) {
		...
	}
		
	/**
	 * (non-PHPdoc)
	 * @see AbstractDao::update()
	 */
	public function update(array &$data) {
		...
	}
		
	/**
	 * (non-PHPdoc)
	 * @see AbstractDao::exists()
	 */
	public function exists(array &$data) {
		...
	}
		
	/**
	 * (non-PHPdoc)
	 * @see AbstractDao::get()
	 */
	public function get(array &$data) {
		...
	}
		
	/**
	 * (non-PHPdoc)
	 * @see AbstractDao::delete()
	 */
	public function delete(array &$data) {
		...
	}
	 
	/**
	 * (non-PHPdoc)
	 * @see AbstractDao::getPage()
	 */
	public function getPage(array $filters, $page = 1, $quantity = 10, $count = true, $orderClause = null) {
		...
	}
}
?>

Dans une classe DAO, il faut retenir 3 choses :

  1. une classe DAO est liée à une table donnée, et est de type de source de données \org\adventy\model\dao\xxxDao, ici \org\adventy\model\dao\MySqlDao pour le cas de connexion à la base de données MySQL/MariaDB ;
  2. son constructeur décrit la table associée en renseignant :
    • la connexion à la source de données ;
    • le nom de la table associée ;
    • le nom et le type des colonnes de la table associée ;
    • la clé primaire de la table associée.
  3. elle doit implémenter les méthodes abstraites de base :
    • insert : crée un enregistrement ;
    • get : récupère un enregistrement par sa clé primaire ;
    • update : modifie un enregistrement par sa clé primaire ;
    • delete : supprime un enregistrement par sa clé primaire ;
    • exists : détermine l'existence d'un enregistrement par sa clé primaire ;
    • getPage : récupère une collection d'enregistrement par page.
    Si l'une de ces méthodes n'a pas besoin d'être implémentée, la meilleure partique consiste d'y lever une exception au lieu de déclarer une méthode vide. Par exemple :
    /**
     * (non-PHPdoc)
     * @see AbstractDao::getPage()
     */
    public function getPage(array $filters, $page = 1, $quantity = 10, $count = true, $orderClause = null) {
       	//A generic exception can be throwed, but typed exception is best practice to catch it later if needed
    	//throw new \Exception(__METHOD__ . ' is not implemented.');
    
    	//This method is not used, then throw an exception instead of an empty method
    	throw new \org\adventy\exception\SqlException(__METHOD__ . ' is not implemented.');
    }
    
    au lieu de :
    /**
     * (non-PHPdoc)
     * @see AbstractDao::getPage()
     */
    public function getPage(array $filters, $page = 1, $quantity = 10, $count = true, $orderClause = null) {
       	//Empty is not recommended, because we don't know if the method is enabled or not
    }
    

Bien évidemment, il est possible de compléter le DAO par de nouvelles méthodes en plus de celles déjà définies, qui vont lire et/ou écrire des données dans la source de données.

L'utilisation de DAO dans un BO

L'appel d'un DAO dans un BO se fait tout simplement par $this->xxxDs->yyyDao, avec xxx comme nom de la source de données (paramétré dans le fichier de configuration /application/configuration.cfg.php), et yyy comme nom de table asscociée en camel case. La classe DAO n'a pas besoin d'être chargée manuellement puisque l'autoloader s'occupe automatiquement de cette tâche.

Prenons l'exemple ci-dessous :

<?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 request parameters
		$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 the Data Source definied in /application/configuration.cfg.php
		$this->userData = $this->xxxDs->userDao->get($filters);
		...
	}
	...
}
?>

L'utilisation de la classe UserDao s'effectue par $this->xxxDs->userDao. S'il n'existe pas déjà une instance de cette classe, alors cette dernière sera auto-chargée, puis une instance sera créée automatiquement. Ensuite, l'appel de ses méthodes publiques se fait par $this->xxxDs->userDao-><methodName>(<arguments>), où <methodName> est le nom d'une méthode publique (ex : $this->xxxDs->userDao->get), et <arguments>, la liste des paramètres à passer à la méthodes si elle existe (ex : $this->xxxDs->userDao->get($filters)).