mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-06 08:14:21 +01:00
655 lines
26 KiB
Plaintext
655 lines
26 KiB
Plaintext
Active Record
|
|
=============
|
|
|
|
Même si Yii DAO peut gérer n'importe quelle tache relative à la base de données,
|
|
il est fort probable qu'une grande partie du temps de développement soit consacré
|
|
à l'écriture de requêtes SQL pour faire des opérations CRUD (create, read, update and delete)
|
|
courantes. De plus il est difficile de maintenir un code quand celui est parsemé
|
|
de requêtes SQL. Active Record est là pour régler ces problèmes.
|
|
|
|
Active Record (AR) est une technique très utilisée de Object-Relational Mapping (ORM).
|
|
Chaque classe AR représente une table dans la base, dont les attributs représente une propriété
|
|
de cette classe AR, et une instance AR représente une ligne de cette table. Les opérations couramment
|
|
utilisées sont implémentées dans des méthodes de cette classe. Ainsi il est possible d'accéder
|
|
aux données d'une manière orientée objet. Par exemple, il est possible d'utiliser le code
|
|
suivant pour insérer une nouvelle ligne dans la table `tbl_post`:
|
|
|
|
~~~
|
|
[php]
|
|
$post=new Post;
|
|
$post->title='post de test';
|
|
$post->content='contenu du post de test';
|
|
$post->save();
|
|
~~~
|
|
|
|
Nous allons maintenant voir comment configurer AR et comment l'utiliser pour
|
|
effectuer des opérations CRUD. Nous verrons dans la prochaine section comment
|
|
utiliser AR pour régler les cas de clés étrangères entre tables. Pour simplifier
|
|
les choses, la table suivante sera utilisée. Attention, si vous utilisez une base
|
|
MySQL, il faut remplacer `AUTOINCREMENT` par `AUTO_INCREMENT` dans le code SQL suivant.
|
|
|
|
~~~
|
|
[sql]
|
|
CREATE TABLE tbl_post (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
title VARCHAR(128) NOT NULL,
|
|
content TEXT NOT NULL,
|
|
create_time INTEGER NOT NULL
|
|
);
|
|
~~~
|
|
|
|
> Note: AR n'est pas fait pour régler tous les problèmes liés aux tâches touchant
|
|
à la base. AR convient le mieux pour modéliser des tables en PHP et pour effectuer
|
|
des requêtes n'impliquant pas de code SQL complexe. Yii DAO est préférable dans ces
|
|
cas de requêtes SQL complexes.
|
|
|
|
|
|
Etablir une connexion à la base de données
|
|
------------------------------------------
|
|
|
|
AR à besoin d'une connexion à une BD pour effectuer les tâches relatives à la base.
|
|
Par défaut, l'application component `db` sera utilisé pour récupérer l'instance
|
|
[CDbConnection] qui servira pour la connexion à la base. Voici un exemple de configuration:
|
|
|
|
~~~
|
|
[php]
|
|
return array(
|
|
'components'=>array(
|
|
'db'=>array(
|
|
'class'=>'system.db.CDbConnection',
|
|
'connectionString'=>'sqlite:path/to/dbfile',
|
|
// turn on schema caching to improve performance
|
|
// 'schemaCachingDuration'=>3600,
|
|
),
|
|
),
|
|
);
|
|
~~~
|
|
|
|
> Tip: Comme Active Record dépend des metadata décrivant les tables pour
|
|
connaître les informations d'une colonne, cela prend du temps lors
|
|
de la lecture des metadata et de leur analyse. S'il est peu probable que
|
|
le schéma de votre base change, il est conseillé d'activer le cache sur le
|
|
schéma en fixant la propriété [CDbConnection::schemaCachingDuration] à
|
|
une valeur supérieure à 0.
|
|
|
|
Le support pour AR est limité par le SGBD. Actuellement, seulement les SGBD suivants
|
|
le supportent:
|
|
|
|
- [MySQL 4.1 ou plus](http://www.mysql.com)
|
|
- [PostgreSQL 7.3 or later](http://www.postgres.com)
|
|
- [SQLite 2 et 3](http://www.sqlite.org)
|
|
- [Microsoft SQL Server 2000 ou plus](http://www.microsoft.com/sqlserver/)
|
|
- [Oracle](http://www.oracle.com)
|
|
|
|
> Note: Le support de Microsoft SQL Server est disponible depuis la version 1.0.4;
|
|
> et le support pour Oracle est disponible depuis la version 1.0.5.
|
|
|
|
Si vous voulez utiliser une application component autre que `db`, ou si vous
|
|
voulez travailler sur plusieurs bases avec AR, vous pouvez surcharger [CActiveRecord::getDbConnection()].
|
|
La classe [CActiveRecord] est la classe de base pour toutes les classes AR.
|
|
|
|
> Tip: Il existe 2 moyens de gérer plusieurs BD avec AR. Si les schémas des bases
|
|
sont différents, il est possible de créer différentes classes AR de base avec différentes
|
|
implémentations de [getDbConnection()|CActiveRecord::getDbConnection]. Dans le cas contraire,
|
|
il est préférable de changer dynamiquement la variable statique [CActiveRecord::db].
|
|
|
|
Définition d'une classe AR
|
|
--------------------------
|
|
|
|
Pour accéder à une table en base, il faut tout d'abord définir une classe AR en héritant
|
|
de [CActiveRecord]. Chaque classe AR représente une seule table, et une instance AR représente
|
|
une ligne dans cette table. L'exemple suivant montre le code minimum requis pour la classe AR représentant
|
|
la table `tbl_post`.
|
|
|
|
~~~
|
|
[php]
|
|
class Post extends CActiveRecord
|
|
{
|
|
public static function model($className=__CLASS__)
|
|
{
|
|
return parent::model($className);
|
|
}
|
|
|
|
public function tableName()
|
|
{
|
|
return 'tbl_post';
|
|
}
|
|
}
|
|
~~~
|
|
|
|
> Tip: Comme les classes AR sont souvent référencées à de nombreux endroits, il est
|
|
> possible d'importer tout le répertoire contenant les classes AR, plutôt que de les
|
|
> inclure une par une. Par exemple, si tous vos fichiers de classes AR sont dans
|
|
> `protected/models`, il est possible de configurer l'application comme suit:
|
|
> ~~~
|
|
> [php]
|
|
> return array(
|
|
> 'import'=>array(
|
|
> 'application.models.*',
|
|
> ),
|
|
> );
|
|
> ~~~
|
|
|
|
Par défaut, le nom de la classe AR est le même que celui de la table en base.
|
|
Il est possible de surcharger la méthode [tableName()|CActiveRecord::tableName] si
|
|
ceux-ci sont différents. La méthode [model()|CActiveRecord::model] est déclarée dans
|
|
chaque classe AR (explication peu après).
|
|
|
|
> Info: Pour utiliser les [préfixes de table](/doc/guide/database.dao#using-table-prefix)
|
|
> introduits dans la version 1.1.0, la méthode [tableName()|CActiveRecord::tableName]
|
|
> pour une classe AR peut être surchargée comme suit,
|
|
> ~~~
|
|
> [php]
|
|
> public function tableName()
|
|
> {
|
|
> return '{{post}}';
|
|
> }
|
|
> ~~~
|
|
> Ainsi, à la place de retourner le nom de la table complète, le nom de la table
|
|
> sans le préfixe et entre doubles accolades est renvoyé.
|
|
|
|
Les valeurs en colonne d'une ligne de table sont accessibles en tant que propriétés
|
|
de l'instance AR correspondante. Par exemple, le code suivant écrit dans la colonne (attribut)
|
|
`title`:
|
|
|
|
~~~
|
|
[php]
|
|
$post=new Post;
|
|
$post->title='un post de test';
|
|
~~~
|
|
|
|
Bien que la propriété `title` ne soit jamais déclarée explicitement dans la classe `Post`,
|
|
il est tout de même possible d'y accéder dans le code précédent. Cela s'explique car `title`
|
|
est une colonne dans la table `tbl_post`, et que CActiveRecord la rend accessible en tant que
|
|
propriété grâce aux méthodes PHP `__get()`. Une exception sera levée si un accès est tenté sur
|
|
une colonne inexistante.
|
|
|
|
> Info: Dans ce guide, tous les noms des tables et des colonnes sont en minuscules.
|
|
La raison étant que les SGBD ont différentes manières de gérer la casse.
|
|
Par exemple, PostgreSQL est par défaut insensible à la casse pour les noms des colonnes,
|
|
et il faut mettre des guillemets dans les conditions pour les colonnes contenant différentes
|
|
casses. L'utilisation des minuscules permet d'éliminer ce problème.
|
|
|
|
AR dépend de la définition correcte des clés primaires sur les tables. Si une table n'a pas
|
|
de clé primaire, il est nécessaire que la classe AR correspondante spécifie quelle(s) colonne(s)
|
|
doit(vent) être la clé primaire en surchargeant la méthode `primaryKey()`,
|
|
|
|
~~~
|
|
[php]
|
|
public function primaryKey()
|
|
{
|
|
return 'id';
|
|
// Pour les clés primaires composites, retourne un tableau, par exemple:
|
|
// return array('pk1', 'pk2');
|
|
}
|
|
~~~
|
|
|
|
|
|
Création des enregistrements
|
|
----------------------------
|
|
|
|
Pour insérer une nouvelle ligne dans une table, une instance de la classe AR
|
|
correspondante est créée, les propriétés sont écrites, et la méthode [save()|CActiveRecord::save]
|
|
est appelée.
|
|
|
|
~~~
|
|
[php]
|
|
$post=new Post;
|
|
$post->title='post de test';
|
|
$post->content='contenu du post de test';
|
|
$post->create_time=time();
|
|
$post->save();
|
|
~~~
|
|
|
|
Si la clé primaire de la table est en auto incrément, après l'insertion,
|
|
l'instance AR contiendra la clé primaire mise à jour. Dans l'exemple ci-dessus,
|
|
la propriété `id` sera égale à la valeur de la clé primaire du nouveau post inséré, même
|
|
si elle n'est jamais changée implicitement.
|
|
|
|
Si une colonne a été définie avec une valeur statique par défaut dans le schéma de la table,
|
|
la propriété correspondante dans l'instance AR aura automatiquement cette valeur suite à
|
|
la création de cette instance. Une façon de changer cette valeur par défaut est de déclarer
|
|
explicitement la propriété dans la classe AR:
|
|
|
|
~~~
|
|
[php]
|
|
class Post extends CActiveRecord
|
|
{
|
|
public $title='veuillez entrer un titre';
|
|
......
|
|
}
|
|
|
|
$post=new Post;
|
|
echo $post->title; // cela afficherait: veuillez entrer un titre
|
|
~~~
|
|
|
|
A partir de la version 1.0.2, une valeur de type [CDbExpression] peut être
|
|
assignée à un attribut avant que l'enregistrement soit enregistré (en insertion ou
|
|
mise à jour) dans la base.
|
|
Par exemple, pour sauvegarder le timestamp retourné par la fonction MySQL `NOW()`, il
|
|
est possible d'utiliser le code suivant:
|
|
|
|
~~~
|
|
[php]
|
|
$post=new Post;
|
|
$post->create_time=new CDbExpression('NOW()');
|
|
// $post->create_time='NOW()'; ne fonctionnera pas car
|
|
// 'NOW()' sera traité comme une chaîne de caractères
|
|
$post->save();
|
|
~~~
|
|
|
|
> Tip: bien que AR permette des opérations sans avoir à écrire de requêtes SQL,
|
|
il est intéressant de savoir quelles requêtes SQL sont exécutées par AR.
|
|
Pour cela, il est possible d'activer la [fonctionnalité de log](/doc/guide/topics.logging)
|
|
de Yii. Par exemple, en activant [CWebLogRoute] dans la configuration de l'application,
|
|
les requêtes SQL seront affichées à la fin de chaque page web.
|
|
Depuis la version 1.0.5, il est possible de mettre [CDbConnection::enableParamLogging] à true
|
|
dans la configuration de l'application pour que les valeurs en paramètres liées aux requêtes SQL
|
|
apparaissent aussi dans le journal des logs.
|
|
|
|
|
|
Lecture des enregistrements
|
|
---------------------------
|
|
|
|
Pour lire des données d'une table, on appelle une des méthodes `find` comme suit:
|
|
|
|
~~~
|
|
[php]
|
|
// trouve la première ligne satisfaisant la condition
|
|
$post=Post::model()->find($condition,$params);
|
|
// trouve la ligne avec la clé primaire spécifiée
|
|
$post=Post::model()->findByPk($postID,$condition,$params);
|
|
// trouve la ligne avec les valeurs d'attributs spécifiées
|
|
$post=Post::model()->findByAttributes($attributes,$condition,$params);
|
|
// trouve la première ligne en utilisant la requête SQL spécifiée
|
|
$post=Post::model()->findBySql($sql,$params);
|
|
~~~
|
|
|
|
Ci-dessus, l'appel de la méthode `find` est effectué au travers de `Post::model()`.
|
|
Ne pas oublier que la méthode statique `model()` est indispensable pour toutes les classes AR.
|
|
La méthode retourne une instance AR qui est utilisée pour accéder aux méthodes de la classe
|
|
(de manière similaire aux méthodes des classes statiques) dans un contexte object.
|
|
|
|
Si la méthode `find` trouve une ligne satisfaisant les conditions de la requête, elle
|
|
retournera une instance de `Post` dont les propriétés contiendront les valeurs des colonnes
|
|
correspondantes de la ligne de la table. Il est alors possible de lire les valeurs chargées
|
|
de la même manière que pour un objet classique, par exemple, `echo $post->title;`.
|
|
|
|
La méthode `find` retournera null si rien n'a été trouvé en base.
|
|
|
|
Lors de l'appel à `find`, on utilise `$condition` et `$params` pour spécifier les conditions
|
|
à la requête. Ici `$condition` est une string représentant la clause `WHERE` d'une requête SQL,
|
|
et `$params` est un tableau de paramètres dont les valeurs devront être liées aux marques dans
|
|
`$condition`. Par exemple,
|
|
|
|
~~~
|
|
[php]
|
|
// trouve la ligne avec postID=10
|
|
$post=Post::model()->find('postID=:postID', array(':postID'=>10));
|
|
~~~
|
|
|
|
> Note: Dans le code ci-dessus, il est possible que vous deviez échapper la référence
|
|
à la colonne `postID` pour certain SGBD. Par exemple, si vous utilisez PostgreSQL,
|
|
vous devez écrire la condition `"postID"=:postID`, car PostgreSQL traite par défaut
|
|
les colonnes comme insensible à la casse.
|
|
|
|
Il est aussi possible d'utiliser `$condition` pour spécifier des conditions plus complexes.
|
|
A la place d'une chaîne de caractères, `$condition` pourra être une instance de [CDbCriteria],
|
|
ce qui permettra de spécifier des conditions autres que la clause `WHERE`. Par exemple,
|
|
|
|
~~~
|
|
[php]
|
|
$criteria=new CDbCriteria;
|
|
$criteria->select='titre'; // sélectionne seulement la colonne 'title'
|
|
$criteria->condition='postID=:postID';
|
|
$criteria->params=array(':postID'=>10);
|
|
$post=Post::model()->find($criteria); // $params n'est pas nécessaire
|
|
~~~
|
|
|
|
Notez que quand [CDbCriteria] est utilisé dans une condition de requête, le
|
|
paramètre `$params` n'est plus requis puisqu'il peut être spécifié dans [CDbCriteria],
|
|
comme on peut le voir ci-dessus.
|
|
|
|
Une autre méthode que l'utilisation de [CDbCriteria] est le passage d'un tableau
|
|
à la méthode `find`.
|
|
Les clés et valeurs du tableau correspondent alors respectivement aux noms et valeurs
|
|
des critères. Ainsi l'exemple ci-dessus peut être réécrit comme suit:
|
|
|
|
~~~
|
|
[php]
|
|
$post=Post::model()->find(array(
|
|
'select'=>'titre',
|
|
'condition'=>'postID=:postID',
|
|
'params'=>array(':postID'=>10),
|
|
));
|
|
~~~
|
|
|
|
> Info: Quand une condition a pour but de faire correspondre des colonnes avec
|
|
des valeurs, il est possible d'utiliser [findByAttributes()|CActiveRecord::findByAttributes].
|
|
Le paramètre `$attributes` est alors un tableau de valeurs avec pour clés les noms des colonnes.
|
|
Dans certains frameworks, cette tâche est accomplie en appelant des méthodes telles que `findByNameAndTitle`.
|
|
Bien que cette approche semble intéressante, elle sème souvent la confusion, et fait apparaître
|
|
des conflits et problèmes comme la sensibilité à la casse des noms de colonnes.
|
|
|
|
Quand plusieurs lignes de données correspondent à la condition spécifiée dans la requête, il est
|
|
possible de toutes les récupérer en une seule opération en utilisant les méthodes `findAll` ci-dessous, chacune d'entres elles possédant sa méthode équivalente `find`, telles que décrites précédemment.
|
|
|
|
~~~
|
|
[php]
|
|
// trouve toutes les lignes satisfaisant la condition spécifiée
|
|
$posts=Post::model()->findAll($condition,$params);
|
|
// trouve toutes les lignes possédant les clés primaires spécifiées
|
|
$posts=Post::model()->findAllByPk($postIDs,$condition,$params);
|
|
// trouve toutes les lignes possédant les valeurs des attributs spécifiés
|
|
$posts=Post::model()->findAllByAttributes($attributes,$condition,$params);
|
|
// trouve toutes les lignes en utilisant la requête SQL spécifiée
|
|
$posts=Post::model()->findAllBySql($sql,$params);
|
|
~~~
|
|
|
|
Si aucun enregistrement ne correspond à la condition de la requête, `findAll`
|
|
retournera un tableau vide. Ce comportement est différent en cela de `find` qui
|
|
retournera null si aucun enregistrement ne correspond.
|
|
|
|
En plus des méthodes `find` et `findAll` décrites ci-dessus, les méthodes suivantes
|
|
sont aussi disponibles:
|
|
|
|
~~~
|
|
[php]
|
|
// retourne le nombre d'enregistrements correspondant à la condition
|
|
$n=Post::model()->count($condition,$params);
|
|
// retourne le nombre d'enregistrements de la requête SQL spécifiée
|
|
$n=Post::model()->countBySql($sql,$params);
|
|
// regarde s'il y a au moins un enregistrement satisfaisant la condition spécifiée
|
|
$exists=Post::model()->exists($condition,$params);
|
|
~~~
|
|
|
|
Mise à jour d'un enregistrement
|
|
-------------------------------
|
|
|
|
Une fois qu'une instance AR contient les valeurs des colonnes, il est possible de les
|
|
changer et de les sauvegarder dans la table.
|
|
|
|
~~~
|
|
[php]
|
|
$post=Post::model()->findByPk(10);
|
|
$post->title='nouveau titre du post';
|
|
$post->save(); // enregistrement dans la base
|
|
~~~
|
|
|
|
Comme l'on peut le voir, la même méthode [save()|CActiveRecord::save] est utilisée
|
|
pour les opérations d'insertion et de mise à jour. Si une instance AR est créée
|
|
en utilisant l'opérateur `new`, l'appel à [save()|CActiveRecord::save] insère une
|
|
nouvelle ligne dans la table; si l'instance AR provient du résultat de méthodes telles que
|
|
`find` ou `findAll`, l'appel à [save()|CActiveRecord::save] met à jour la ligne
|
|
existante dans la table. En fait, il est possible d'utiliser [CActiveRecord::isNewRecord]
|
|
pour savoir si une instance AR existe ou non.
|
|
|
|
Il est aussi possible de mettre à jour une ou plusieurs lignes dans une table sans
|
|
les charger au préalable. AR inclut les méthodes suivantes au niveau de la classe
|
|
dans ce but:
|
|
|
|
~~~
|
|
[php]
|
|
// met à jour les lignes correspondant à la condition spécifiée
|
|
Post::model()->updateAll($attributes,$condition,$params);
|
|
// met à jour les lignes correspondant à la condition et aux clés primaires spécifiées
|
|
Post::model()->updateByPk($pk,$attributes,$condition,$params);
|
|
// met à jour les colonne de comptage pour les lignes satisfaisant les conditions spécifiées
|
|
Post::model()->updateCounters($counters,$condition,$params);
|
|
~~~
|
|
|
|
Ci-dessus, `$attributes` est un tableau de valeurs de colonnes dont les clés correspondent
|
|
aux noms des colonnes; `$counters` est une tableau de valeurs incrémentales dont les clés sont
|
|
les noms des colonnes; et `$condition` et `$params` sont les mêmes que dans les sections précédentes.
|
|
|
|
Suppression des enregistrements
|
|
-------------------------------
|
|
|
|
Il est aussi possible de supprimer une ligne de données si une instance AR à été
|
|
chargée avec cette ligne.
|
|
|
|
~~~
|
|
[php]
|
|
$post=Post::model()->findByPk(10); // on suppose qu'un post avec un ID à 10 existe
|
|
$post->delete(); // supprime la ligne dans la table
|
|
~~~
|
|
|
|
Attention, après suppression, l'instance AR reste inchangée, même si la ligne correspondante
|
|
dans la table a déjà été effectivement supprimée.
|
|
|
|
Les méthodes suivantes de la classe sont incluses afin de pouvoir supprimer des lignes
|
|
sans les avoir chargées auparavant:
|
|
|
|
~~~
|
|
[php]
|
|
// supprime les lignes correspondant à la condition spécifiée
|
|
Post::model()->deleteAll($condition,$params);
|
|
// supprime les lignes correspondant à la condition et aux clés primaires spécifiées
|
|
Post::model()->deleteByPk($pk,$condition,$params);
|
|
~~~
|
|
|
|
Validation des données
|
|
----------------------
|
|
|
|
Durant une insertion ou mise à jour d'une ligne, il est souvent nécessaire
|
|
de vérifier si les valeurs des colonnes suivent bien certaines règles. C'est
|
|
particulièrement important si ces valeurs proviennent des utilisateurs finaux.
|
|
En général, il ne faut jamais faire confiance aux données provenant du côté client.
|
|
|
|
AR va effectuer cette validation de données automatiquement quand la méthode [save()|CActiveRecord::save]
|
|
est appelée. La validation se base sur les règles définies dans la méthodes [rules()|CModel::rules]
|
|
de la classe AR. Pour plus de détails sur comment écrire ces règles de validation, veuillez consulter
|
|
la section [Declaration des règles de validation](/doc/guide/form.model#declaring-validation-rules).
|
|
Voici ci-dessous le déroulement typique lors de l'enregistrement d'une ligne:
|
|
|
|
~~~
|
|
[php]
|
|
if($post->save())
|
|
{
|
|
// données valides et insertion/mise à jour sans erreur
|
|
}
|
|
else
|
|
{
|
|
// données invalides. Un appel à getErrors() retournera les messages d'erreur
|
|
}
|
|
~~~
|
|
|
|
Quand les données à insérer ou mettre à jour sont fournies par les utilisateurs finaux
|
|
sous forme HTML, il faut les assigner aux propriétés correspondantes de l'AR. Voici comment
|
|
il est possible de faire cela:
|
|
|
|
~~~
|
|
[php]
|
|
$post->title=$_POST['title'];
|
|
$post->content=$_POST['content'];
|
|
$post->save();
|
|
~~~
|
|
|
|
S'il y avait de nombreuses colonnes, il faudrait faire de nombreuses assignations.
|
|
Cela peut être évité en utilisant la propriété [attributes|CActiveRecord::attributes]
|
|
comme montré ci-dessous. Plus de détails sont disponibles dans les sections
|
|
[Securing Attribute Assignments](/doc/guide/form.model#securing-attribute-assignments)
|
|
et [Creating Action](/doc/guide/form.action).
|
|
|
|
~~~
|
|
[php]
|
|
// on suppose que $_POST['Post'] est un tableau de valeurs
|
|
// dont les clés sont les noms de colonnes
|
|
$post->attributes=$_POST['Post'];
|
|
$post->save();
|
|
~~~
|
|
|
|
|
|
Comparaison d'enregistrements
|
|
-----------------------------
|
|
|
|
Tout comme les enregistrements d'une table, les instances AR sont identifiées
|
|
de manière unique grâce à la valeur de leur clé primaire. Ainsi, afin de comparer
|
|
deux instances AR, il suffit de comparer leur clé primaire. Cependant une façon plus
|
|
simple est d'appeler la méthode [CActiveRecord::equals()].
|
|
|
|
> Info: A la différence des implémentations de AR dans les autres frameworks, Yii supporte
|
|
les clés primaires composites dans les AR. Une clé composite est consistuée de deux colonnes
|
|
ou plus. Dans ce cas, la valeur de la clé primaire est représentée dans Yii comme un tableau.
|
|
La propriété [primaryKey|CActiveRecord::primaryKey] renvoie la valeur de la clé primaire
|
|
dans une instance AR.
|
|
|
|
Cas spécifiques
|
|
---------------
|
|
|
|
[CActiveRecord] fourni des méthodes qu'il est possible de surcharger pour modifier le
|
|
comportement de la classe.
|
|
|
|
- [beforeValidate|CModel::beforeValidate] et
|
|
[afterValidate|CModel::afterValidate]: invoquées avant et après la validation.
|
|
|
|
- [beforeSave|CActiveRecord::beforeSave] and
|
|
[afterSave|CActiveRecord::afterSave]: invoquées avant et après l'enregistrement d'une instance AR.
|
|
|
|
- [beforeDelete|CActiveRecord::beforeDelete] and
|
|
[afterDelete|CActiveRecord::afterDelete]: invoquées avant et après la suppression d'une instance AR.
|
|
|
|
- [afterConstruct|CActiveRecord::afterConstruct]: invoquée pour chaque instance AR créée avec
|
|
l'opérateur `new`.
|
|
|
|
- [beforeFind|CActiveRecord::beforeFind]: invoquée avant que le AR finder
|
|
exécute une requête (par exemple `find()`, `findAll()`). Disponible depuis la version 1.0.9.
|
|
|
|
- [afterFind|CActiveRecord::afterFind]: invoquée après chaque création d'instance AR
|
|
issue du résultat d'une requête.
|
|
|
|
|
|
Utilisation des transactions avec AR
|
|
------------------------------------
|
|
|
|
Chaque instance AR contient une propriété nommée
|
|
[dbConnection|CActiveRecord::dbConnection] qui est une instance de [CDbConnection].
|
|
Il est donc possible d'utiliser la fonctionnalité de [transaction](/doc/guide/database.dao#using-transactions)
|
|
fourni par Yii DAO si besoin:
|
|
|
|
~~~
|
|
[php]
|
|
$model=Post::model();
|
|
$transaction=$model->dbConnection->beginTransaction();
|
|
try
|
|
{
|
|
// find et sqve sont des actions qui peuvent se produirent dans une autre requête
|
|
// il faut donc utiliser une transaction pour garantir l'intégrité des données
|
|
$post=$model->findByPk(10);
|
|
$post->title='new post title';
|
|
$post->save();
|
|
$transaction->commit();
|
|
}
|
|
catch(Exception $e)
|
|
{
|
|
$transaction->rollBack();
|
|
}
|
|
~~~
|
|
|
|
|
|
Named Scopes
|
|
------------
|
|
|
|
> Note: Le support pour les named scopes est disponible depuis la version 1.0.5.
|
|
> L'idée originelle des named scopes provient de Ruby on Rails.
|
|
|
|
Un *named scope* représente un critère *named* d'une requête qui peut être combiné avec
|
|
d'autres named scopes et appliqués ensemble dans une requête sur un active record.
|
|
|
|
Les Named scopes sont normalement déclarés dans la méthode [CActiveRecord::scopes()] comme des paires de noms-critères. Le code suivant déclare deux named scopes, `published` et `recently`, dans la classe modélisant `Post`:
|
|
|
|
~~~
|
|
[php]
|
|
class Post extends CActiveRecord
|
|
{
|
|
......
|
|
public function scopes()
|
|
{
|
|
return array(
|
|
'published'=>array(
|
|
'condition'=>'status=1',
|
|
),
|
|
'recently'=>array(
|
|
'order'=>'create_time DESC',
|
|
'limit'=>5,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
~~~
|
|
|
|
Chaque named scope est déclaré comme un tableau qui est utilisé pour initialiser une instance [CDbCriteria]. Par exemple, le named scope `recently` indique que la propriété `order` sera `create_time DESC` et que la propriété `limit` sera 5, ce qui donne un critère de requête qui retournera les 5 posts les plus récents.
|
|
|
|
Les Named scopes vont principalement être utilisés pour altérer les appels aux méthodes `find`. Plusieurs named scopes peuvent être chainés ensemble pour restreindre les résultats de la requête. Par exemple, pour trouver les posts récemment publiés, il est possible de faire:
|
|
|
|
~~~
|
|
[php]
|
|
$posts=Post::model()->published()->recently()->findAll();
|
|
~~~
|
|
|
|
En général, les named scopes doivent se situer à gauche de l'appel à la méthode `find`. Chacun fournit un critère pour la requête, qui sera combiné avec les autres critères, dont celui passé en paramètre de la méthode `find`. Finalement cela revient à ajouter une liste de filtre à la requête.
|
|
|
|
A partir de la version 1.0.6, les named scopes peuvent aussi être utilisés avec les méthodes `update` et `delete`. Par exemple, le code suivant supprime tous les posts récemment publiés:
|
|
|
|
~~~
|
|
[php]
|
|
Post::model()->published()->recently()->delete();
|
|
~~~
|
|
|
|
> Note: Les Named scopes peuvent seulement être utilisé avec les méthodes du niveau de la classe. Ainsi la méthode doit être appelée en utilisant `ClassName::model()`.
|
|
|
|
|
|
### Named Scopes avec paramètres
|
|
|
|
Les Named scopes sont paramètrables. Par exemple, nous pourrions avoir besoin de configurer le nombre de posts indiqué dans le named scope `recently`. Pour cela, au lieu de déclarer le named scope dans la méthode [CActiveRecord::scopes], il faut le faire dans une nouvelle méthode dont le nom est le même que celui du named scope:
|
|
|
|
~~~
|
|
[php]
|
|
public function recently($limit=5)
|
|
{
|
|
$this->getDbCriteria()->mergeWith(array(
|
|
'order'=>'create_time DESC',
|
|
'limit'=>$limit,
|
|
));
|
|
return $this;
|
|
}
|
|
~~~
|
|
|
|
Il est alors possible d'utiliser le code ci-dessous pour récupérer les 3 posts récemment publiés:
|
|
|
|
~~~
|
|
[php]
|
|
$posts=Post::model()->published()->recently(3)->findAll();
|
|
~~~
|
|
|
|
Si le paramètre 3 ci-dessus n'est pas spécifié, les 5 derniers posts publiés sont renvoyés par défaut.
|
|
|
|
|
|
### Scope par défaut
|
|
|
|
Une classe peut avoir un named scope par défaut qui peut être appliqué à toutes les requêtes (dont les relationelles) sur un modèle. Par exemple, un site web supportant plusieurs langues souhaite afficher uniquement le contenu correspondant à la langue définie par l'utilisateur. Comme il se peut qu'il y ait beaucoup de requêtes concernant le contenu du site, il est possible de définir un named scope par défaut pour régler ce problème. Pour cela, il faut surcharger la méthode [CActiveRecord::defaultScope] comme ci-dessous:
|
|
|
|
~~~
|
|
[php]
|
|
class Content extends CActiveRecord
|
|
{
|
|
public function defaultScope()
|
|
{
|
|
return array(
|
|
'condition'=>"language='".Yii::app()->language."'",
|
|
);
|
|
}
|
|
}
|
|
~~~
|
|
|
|
Tous les appels aux méthodes find utiliseront alors automatiquement le critère défini ci-dessus.
|
|
|
|
~~~
|
|
[php]
|
|
$contents=Content::model()->findAll();
|
|
~~~
|
|
|
|
> Note: Le scope par défaut et les scopes nommés ne s'appliquent que sur les requêtes `SELECT`. Ils sont ignorés pour les requêtes `INSERT`, `UPDATE` et `DELETE`.
|
|
|
|
<div class="revision">$Id: database.ar.txt 1682 2013-11-20$</div>
|