Extension de fonctionnalités » History » Version 6
Simon, 07/04/2012 09:48 AM
1 | 1 | Simon | {{>toc}} |
---|---|---|---|
2 | |||
3 | |||
4 | h2. Généralités |
||
5 | |||
6 | |||
7 | 6 | Simon | Le système de plugins est conçu autour du composant "Event Dispatcher du framework symfony":http://components.symfony-project.org/event-dispatcher/documentation, basé sur le concept d'"Observer pattern":http://fr.wikipedia.org/wiki/Observateur_%28patron_de_conception%29. |
8 | 1 | Simon | |
9 | 5 | Simon | A l'exception des classes systèmes externes et dela classe _culture_, les classes peuvent être étendues par le système de plugin et la fonction magique __call(). (voir "documentation":http://components.symfony-project.org/event-dispatcher/trunk/book/02-Recipes#chapter_02_adding_methods_to_a_class) |
10 | 1 | Simon | |
11 | 6 | Simon | h2. Extension des fonctionnalités de l'application |
12 | 1 | Simon | |
13 | 6 | Simon | Il est, via le [[Systeme de Plugins|système de plugins]], aisé d'écouter un événement pour exécuter une nouvelle action lors de son appel. |
14 | 1 | Simon | |
15 | 6 | Simon | Nous allons par exemple créer un plugin qui logguera chaque tentative d'authentification. |
16 | 1 | Simon | |
17 | 6 | Simon | La fonction _AuthenthificationProcess()_ dans le fichier _/lib/functions_auth.php_ déclare l'événement *authentication.main_authentication* : |
18 | |||
19 | <pre> |
||
20 | <code class="php"> |
||
21 | |||
22 | function AuthenthificationProcess($login, $pass, $type) |
||
23 | { |
||
24 | // Notify the beginning of the current method |
||
25 | global $dispatcher; |
||
26 | $dispatcher->notify(new sfEvent(__FUNCTION__, 'authentication.main_authentication', array('login' => $login, 'password' => $pass, 'type' => $type))); |
||
27 | |||
28 | // ..... |
||
29 | // Processus d'authentification |
||
30 | } |
||
31 | |||
32 | </code> |
||
33 | </pre> |
||
34 | |||
35 | Le fichier __init__.php du nouveau plugin devra contenir les instructions suivantes : |
||
36 | |||
37 | <pre> |
||
38 | <code class="php"> |
||
39 | |||
40 | // Log de l'authentification dans [path to app]/tmp |
||
41 | function logAction(sfEvent $event) { |
||
42 | $a[0]= $event['login']. " s'est authentifé le ".date('d/n/Y à H:i:s')." depuis ". $event['type']; |
||
43 | logfile(SITE_PATH.'/tmp/auth.log', $a); |
||
44 | } |
||
45 | |||
46 | // Execute la fonction logAction lorsque l'événement authentication.main_authentication est notifié |
||
47 | $dispatcher->connect('authentication.main_authentication', 'logAction'); |
||
48 | |||
49 | </code> |
||
50 | </pre> |
||
51 | |||
52 | Votre plugin est terminé! Chaque fois qu'un utilisateur s'authentifiera, le fichier _auth.log_ sera renseigné. |
||
53 | |||
54 | |||
55 | h2. Ajout d'une méthode grâce à la fonction magique __call() |
||
56 | |||
57 | |||
58 | La fonction magique __call() permet de traiter les méthodes non déclarées dans la classe. Couplée avec le motif de conception observeur/observable, elle va nous permettre d'étendre la classe. |
||
59 | |||
60 | Remarque : L'événement créé par Linea21 se nomme *[nom_de_la_class].extensible_function*. |
||
61 | |||
62 | A titre d'illustration, voici un exemple d'implémentation sur le module News (qui gère l'actualité) : |
||
63 | |||
64 | 1 | Simon | <pre><code class="php"> |
65 | |||
66 | 6 | Simon | public function __call($method, $arguments) |
67 | 1 | Simon | { |
68 | 6 | Simon | $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'news.extensible_function', array( |
69 | 'method' => $method, |
||
70 | 'arguments' => $arguments |
||
71 | ))); |
||
72 | if (!$event->isProcessed()) |
||
73 | { |
||
74 | throw new Exception(sprintf('Call to undefined method %s::%s.', get_class($this), $method)); |
||
75 | } |
||
76 | 1 | Simon | |
77 | 6 | Simon | return $event->getReturnValue(); |
78 | 1 | Simon | } |
79 | 6 | Simon | |
80 | 1 | Simon | </code> |
81 | </pre> |
||
82 | |||
83 | 6 | Simon | |
84 | |||
85 | 1 | Simon | Dans le <code>__init__.php</code> de mon plugin : |
86 | |||
87 | |||
88 | <pre><code class="php"> |
||
89 | |||
90 | 6 | Simon | // 1 -Création de la classe extensibleNews() et ajout des méthodes |
91 | class extensibleNews |
||
92 | 1 | Simon | { |
93 | 6 | Simon | static public function listenToMethodNotFound(sfEvent $event) |
94 | { |
||
95 | 1 | Simon | |
96 | 6 | Simon | switch ($event['method']) |
97 | { |
||
98 | case 'performAction': |
||
99 | self::doTest($event->getSubject(), $event['arguments']); |
||
100 | return true; |
||
101 | default: |
||
102 | return false; |
||
103 | } |
||
104 | } |
||
105 | |||
106 | static private function performAction($subject, $arguments) |
||
107 | { |
||
108 | if(is_string($arguments)) $msg = $arguments; |
||
109 | if(is_array($arguments)) $msg = join(', ', $arguments); |
||
110 | mail('info@xxxx.com', 'extension de Linea21', 'Voici les arguments passés à ma fonction : '. $msg); |
||
111 | _debug('[event/dispatcher] (INTERNAL) - we run ' . __FUNCTION__ . '() function by extensibleFunc() call with arguments : '. $msg); |
||
112 | } |
||
113 | |||
114 | 1 | Simon | } |
115 | 2 | Simon | |
116 | 6 | Simon | // 2 - On connecte l'événement en précisant la classe et la méthode à appeler |
117 | $dispatcher->connect('news.extensible_function', array('extensibleNews', 'listenToMethodNotFound')); |
||
118 | |||
119 | // 3 - Enfin, on appelle la nouvelle méthode depuis l'objet news |
||
120 | // ici après un test conditionnel pour exécuter l'action sur la section 'news' seulement |
||
121 | if(isset($_REQUEST['rub']) && $_REQUEST['rub'] == 'news') { |
||
122 | include_once '../class/class.news.php'; |
||
123 | $n = new news; |
||
124 | $n->performAction('arg 1', 'arg 2', 'arg 3'); |
||
125 | } |
||
126 | |||
127 | 1 | Simon | </code> |
128 | </pre> |