Documentation : DAO générique

Présentation

Comme vous avez pu le voir rapidement dans l'introduction, Temma est capable de créer automatiquement des DAO. Le cas le plus simple est lorsque vous créez un contrôleur qui doit accéder à une seule table de la bases de données.
Il suffit alors que ce contrôleur possède un attribut protégé nommé $_temmaAutoDao, positionné à la valeur booléenne true.

Si on reprend l'exemple donné en introduction :

class ArticleController extends \Temma\Controller {
     /** Indique que le framework doit créer automatiquement la DAO. */
     protected $_temmaAutoDao = true;
}
						

En procédant de la sorte, Temma va créer un objet \Temma\Dao, qui sera automatiquement configuré pour faciliter la manipulation des données stockées dans une table dont le nom est identique à celui du contrôleur (article).
Cet objet sera disponible via l'attribut $this->_dao.

Configuration avancée

Principe général

Par défaut, les DAO présupposent plusieurs choses :

  • Si le cache est accessible, il faut l'utiliser pour accélérer l'accès aux données.
  • La table est dans la base de données sur laquelle la connexion est ouverte.
  • Le champ contenant la clé primaire se nomme id.
  • Tous les champs de la table doivent être récupérés quand on y accède.
  • Quand on récupère les champs de la table, on récupère les noms tels qu'ils sont en base.
  • Le nom de la table correspond au nom du contrôleur.

Pour pouvoir paramétrer le fonctionnement de la DAO (désactiver le cache, spécifier un nom de base ou de table différent, renommer les champs, ...), il est conseillé d'écrire un objet DAO personnalisé, qui pourra contenir les informations spécifiques dont vous avez besoin.

Configuration spécifique

Toutefois, si vous êtes dans le cas où un contrôleur doit pouvoir manipuler des données en configurant finement le comportement de la DAO, mais que vous ne souhaitiez pas créer d'objet DAO personnalisé, il est possible de fournir les paramètres directement dans le contrôleur, en remplissant un tableau associatif.
Notez bien que cette technique reste limitée et ne doit surtout pas être employée dans le cas où la même table est accédée par plusieurs contrôleurs différents.

Voici un exemple d'utilisation avec paramétrage spécifique :

01 class ArticleController extends \Temma\Controller {
02     protected $_temmaAutoDao = array(
03         'cache'  => false,
04         'base'   => 'cms',
05         'table'  => 'content',
06         'id'     => 'cid',
07         'fields' => array(
08             'cid'     => 'contentId',
09                          'title',
10                          'login',
11             'content' => 'text',
12             'date'    => 'creationDate',
13                          'status'
14         );
15     );
16 }
						

Ligne 2 : Définition du tableau de configuration de la DAO.
Ligne 3 : Désactivation du cache.
Ligne 4 : Définition du nom de la base de données contenant la table.
Ligne 5 : Définition du nom de la table.
Ligne 6 : Définition du nom du champ contenant la clé primaire.
Lignes 7 à 14 : Définition d'un tableau associatif contenant la liste des champs à récupérer dans la base de données. S'il faut renommer les champs, il suffit de déclarer une paire associative dont la clé est le nom du champ dans la table, et la valeur associée est le nom tel qu'il doit être renommé.

Les paramètres sont indépendants, vous n'êtes pas obligés de tous les redéfinir.

Opérations basiques

Les objets \Temma\Dao proposent 6 méthodes basiques :

  • count() : Compte le nombre d'éléments dans une table.
  • get() : Retourne toutes les informations sur un élément de la table.
  • search() : Recherche des entrée.
  • create() : Ajoute un nouvel élément dans la table.
  • remove() : Efface un ou plusieurs éléments.
  • update() : Met-à-jour un ou plusieurs enregistrements.

Ces méthodes sont expliquées en détail plus bas, mais nous allons d'abord voir comment sont construits les critères de recherche et les critères de tri, qui peuvent être utilisés dans certaines de ces méthodes.

Critères de recherche

Les DAO proposent un mécanisme permettant de composer facilement des filtres de recherche. Pour cela, il faut créer un critère, qui pourra être passé en paramètre de certaines méthodes.

Créer un critère se fait grâce à la méthode criteria(), qui crée un objet de type \Temma\DaoCriteria.

Ensuite, vous pouvez combiner des appels aux méthodes suivantes :

  • equal() : un champ vaut une certaine valeur (possibilité de donner une liste de valeurs possibles)
  • different() : un champ ne vaut pas une certaine valeur (possibilité de donner une liste de valeurs possibles)
  • like() : un champ textuel vérifie une expression de recherche
  • notLike() : un champ textuel ne vérifie pas une expression de recherche
  • is() : un champ booléen est positionné sur "vrai"
  • isNot() : un champ boolén est positionné sur "faux"
  • lessThan() : la valeur d'un champ numérique est inférieure à une certaine valeur
  • greaterThan() : la valeur d'un champ numérique est supérieure à une certaine valeur
  • lessOrEqualTo() : la valeur d'un champ numérique est inférieure ou égale à une certaine valeur
  • greaterOrEqualTo() : la valeur d'un champ numérique est supérieure ou égale à une certaine valeur

Il existe des alias, pour simplifier l'écriture :

  • eq() : équivalent à equal()
  • ne() : équivalent à different()
  • lt() : équivalent à lessThan()
  • gt() : équivalent à greaterThan()
  • le() : équivalent à lessOrEqualTo()
  • ge() : équivalent à greaterOrEqualTo()

Par défaut, les critères sont combinés en utilisant des opérateurs booléens "ET", ce qui conduit à la création d'un système de filtrage des données : seules les données qui vérifient toutes les conditions sont récupérées. Il est possible de combiner tous les critères suivant l'opérateur "OU" en passant la chaîne "or" en paramètre de la méthode criteria().
Il est aussi possible de combiner les critères avec des opérateurs booléens grâce aux méthodes and_() et or_(), qui prennent chacune un nouvel objet de critère en paramètre.

01 // recherche les entrées dont l'email vaut "tom@tom.com" ET le booléen "free" est à vrai
02 $critera = $this->_dao->criteria()
03            ->equal('email', 'tom@tom.com')
04            ->is('free');
05 $users = $this->_dao->search($criteria);
						

Ligne 2 : Création de l'objet de critère.
Ligne 3 : Ajout d'un critère d'égalité. Le champ email doit avoir la valeur tom@tom.com.
Ligne 4 : Ajout d'un critère d'égalité sur un booléen. Le champ free doit être positionné à "vrai".
Ligne 5 : L'objet de critère est utilisé avec la méthode search() de la DAO pour récupérer les éléments correspondant au critère.

01 // recherche les entrées dont l'âge est supérieur à 12 ET inférieur à 20
02 $criteria = $this->_dao->criteria()
03             ->greaterThan('age', 12)
04             ->lessThan('age', 20);
						

Ligne 2 : Création de l'objet de critère.
Ligne 3 : Ajout d'un critère de comparaison. Le champ age doit être strictement supérieur à 12.
Ligne 4 : Ajout d'un critère de comparaison. Le champ age doit être strictement inférieur à 20.

01 // recherches les entrées dont l'email vient de Gmail OU dont le nom
02 // n'est pas celui d'un créateur de Google
03 $criteria = $this->_dao->criteria('or')
04             ->like('email', '%@gmail.com')
05             ->different('name', array('Sergey', 'Larry'));
						

Ligne 3 : Création de l'objet de critère, en spécifiant que les critères seront associés par des opérateurs "OU" (et non pas "ET" comme par défaut).
Ligne 4 : Ajout d'un critère de comparaison. Le champ email doit se terminer par la chaîne "@gmail.com".
Ligne 5 : Ajout d'un critère de comparaison. Le champ name ne doit pas contenir la valeur "Sergey" ni "Larry".

01 // recherche les entrées dont l'email vaut "john@john.com" ou "bob@bob.com", ET dont l'âge est
02 // inférieur ou égal à 12 OU strictement supérieur à 24
03 $criteria = $this->_dao->criteria()
04             ->equal('email', array('john@john.com', 'bob@bob.com'))
05             ->and_(
06                    $this->_dao->criteria('or')
07                    ->lessOrEqualTo('age', 12)
08                    ->greaterThan('age', 24)
09             );
						

Ligne 3 : Création de l'objet de critère.
Ligne 4 : Ajout d'un critère d'égalité, en fournissant une liste de valeurs.
Ligne 5 : Ajout d'un opérateur booléen "ET", qui contient un sous-ensemble de critères.
Ligne 6 : Création du sous-ensemble de critères. On spécifie que les différents critères de cet ensemble seront liés par des opérateurs "OU".
Ligne 7 : Ajout d'un critère de comparaison. Le champ age doit contenir une valeur inférieure ou égale à 12.
Ligne 8 : Ajout d'un critère de comparaison. Le champ age doit être strictement supérieur à 24.

Critères de tri

La méthode search() est susceptible de retourner plusieurs éléments, que l'on peut vouloir trier dans un certain ordre.

Il est possible de trier de 3 manières différentes :

  1. En fournissant le nom d'un champ, ce qui effectuera un tri ascendant sur les valeurs de ce champ.
  2. En transmettant un tableau contenant les noms des champs sur lesquels le tri doit être effectué. Par défaut, les tris sont ascendants (de la plus petite valeur à la plus grande), mais il est possible de spécifier un tri descendant en utilisant un tableau associatif dont la clé est le nom du champ et la valeur est la chaîne desc.
  3. En fournissant la valeur booléenne false, pour obtenir un tri aléatoire.

// tri suivant la date de naissance, de manière ascendante
$sort = 'birthday';

// tri suivant la date de naissance (ascendant) et le nombre de points (descendant)
$sort = array(
    'birthday',
    'points' => 'desc'
);

// équivalent au précédent
$sort = array(
    'birthday' => 'asc',
    'points'   => 'desc'
);

// tri aléatoire
$sort = false;
						
count([criteria])

Si cette méthode est appelée sans paramètre, elle retourne le nombre total d'éléments dans la table.

Si elle est appelée avec un objet de critère en paramètre, elle retourne le nombre d'éléments qui correspondent au(x) critère(s).

Exemple d'utilisation :

// récupère le nombre total d'éléments dans la table
$nbr = $this->_dao->count();

// récupère le nombre d'articles créés par Bob
$nbr = $this->_dao->count($this->_dao->criteria()->equal('name', 'Bob'));
						
get(int)

Cette méthode retourne toutes les informations sur un enregistrement de la table, dont l'identifiant de clé primaire est passé en paramètre. Les données sont retournées dans un tableau associatif, qui liste des tuples dont la clé est le nom du champ.

Si une liste de champs a été fournie à la création de la DAO, seuls les champs en question sont retournés. Si cette liste prévoyait de renommer les champs, les clés du tableau associatif sont modifiées en conséquence.

Exemple d'utilisation :

// récupère les informations sur l'article ayant l'identifiant 12
$data = $this->_dao->get(12);

// affichage du titre
print($data['title']);
						
search([criteria], [sort], [int], [int])

Cette méthode sert à récupérer les données de plusieurs lignes de la table. Elle retourne une liste dont chaque élément est un tableau associatif (dont le contenu est identique à ce que retourne la méthode get(), cf. ci-dessus).
Le premier paramètre est un critère de recherche, tel qu'expliqué plus haut dans cette page. S'il n'est pas fourni, ou passé à null, la méthode prendra toutes les lignes de la table.
Le deuxième paramètre contient les options de tri, telles qu'expliquées plus haut dans cette page.
Le troisième paramètre peut contenir le numéro du premier élément à retourner (en commençant à zéro).
Le quatrième paramètre peut contenir le nombre d'éléments à retourner.

Exemple d'utilisation :

// recherche les 5 articles les plus récents, parmi tous ceux écrits depuis le 1er janvier 2011
$articles = $this->_dao->search($this->_dao->criteria()->greaterThan('date', '2011-01-01'),
                                array('date' => 'desc'), null, 5);

// affichage des titres de tous les articles récupérés
foreach ($articles as $article)
    print($article['title']);

// recherche 3 articles au hasard
$articles = $this->_dao->search(null, false, null, 3);
						
create(array)

Cette méthode ajoute une nouvelle ligne dans la table.
Il faut donner en paramètre un tableau associatif, contenant des paires clé/valeur correspondant à chaque champ de la table.

La méthode retourne l'identifiant de clé primaire de l'élément nouvellement créé.

Exemple d'utilisation :

// création du nouvel article
$id = $this->_dao->create(array(
    'title'   => 'Titre de test',
    'login'   => 'Bob',
    'date'    => date('c'),
    'content' => 'Texte...'
));

// affichage de l'identifiant du nouvel article
print($id);
						
remove([int|criteria])

Cette méthode sert à effacer des enregistrements de la table.
Si elle est appelée sans paramètre, elle efface tous les éléments.
Si un identifiant numérique est passé en paramètre, il sera utilisé comme clé primaire de l'élément à effacer.
Si un critère de recherche est passé en paramètre, il est utilisé pour choisir les éléments qui seront effacés.

Exemple d'utilisation :

// effacement de l'article ayant l'identifiant 12
$this->_dao->remove(12);

// effacement de tous les articles écrits par Bob
$this->_dao->remove($this->_dao->criteria()->equal('login', 'Bob'));
						
update([int|criteria], array)

Avec cette méthode, vous pouvez modifier les données enregistrée dans la table.

Si le premier paramètre est mis à null, tous les éléments de la table seront modifiés.
Si un identifiant numérique est passé en paramètre, il sera utilisé comme clé primaire de l'identifiant qui sera modifié.
Si un critère de recherche est passé en paramètre, il sera utilisé pour sélectionner les éléments qui seront modifiés.

Le second paramètre doit contenir un tableau associatif, contenant des paires clé/valeur correspondant aux champs à mettre à jour (avec une déclaration identique à la méthode create()).

Exemple d'utilisation :

// change le login en "Robert" dans tous les articles que Bob a écrit
$this->_dao->update($this->_dao->criteria()->equal('login', 'Bob'),
                    array('login' => 'Robert'));
						
Gestion du cache

L'utilisation du cache accélère les lectures sur la base de données. Malheureusement, cela peut avoir un effet indésirable : Toutes les requêtes identiques retourneront des résultats identiques pendant la durée de mise en cache. Cela peut être problématique lorsque vous exécutez des requêtes qui s'écrivent à l'identique mais qui doivent retourner des résultats différents (par exemple des sélections dont les résultats sont triés de manière aléatoire, ou si vous devez ponctuellement prendre des données à jour).

Il est donc possible de désactiver momentanément l'utilisation du cache en utilisant la méthode disableCache(). La réactivation se fait en utilisant la méthode enableCache(). Ces deux méthodes retournent l'instance de leur DAO, sauf si un paramètre leur est fourni, qui sera alors retourné.

Exemple d'utilisation :

// désactivation du cache
$this->_dao->disableCache();
// recherche
$result = $this->_dao->search();
// réactivation du cache
$this->_dao->enableCache();

// résultat identique au précédent
$result = $this->_dao->disableCache()->search();
$this->_dao->enableCache();

// résultat identique aux précédents
// ordre d'exécution :
// 1. disableCache()
// 2. search() qui est écrit en paramètre à enableCache()
// 3. enableCache()
// au final, c'est le résultat du search() qui est récupéré, car il est retourné par enableCache()
$result = $this->_dao->disableCache()->enableCache($this->_dao->search());