Aller au menu - Aller au contenu

Icône TP : Création d'un template

Avatar
Mise à jour : 04/09/2010
Difficulté : Intermédiaire Intermédiaire Creative Commons BY-NC-SA
487 visites depuis 7 jours, dont 8 sur ce chapitre classé 233/786
Les deux chapitres précédents étaient assez théoriques. Ici, vous allez mettre en pratique tout ça ! ;)
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Créer son propre template

Maintenant que vous voyez un peu comment les templates fonctionnent, et à quoi ils servent, vous allez certainement vouloir en créer de nouveaux adaptés à vos besoins.

Introduction



Nous allons détailler ici toutes les étapes de la création de notre template.
Je vais continuer avec l'exemple de notre article, que j'utilise depuis le début du tutoriel. Nous voulons maintenant que le nom de l'auteur original (celui qui a créé l'article), et le nom de la dernière personne à l'avoir modifié, soient enregistrés automatiquement.
Nous allons aussi ajouter un champ qui indiquera si l'article est disponible ou non en lecture pour les visiteurs. Le fonctionnement ressemblera à SoftDelete et cela permettra d'assimiler un peu mieux le fonctionnement des évènements.

Je vous propose de nommer notre template Publishable. ;)

Avant de commencer, vous pouvez supprimer la colonne user_id et la relation Article-User que nous avons définies dans le schéma. N'oubliez pas ensuite de tout reconstruire en appelant ~/web/builder.php.


Création de la classe



Je vous ai dit dans le chapitre précédent que le fonctionnement des templates ressemblait à celui des objets Doctrine_Record. Et pour cause : Doctrine_Template hérite de la même classe de base, Doctrine_Record_Abstract.
Ils utilisent donc les mêmes méthodes pour se configurer : setUp() et setTableDefinition().

Nous définirons donc les colonnes à ajouter à l'intérieur de setTableDefinition(), tandis que setUp() servira à définir les relations.

Nous allons placer tous nos templates dans ~/lib/models/templates/.

Code : PHP - ~/lib/models/templates/Doctrine_Template_Publishable.php
1
2
3
4
<?php

class Doctrine_Template_Publishable extends Doctrine_Template
{ }


Notez que j'ai préfixé le nom du template de Doctrine_Template_, mais vous n'y êtes pas obligés. Si vous utilisez un préfixe particulier dans votre projet, vous pouvez tout à fait l'utiliser, ou même l'appeler Publishable tout court.
Seul petit détail : si vous placez un préfixe (autre que Doctrine_Template_), il vous faudra utiliser le nom complet lors de la définition avec actAs(), sinon Doctrine ne pourra pas le trouver et le charger automatiquement. À moins de définir votre propre autoloader... mais ça n'entre pas dans le cadre de ce cours. Bref, vous faites comme vous voulez. ;)


Détails supplémentaires



Vous avez le code de base de la classe, maintenant, à vous de jouer ! ;)

Trois colonnes seront nécessaires pour ce template. Nommez-les comme vous le voulez. ;) Deux d'entre elles contiendront des références à des utilisateurs (par exemple leur ID). La troisième sera simplement de type booléen.

Notez qu'il n'est pas obligatoire du tout d'utiliser l'attribut $_options. Néanmoins, je vous encourage à le faire, la personnalisation depuis le schéma étant impossible sinon. À vous de choisir quelles options implémenter (aidez-vous des options « classiques » que vous trouverez dans les autres templates existants ;) ).
Les colonnes supplémentaires sont à ajouter dans la méthode setTableDefinition(), et les relations à l'intérieur de setUp().

Ajout d'un listener



Je vous propose d'ajouter un listener au template. Il servira notamment pour la mise à jour automatique de l'auteur de l'article.

Pour rappel, il doit hériter de Doctrine_Record_Listener.
Créez un répertoire ~/lib/models/templates/listeners/. Nous placerons nos listeners ici.
Je vous propose d'appeler notre classe Doctrine_Template_Listener_Publishable.

Pour le construire, commencez par vous demander quelles méthodes seront utiles (c'est-à-dire quels évènements intercepter).

Correction : le template

Vous avez bien travaillé ? Vous n'avez pas trouvé comment faire ?

Voici ci-dessous la correction détaillée.

Les options



Tout d'abord, voici un exemple d'options possibles. Bien sûr, ce n'est pas LA correction unique, vous mettez les options que vous voulez ! ;)

Code : PHP - ~/lib/models/templates/Doctrine_Template_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php

class Doctrine_Template_Publishable extends Doctrine_Template
{
    protected $_options = array(
        'created' => array(
            // Nom de la colonne 'auteur original'.
            'name'     => 'created_by',
            // Alias. On pourra faire $article->OriginalAuthor.
            'alias'    => 'OriginalAuthor',
            // Classe représentant un auteur.
            'class'    => 'User',
            // Champ de la classe User servant à la relation.
            'foreign'  => 'id',
            // Type du champ, on stocke l'ID, donc integer.
            'type'     => 'integer',
            // On donne la possibilité de ne pas utiliser cette colonne.
            'disabled' => false,
            // Options supplémentaires pour la colonne (notnull, default, etc.).
            'options'  => array(),
        ),
        // Mêmes options pour la colonne du dernier auteur.
        'updated' => array(
            'name'     => 'updated_by',
            'alias'    => 'Author',
            'class'    => 'User',
            'foreign'  => 'id',
            'type'     => 'integer',
            'disabled' => false,
            'options'  => array(),
        ),
        // Options pour la colonne 'publiable'.
        'publishable' => array(
            'name'     => 'is_publishable',
            'alias'    => null,
            'type'     => 'boolean',
            'disabled' => false,
            // Par défaut, l'article sera publiable.
            'options'  => array('notnull' => true, 'default' => true),
        ),
    );

    /* ... */
}


Comme vous le voyez, j'ai repris les options présentes dans la plupart des templates : on donne la possibilité de désactiver certaines colonnes, d'ajouter des alias pour accéder aux auteurs, etc.
L'option class indique quelle classe sera utilisée pour la relation (c'est-à-dire celle qui représente un auteur, un membre, etc. : toute personne susceptible de rédiger l'article), et foreign indique le nom de la colonne sur laquelle la relation est définie (par défaut, id).

Les colonnes



Nous allons, comme nous l'avons dit, ajouter deux champs à notre table. Il n'y a rien d'extraordinaire, c'est exactement pareil que lors de la définition du schéma dans les classes de base.

Code : PHP - ~/lib/models/templates/Doctrine_Template_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php

class Doctrine_Template_Publishable extends Doctrine_Template
{
    /* ... */

    public function setTableDefinition()
    {
        if(!$this->_options['created']['disabled']) {
            $this->hasColumn(
                $this->_options['created']['name'],
                $this->_options['created']['type'],
                null,
                $this->_options['created']['options']
            );
        }
  
        if(!$this->_options['updated']['disabled']) {
            $this->hasColumn(
                $this->_options['updated']['name'],
                $this->_options['updated']['type'],
                null,
                $this->_options['updated']['options']
            );
        }
  
        if(!$this->_options['publishable']['disabled']) {
            $name = $this->_options['publishable']['name'];
            if($this->_options['publishable']['alias']) {
                $name .= ' as '.$this->_options['publishable']['alias'];
            }
      
            $this->hasColumn(
                $name,
                $this->_options['publishable']['type'],
                null,
                $this->_options['publishable']['options']
            );
        }
    }
  
    /* ... */
}


Nous vérifions pour chaque élément qu'il n'est pas désactivé, et nous ajoutons la colonne au modèle en conséquence, en utilisant les options définies plus haut. Encore une fois, rien de spécial, la définition des colonnes se fait de la même manière que dans les classes de base.

Les relations



Nous avons choisi d'enregistrer l'ID de l'auteur original, et l'ID du dernier auteur à avoir modifié l'article. Nous allons donc définir deux relations dans la méthode setUp().

Code : PHP - ~/lib/models/templates/Doctrine_Template_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

class Doctrine_Template_Publishable extends Doctrine_Template
{
    /* ... */

    public function setUp()
    {
        if(!$this->_options['created']['disabled']) {
            $name = $this->_options['created']['class'];
            if($this->_options['created']['alias']) {
                $name .= ' as '.$this->_options['created']['alias'];
            }
      
            $this->hasOne($name, array(
                'local'   => $this->_options['created']['name'],
                'foreign' => $this->_options['created']['foreign']
            ));
        }

        if(!$this->_options['updated']['disabled']) {
            $name = $this->_options['updated']['class'];
            if($this->_options['updated']['alias']) {
                $name .= ' as '.$this->_options['updated']['alias'];
            }
      
            $this->hasOne($name, array(
                'local'   => $this->_options['updated']['name'],
                'foreign' => $this->_options['updated']['foreign']
            ));
        }
    }
}


Une fois encore, la manière d'indiquer les relations ne diffère pas de lors de la définition du schéma. L'option name est utilisée en tant que clé locale, et foreign en tant que clé étrangère. class indique la classe à lier, et alias un éventuel alias (par défaut, OriginalAuthor et Author).

Voilà, à ce stade, nous avons défini toutes les colonnes et relations nécessaires à notre template. Nous pouvons par exemple accéder au login de la dernière personne ayant modifié un article :

Code : PHP
1
2
3
4
5
<?php

echo $article->Author->login;

$article->Author = $monObjetUser;

Correction : le listener

Sans le listener associé, notre template serait bien peu pratique. ^^


Réfléchissons à ce que nous voulons obtenir.
  • Nous voulons que l'auteur soit ajouté lors du premier enregistrement de notre article. La méthode à utiliser est preInsert().
  • Nous voulons aussi qu'à chaque modification, le nom de l'auteur soit également mis à jour. Nous nous servirons de preUpdate(). preDqlUpdate() sera aussi utilisé, lorsque la mise à jour est effectuée depuis une requête DQL (construite à la main, reportez-vous au chapitre sur la manipulation des données pour plus de détails ;) ).
  • Pour filtrer automatiquement les articles non publiables afin qu'ils n'apparaissent pas lors d'une sélection de données, preDqlSelect() sera ici utile.


Voyons dès à présent le code de base de la classe :

Code : PHP - ~/lib/models/templates/listeners/Doctrine_Template_Listener_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

class Doctrine_Template_Listener_Publishable extends Doctrine_Record_Listener
{
    protected $_options = array();
  
    public function __construct(array $options)
    {
        $this->_options = $options;
    }
  
    public function preInsert(Doctrine_Event $event)
    { }
  
    public function preUpdate(Doctrine_Event $event)
    { }
  
    public function preDqlUpdate(Doctrine_Event $event)
    { }

    public function preDqlSelect(Doctrine_Event $event)
    { }

    protected function getCurrentUserId()
    {
        // À adapter à votre projet, bien sûr
        return $_SESSION['user_id'];
    }
}


Nous avons défini nos quatre méthodes. Nous récupérons aussi les options du template dans l'attribut $_options car nous en aurons besoin.

Chacune de ces méthodes reçoit en paramètre l'objet Doctrine_Event représentant l'évènement. Il nous sera possible de récupérer les objets concernés à partir de celui-ci.

Notez que nous savons déjà que l'on va avoir besoin de connaître l'utilisateur courant (celui qui rédige et sauvegarde l'article). Le rôle de la méthode getCurrentUserId() est de nous renvoyer... son ID. :) Bien entendu, la manière de le récupérer va différer selon votre projet. À vous d'adapter cela. ;)

S'il y en a parmi vous qui utilisent Symfony, vous pourrez le récupérer avec quelque chose de similaire à <?php sfContext::getInstance()->getUser()->getId();.


Pré-insertion d'un article




Nous allons ici travailler dans la méthode preInsert(), c'est-à-dire lors du premier enregistrement de l'article.

Code : PHP - ~/lib/models/templates/listeners/Doctrine_Template_Listener_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php

class Doctrine_Template_Listener_Publishable extends Doctrine_Record_Listener
{
    /* ... */
  
    public function preInsert(Doctrine_Event $event)
    {
        // On récupère ce dont on aura besoin.
        $invoker        = $event->getInvoker();
        $invokerTable   = $invoker->getTable();
        $modifiedFields = $invoker->getModified();

        // Si cette colonne n'est pas désactivée :
        if(!$this->_options['created']['disabled']) {
            $createdField = $invokerTable->getFieldName($this->_options['created']['name']);

            // On s'assure que le champ n'a pas été modifié manuellement.
            if(!isset($modifiedFields[$createdField])) {
                // On met le champ à jour.
                $invoker->$createdField = $this->getCurrentUserId();
            }
        }

        // Si cette colonne n'est pas désactivée :
        if(!$this->_options['updated']['disabled']) {
            $updatedField = $invokerTable->getFieldName($this->_options['updated']['name']);
    
            // On s'assure que le champ n'a pas été modifié manuellement.
            if(!isset($modifiedFields[$updatedField])) {
                // On met le champ à jour.
                $invoker->$updatedField = $this->getCurrentUserId();
            }
        }
    }
  
    /* ... */
}


L'objet $event est capable de nous retourner l'objet concerné avec la méthode getInvoker(). Doctrine_Record possède une méthode getTable() qui nous retourne une instance de cette table (donc, la classe ArticleTable).

Petit détail
La méthode Doctrine_Record::getModified() retourne la liste des champs de l'objet qui ont été modifiés.
Avant de mettre à jour les champs concernant l'auteur, nous vérifions que ceux-ci n'ont pas été modifiés manuellement (pour une quelconque raison). Si c'est le cas, alors on ne les modifie pas.

Enfin, si la colonne n'est pas désactivée (souvenez-vous que nous avons connaissance des options du template), on la met à jour en récupérant l'ID de l'utilisateur courant.

Mise à jour d'un article



Lors de la mise à jour d'un article, nous modifions seulement la valeur de la colonne updated.
Nous allons ici travailler sur deux méthodes : preUpdate() lors d'une mise à jour par l'objet directement, et preDqlUpdate() lors d'une mise à jour par l'intermédiaire d'une requête DQL.

Premier cas : avec Doctrine_Record



Commençons par preUpdate(). C'est identique à précédemment.

Code : PHP - ~/lib/models/templates/listeners/Doctrine_Template_Listener_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

class Doctrine_Template_Listener_Publishable extends Doctrine_Record_Listener
{
    /* ... */

    public function preUpdate(Doctrine_Event $event)
    {
        // On récupère ce dont on aura besoin.
        $invoker        = $event->getInvoker();
        $invokerTable   = $invoker->getTable();
        $modifiedFields = $invoker->getModified();

        // Si cette colonne n'est pas désactivée :
        if(!$this->_options['updated']['disabled']) {
            $updatedField = $invokerTable->getFieldName($this->_options['updated']['name']);
     
            // On s'assure que le champ n'a pas été modifié manuellement.
            if(!isset($modifiedFields[$updatedField])) {
                // On met le champ à jour.
                $invoker->$updatedField = $this->getCurrentUserId();
            }
        }
    }

    /* ... */
}


Second cas : avec Doctrine_Query



Voyons maintenant comment gérer ça lors d'une requête DQL :

Code : PHP - ~/lib/models/templates/listeners/Doctrine_Template_Listener_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

class Doctrine_Template_Listener_Publishable extends Doctrine_Record_Listener
{
    /* ... */

    public function preDqlUpdate(Doctrine_Event $event)
    {
        // Si cette colonne n'est pas désactivée :
        if(!$this->_options['updated']['disabled']) {
            // On récupère ce dont on aura besoin.
            $invokerTable = $event->getInvoker()->getTable();
            $params       = $event->getParams();
            $updatedField = $invokerTable->getFieldName($this->_options['updated']['name']);
            $q            = $event->getQuery();
            $field        = $params['alias'].'.'.$updatedField;  // Contient par exemple 'a.updated_by'

            // On s'assure que le champ n'a pas été modifié manuellement.
            if(!$q->contains($field)) {
                // On met le champ à jour.
                $q->set($field, '?', $this->getCurrentUserId());
            }
        }
    }

    /* ... */
}


L'objet $event nous permet de récupérer la requête associée avec getQuery(). $params contient... des paramètres ! En l'occurrence, nous nous intéressons à $params['alias'] qui contient l'alias utilisé dans la requête (que j'appelle souvent 'a'). Notez par la même occasion que l'alias principal de la requête peut aussi être récupéré avec <?php $q->getRootAlias().

Pour nous assurer que le champ n'a pas été modifié à la main, et ne pas écraser les modifications, nous vérifions que la requête ne le contient pas avec Doctrine_Query::contains(). Si tout est bon, alors on peut l'ajouter à notre requête avec set().

Voilà, à ce stade, à chaque fois que l'on créera/modifiera un article, le nom de l'auteur original et du dernier à l'avoir modifié seront automatiquement renseignés. Magique, non ? ;)

Sélection d'articles



Reste un détail. Nous ne voulons pas qu'un article marqué comme supprimé apparaisse lorsque nous effectuons des sélections dans la base. Il nous faut pour ça modifier la requête à la volée.
Utilisons preDqlSelect() :

Code : PHP - ~/lib/models/templates/listeners/Doctrine_Template_Listener_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

class Doctrine_Template_Listener_Publishable extends Doctrine_Record_Listener
{
    /* ... */
  
    public function preDqlSelect(Doctrine_Event $event)
    {
        // Si cette colonne n'est pas désactivée :
        if(!$this->_options['publishable']['disabled']) {
            // On récupère ce dont on aura besoin.
            $q      = $event->getQuery();
            $params = $event->getParams();
            $field  = $params['alias'].'.'.$this->_options['publishable']['name'];
    
            // On vérifie qu'il faille appliquer la restriction.
            if(!$q->contains($field)) {
                $q->andWhere($field.' = ?', true);
            }
        }
    }
  
    /* ... */
}


Premièrement, nous nous assurons que la colonne est activée, et nous récupérons les objets dont nous avons besoin.
Ensuite, on s'assure que la requête ne contient pas déjà ce champ, et on ajoute une condition sur celui-ci.

Et bien, chers amis, j'ai une bonne nouvelle, notre listener est terminé ! :)

Conclusion

Notre template ainsi que son listener sont maintenant opérationnels. :soleil:

Liaison des composants



Il reste juste une chose à régler : l'utiliser dans le template ! En effet, nous n'avons pas encore indiqué au template qu'il doit l'utiliser.

La méthode addListener() est là pour ça. Mais vous le saviez déjà, non ?
Nous l'appellerons dans setTableDefinition() :

Code : PHP - ~/lib/models/templates/Doctrine_Template_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php

class Doctrine_Template_Publishable extends Doctrine_Template
{
    /* ... */

    public function setTableDefinition()
    {
        /* ... */

        $this->addListener(new Doctrine_Template_Listener_Publishable($this->_options));
    }
    
    /* ... */
}


Résumé



Je vous donne ci-dessous le code complet du template et du listener. Oh que je suis gentil ! :D

Doctrine_Template_Publishable :
Secret (cliquez pour afficher)
Code : PHP - ~/lib/models/templates/Doctrine_Template_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?php

class Doctrine_Template_Publishable extends Doctrine_Template
{
    protected $_options = array(
        'created' => array(
            'name'     => 'created_by',
            'alias'    => 'OriginalAuthor',
            'class'    => 'User',
            'foreign'  => 'id',
            'type'     => 'integer',
            'disabled' => false,
            'options'  => array(),
        ),
        'updated' => array(
            'name'     => 'updated_by',
            'alias'    => 'Author',
            'class'    => 'User',
            'foreign'  => 'id',
            'type'     => 'integer',
            'disabled' => false,
            'options'  => array(),
        ),
        'publishable' => array(
            'name'     => 'is_publishable',
            'alias'    => null,
            'type'     => 'boolean',
            'disabled' => false,
            'options'  => array('notnull' => true, 'default' => true),
        ),
    );

    public function setTableDefinition()
    {
        if(!$this->_options['created']['disabled']) {
            $this->hasColumn(
                $this->_options['created']['name'],
                $this->_options['created']['type'],
                null,
                $this->_options['created']['options']
            );
        }
  
        if(!$this->_options['updated']['disabled']) {
            $this->hasColumn(
                $this->_options['updated']['name'],
                $this->_options['updated']['type'],
                null,
                $this->_options['updated']['options']
            );
        }
  
        if(!$this->_options['publishable']['disabled']) {
            $name = $this->_options['publishable']['name'];
            if($this->_options['publishable']['alias']) {
                $name .= ' as '.$this->_options['publishable']['alias'];
            }
      
            $this->hasColumn(
                $name,
                $this->_options['publishable']['type'],
                null,
                $this->_options['publishable']['options']
            );
        }

        $this->addListener(new Doctrine_Template_Listener_Publishable($this->_options));
    }

    public function setUp()
    {
        if(!$this->_options['created']['disabled']) {
            $name = $this->_options['created']['class'];
            if($this->_options['created']['alias']) {
                $name .= ' as '.$this->_options['created']['alias'];
            }
      
            $this->hasOne($name, array(
                'local'   => $this->_options['created']['name'],
                'foreign' => $this->_options['created']['foreign']
            ));
        }

        if(!$this->_options['updated']['disabled']) {
            $name = $this->_options['updated']['class'];
            if($this->_options['updated']['alias']) {
                $name .= ' as '.$this->_options['updated']['alias'];
            }
      
            $this->hasOne($name, array(
                'local'   => $this->_options['updated']['name'],
                'foreign' => $this->_options['updated']['foreign']
            ));
        }
    }
}


Doctrine_Template_Listener_Publishable :
Secret (cliquez pour afficher)
Code : PHP - ~/lib/models/templates/listeners/Doctrine_Template_Listener_Publishable.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<?php

class Doctrine_Template_Listener_Publishable extends Doctrine_Record_Listener
{
    protected $_options = array();
  
    public function __construct(array $options)
    {
        $this->_options = $options;
    }
  
    public function preInsert(Doctrine_Event $event)
    {
        $invoker        = $event->getInvoker();
        $invokerTable   = $invoker->getTable();
        $modifiedFields = $invoker->getModified();

        if(!$this->_options['created']['disabled']) {
            $createdField = $invokerTable->getFieldName($this->_options['created']['name']);

            if(!isset($modifiedFields[$createdField])) {
                $invoker->$createdField = $this->getCurrentUserId();
            }
        }

        if(!$this->_options['updated']['disabled']) {
            $updatedField = $invokerTable->getFieldName($this->_options['updated']['name']);
    
            if(!isset($modifiedFields[$updatedField])) {
                $invoker->$updatedField = $this->getCurrentUserId();
            }
        }
    }
  
    public function preUpdate(Doctrine_Event $event)
    {
        $invoker        = $event->getInvoker();
        $invokerTable   = $invoker->getTable();
        $modifiedFields = $invoker->getModified();

        if(!$this->_options['updated']['disabled']) {
            $updatedField = $invokerTable->getFieldName($this->_options['updated']['name']);
     
            if(!isset($modifiedFields[$updatedField])) {
                $invoker->$updatedField = $this->getCurrentUserId();
            }
        }
    }
  
    public function preDqlUpdate(Doctrine_Event $event)
    {
        if(!$this->_options['updated']['disabled']) {
            $invokerTable = $event->getInvoker()->getTable();
            $params       = $event->getParams();
            $updatedField = $invokerTable->getFieldName($this->_options['updated']['name']);
            $q            = $event->getQuery();
            $field        = $params['alias'].'.'.$updatedField;

            if(!$q->contains($field)) {
                $q->set($field, '?', $this->getCurrentUserId());
            }
        }
    }

    public function preDqlSelect(Doctrine_Event $event)
    {
        if(!$this->_options['publishable']['disabled']) {
            $q      = $event->getQuery();
            $params = $event->getParams();
            $field  = $params['alias'].'.'.$this->_options['publishable']['name'];
    
            if(!$q->contains($field)) {
                $q->andWhere($field.' = ?', true);
            }
        }
    }

    protected function getCurrentUserId()
    {
        // À adapter à votre projet, bien sûr.
        return $_SESSION['user_id'];
    }
}


Et maintenant ?



Ce TP est bien sûr un exemple parmi tant d'autres. Il y a notamment une notion que nous n'avons pas abordé : le partage de méthodes. Vous vous souvenez ?
Maintenant, à vous de jouer pour trouver des idées afin d'améliorer ce p'tit behavior. ;)
Vous avez pu apercevoir dans ce chapitre la grande modularité qu'offre Doctrine et l'intérêt des templates.
Attention cependant, ne les utilisez pas à tort et à travers ! Et souvenez-vous aussi que vous pouvez tout à fait ajouter un listener sur un objet en particulier, et non obligatoirement sur une classe entière !
Chapitre précédent Sommaire Chapitre suivant

Partager

2 commentaires pour "TP : Création d'un template"
Note moyenne : 3.54 / 4 (35 votes)
Pseudo Commentaire
Hors ligne Nami Doc # Posté le 30/08/2010 à 15:39:55
Lamaer taler dansk

Avis : Très bon

Très bon "semi-TP" :) ! Tu montres bien globalement comment faire (peut-être devrais-tu re-préciser pour les callbacks DQL), c'est plutôt bien expliqué, et complet.

La flemme conquerra le monde !
Secret (cliquez pour afficher)
Image utilisateur
 
Hors ligne Vermicelle # Posté le 04/11/2010 à 18:00:58

Bravo, c'est génial :)

Merci beaucoup, je viens de gagner du temps!

Voir tous les commentaires
Ce tutoriel a été corrigé par les zCorrecteurs.