Completed
Push — master ( 00e474...9d3fbd )
by Michael
04:26
created

class/oledrion_plugins.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
/**
13
 * oledrion
14
 *
15
 * @copyright   {@link http://xoops.org/ XOOPS Project}
16
 * @license     {@link http://www.fsf.org/copyleft/gpl.html GNU public license}
17
 * @author      Hervé Thouzard (http://www.herve-thouzard.com/)
18
 */
19
20
/**
21
 * Gestion des plugins du module
22
 *
23
 * On distingue les "filtres" (plugin qui reçoit du contenu qu'il peut modifier et dont le retour est passé au filtre suivant)
24
 * des "actions" (plugin qui est généralement appelé sur un évènement et qui ne doit rien modifier).
25
 *
26
 * Chaque plugin dispose d'une priorité de 1 à 5, 1 étant la priorité la plus haute, 5 la plus basse
27
 *
28
 * Dans le répertoire plugins on a 2 sous répertoires, "actions" et "filters", en fonction du type du plugin
29
 *
30
 * Chaque plugin doit se trouver dans son propre sous-répertoire, par exemple :
31
 *     /xoops/modules/oledrion/plugins/pdf/
32
 *
33
 * Cela permet aux plugins d'avoir plusieurs fichiers et de ne pas les mélanger avec les autres plugins
34
 *
35
 * Le module scrute ces 2 répertoires ("actions" et "filters") pour charger les plugins.
36
 * Chaque répertoire doit contenir un script "plugins.php" qui permet la descriptions des plugins qui se trouvent dans ce répertoire.
37
 * A titre d'exemple, voir ceux fournits de base avec le module
38
 *
39
 * Les modèles de classe à étendre se trouvent dans /xoops/modules/oledrion/plugins/modules/oledrion_action.php et oledrion_filter.php
40
 *
41
 * @since 2.31
42
 */
43
class Oledrion_plugins
44
{
45
    /**
46
     * Dictionnaire des évènements
47
     */
48
    const EVENT_ON_PRODUCT_CREATE = 'onProductCreate';
49
    const EVENT_ON_CATEGORY_CREATE = 'onCategoryCreate';
50
    const EVENT_ON_PRODUCT_DOWNLOAD = 'onProductDownload';
51
    // **************************************************************
52
53
    /**
54
     * Types d'évènements
55
     */
56
    const PLUGIN_ACTION = 0;
57
    const PLUGIN_FILTER = 1;
58
59
    /**
60
     * Nom du script Php inclut qui contient l'inscription des plugins
61
     */
62
    const PLUGIN_SCRIPT_NAME = 'plugins.php';
63
64
    /**
65
     * Dans le fichier Php qui contient l'inscription des plugins, méthode à appeler pour récupérer la liste des plugins
66
     */
67
    const PLUGIN_DESCRIBE_METHOD = 'registerEvents';
68
69
    /**
70
     * Nom de la variable de session qui contient la liste des plugins détachés
71
     */
72
    const PLUGIN_UNPLUG_SESSION_NAME = 'oledrion_plugins';
73
74
    /**
75
     * Priorités des plugins
76
     * @var constant
77
     */
78
    const EVENT_PRIORITY_1 = 1; // Priorité la plus haute
79
    const EVENT_PRIORITY_2 = 2;
80
    const EVENT_PRIORITY_3 = 3;
81
    const EVENT_PRIORITY_4 = 4;
82
    const EVENT_PRIORITY_5 = 5; // Priorité la plus basse
83
84
    /**
85
     * Utilisé pour construire le nom de la classe
86
     */
87
    private $pluginsTypeLabel = array(self::PLUGIN_ACTION => 'Action', self::PLUGIN_FILTER => 'Filter');
88
89
    /**
90
     * Nom des classes qu'il faut étendre en tant que plugin
91
     */
92
    private $pluginsClassName = array(
93
        self::PLUGIN_ACTION => 'oledrion_action',
94
        self::PLUGIN_FILTER => 'oledrion_filter'
95
    );
96
97
    /**
98
     * Nom de chacun des dossiers en fonction du type de plugin
99
     */
100
    private $pluginsTypesFolder = array(self::PLUGIN_ACTION => 'actions', self::PLUGIN_FILTER => 'filters');
101
102
    /**
103
     * Contient l'unique instance de l'objet
104
     * @var object
105
     */
106
    private static $instance = false;
0 ignored issues
show
The property $instance is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
107
108
    /**
109
     * Liste des évènements
110
     * @var array
111
     */
112
    private static $events = array();
113
114
    /**
115
     * Retourne l'instance unique de la classe
116
     *
117
     * @return object
118
     */
119
    public static function getInstance()
120
    {
121
        static $instance;
122
        if (null === $instance) {
123
            $instance = new static();
124
        }
125
126
        return $instance;
127
    }
128
129
    /**
130
     * Chargement des 2 types de plugins
131
     *
132
     */
133
    private function __construct()
134
    {
135
        $this->events = array();
136
        $this->loadPlugins();
137
    }
138
139
    /**
140
     * Chargement des plugins (actions et filtres)
141
     * @return void
142
     */
143
    public function loadPlugins()
144
    {
145
        $this->loadPluginsFiles(OLEDRION_PLUGINS_PATH . $this->pluginsTypesFolder[self::PLUGIN_ACTION], self::PLUGIN_ACTION);
146
        $this->loadPluginsFiles(OLEDRION_PLUGINS_PATH . $this->pluginsTypesFolder[self::PLUGIN_FILTER], self::PLUGIN_FILTER);
147
    }
148
149
    /**
150
     * Vérifie que le fichier Php passé en paramètre contient bien une classe de filtre ou d'action et si c'est le cas, le charge dans la liste des plugins
151
     * @param  string  $fullPathName Chemin complet vers le fichier (répertoire + nom)
152
     * @param  integer $type         Type de plugin recherché (action ou filtre)
153
     * @param  string  $pluginFolder Le nom du répertoire dans lequel se trouve le fichier (le "dernier nom")
154
     * @return void
155
     */
156
    private function loadClass($fullPathName, $type, $pluginFolder)
157
    {
158
        require_once $fullPathName;
159
        $className = strtolower($pluginFolder) . $this->pluginsTypeLabel[$type];
160
        if (class_exists($className) && get_parent_class($className) == $this->pluginsClassName[$type]) {
161
            // TODO: Vérifier que l'évènement n'est pas déjà en mémoire
162
            $events = call_user_func(array($className, self::PLUGIN_DESCRIBE_METHOD));
163
            foreach ($events as $event) {
164
                $eventName                                         = $event[0];
165
                $eventPriority                                     = $event[1];
166
                $fileToInclude                                     = OLEDRION_PLUGINS_PATH . $this->pluginsTypesFolder[$type] . '/' . $pluginFolder . '/' . $event[2];
167
                $classToCall                                       = $event[3];
168
                $methodToCall                                      = $event[4];
169
                $this->events[$type][$eventName][$eventPriority][] = array(
170
                    'fullPathName' => $fileToInclude,
171
                    'className'    => $classToCall,
172
                    'method'       => $methodToCall
173
                );
174
            }
175
        }
176
    }
177
178
    /**
179
     * Part à la recherche d'un type de plugin dans les répertoires
180
     *
181
     * @param  string  $path La racine
182
     * @param  integer $type Le type de plugin recherché (action ou filtre)
183
     * @return void
184
     */
185
    private function loadPluginsFiles($path, $type)
186
    {
187
        $objects = new DirectoryIterator($path);
188
        foreach ($objects as $object) {
189
            if ($object->isDir() && !$object->isDot()) {
190
                $file = $path . '/' . $object->current() . '/' . self::PLUGIN_SCRIPT_NAME;
191
                if (file_exists($file)) {
192
                    $this->loadClass($file, $type, $object->current());
193
                }
194
            }
195
        }
196
    }
197
198
    /**
199
     * Déclenchement d'une action et appel des plugins liés
200
     *
201
     * @param  string                     $eventToFire L'action déclenchée
202
     * @param  object|Oledrion_parameters $parameters  Les paramètres à passer à chaque plugin
0 ignored issues
show
Should the type for parameter $parameters not be null|Oledrion_parameters?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
203
     * @return object                     L'objet lui même pour chaîner
204
     */
205 View Code Duplication
    public function fireAction($eventToFire, Oledrion_parameters $parameters = null)
206
    {
207
        if (!isset($this->events[self::PLUGIN_ACTION][$eventToFire])) {
208
            trigger_error(sprintf(_OLEDRION_PLUGINS_ERROR_1, $eventToFire));
209
210
            return $this;
211
        }
212
        ksort($this->events[self::PLUGIN_ACTION][$eventToFire]); // Tri par priorité
213
        foreach ($this->events[self::PLUGIN_ACTION][$eventToFire] as $priority => $events) {
214
            foreach ($events as $event) {
215
                if ($this->isUnplug(self::PLUGIN_ACTION, $eventToFire, $event['fullPathName'], $event['className'], $event['method'])) {
216
                    continue;
217
                }
218
                require_once $event['fullPathName'];
219
                if (!class_exists($event['className'])) {
220
                    $class = new $event['className'];
221
                }
222
                if (!method_exists($event['className'], $event['method'])) {
223
                    continue;
224
                }
225
                call_user_func(array($event['className'], $event['method']), $parameters);
226
                unset($class);
227
            }
228
        }
229
230
        return $this;
231
    }
232
233
    /**
234
     * Déclenchement d'un filtre et appel des plugins liés
235
     *
236
     * @param  string                     $eventToFire Le filtre appelé
237
     * @param  object|Oledrion_parameters $parameters  Les paramètres à passer à chaque plugin
238
     * @return object                     Le contenu de l'objet passé en paramètre
0 ignored issues
show
Should the return type not be Oledrion_plugins|Oledrion_parameters|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
239
     */
240 View Code Duplication
    public function fireFilter($eventToFire, Oledrion_parameters $parameters)
241
    {
242
        if (!isset($this->events[self::PLUGIN_FILTER][$eventToFire])) {
243
            trigger_error(sprintf(_OLEDRION_PLUGINS_ERROR_1, $eventToFire));
244
245
            return $this;
246
        }
247
        ksort($this->events[self::PLUGIN_FILTER][$eventToFire]); // Tri par priorité
248
        foreach ($this->events[self::PLUGIN_FILTER][$eventToFire] as $priority => $events) {
249
            foreach ($events as $event) {
250
                if ($this->isUnplug(self::PLUGIN_FILTER, $eventToFire, $event['fullPathName'], $event['className'], $event['method'])) {
251
                    continue;
252
                }
253
                require_once $event['fullPathName'];
254
                if (!class_exists($event['className'])) {
255
                    $class = new $event['className'];
256
                }
257
                if (!method_exists($event['className'], $event['method'])) {
258
                    continue;
259
                }
260
                call_user_func(array($event['className'], $event['method']), $parameters);
261
                unset($class);
262
            }
263
        }
264
265
        if (null !== $parameters) {
266
            return $parameters;
267
        }
268
    }
269
270
    /**
271
     * Indique si un plugin s'est détaché d'un évènement particulier
272
     *
273
     * @param  integer $eventType
274
     * @param  string  $eventToFire
275
     * @param  string  $fullPathName
276
     * @param  string  $className
277
     * @param  string  $method
278
     * @return boolean
279
     */
280
    public function isUnplug($eventType, $eventToFire, $fullPathName, $className, $method)
281
    {
282
        $unplug = array();
283
        if (isset($_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME])) {
284
            $unplug = $_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME];
285
        } else {
286
            return false;
287
        }
288
289
        return isset($unplug[$eventType][$eventToFire][$fullPathName][$className][$method]);
290
    }
291
292
    /**
293
     * Permet à un plugin de se détacher d'un évènement
294
     *
295
     * @param  integer $eventType
296
     * @param  string  $eventToFire
297
     * @param  string  $fullPathName
298
     * @param  string  $className
299
     * @param  string  $method
300
     * @return void
301
     */
302
    public function unplugFromEvent($eventType, $eventToFire, $fullPathName, $className, $method)
303
    {
304
        $unplug = array();
305
        if (isset($_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME])) {
306
            $unplug = $_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME];
307
        }
308
        $unplug[$eventType][$eventToFire][$fullPathName][$className][$method] = true;
309
        $_SESSION[self::PLUGIN_UNPLUG_SESSION_NAME]                           = $unplug;
310
    }
311
}
312