/[openfoncier]/trunk/obj/module.class.php
ViewVC logotype

Contents of /trunk/obj/module.class.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18436 - (show annotations)
Tue Aug 13 14:49:35 2024 UTC (5 months, 3 weeks ago) by softime
File size: 19392 byte(s)
chore(branch): fusion de la branche d'intégration 6.6.0-develop dans le trunk@18406

1 <?php
2
3 /**
4 * Le namespace auxquels tous les modules doivent appartenir
5 */
6 namespace Module;
7
8 use \ReflectionClass;
9 use \RuntimeException;
10 use \InvalidArgumentException;
11
12 require_once __DIR__.'/utils.class.php';
13 use \application;
14
15 require_once __DIR__.'/lien_module.class.php';
16 use \lien_module;
17
18 require_once __DIR__.'/om_dbform.class.php';
19 use \om_dbform;
20
21
22 /**
23 * Classe (abstraite) représentant un module
24 */
25 abstract class module {
26
27 /**
28 * Une instance du framework openmairie
29 *
30 * @var application
31 */
32 protected application $framework;
33
34 /**
35 * Le chemin vers le répertoire contenant ce module
36 * @var string
37 */
38 public string $dir;
39
40 /**
41 * Une configuration statique
42 */
43 public array $conf = array();
44
45 /**
46 * Une liste de paramètres dynamiques
47 */
48 public array $params = array();
49
50 /**
51 * Une instance du lien avec l'objet auquel est associé ce module
52 */
53 public ?lien_module $object_link_instance = null;
54
55 /**
56 * Une instance de l'objet métier auquel est associé ce module
57 */
58 public ?om_dbform $object = null;
59
60 /**
61 * Renvoie la description du module (type libellé)
62 *
63 * @return string
64 */
65 abstract public function get_description();
66
67 /**
68 * Installe le module.
69 *
70 * @return bool 'true' si l'installation s'est bien passée, 'false' sinon
71 */
72 abstract public function install();
73
74 /**
75 * Désinstalle le module.
76 *
77 * @return bool 'true' si la désinstallation s'est bien passée, 'false' sinon
78 */
79 abstract public function uninstall();
80
81 /**
82 * Créer une instance de module
83 *
84 * @param string $dir Le répertoire contenant le module
85 * @param application $framework Une instance du framework openmairie
86 * @param lien_module $object_link_instance Une instance d'objet lien
87 * @param om_dbform $object Une instance d'objet métier
88 *
89 * @return module
90 */
91 public function __construct(
92 string $dir,
93 application $framework,
94 ?lien_module $object_link_instance = null,
95 ?om_dbform $object = null
96 ) {
97 $this->framework = $framework;
98 $this->log(__METHOD__, 'object_link: '.($object_link_instance ? $object_link_instance->to_string() : 'null').
99 ', object: '.($object ? get_class($object).
100 '#'.$object->getVal($object->clePrimaire) : 'null'));
101 $this->dir = $dir;
102 $this->object_link_instance = $object_link_instance;
103 $this->object = $object;
104 if (! empty($this->object) && empty($this->object->getVal($this->object->clePrimaire))) {
105 $this->log(__METHOD__, "objet sans clé primaire définie (et probablement idem pour ses valeurs)");
106 }
107 $this->load_conf();
108 }
109
110 /**
111 * Renvoie une représentation en "string" du module
112 *
113 * @return string
114 */
115 public function to_string() {
116 $str = sprintf(
117 '%s (link:%s, object:%s, ordre:%s)',
118 $this->get_short_name(),
119 $this->get_object_link_instance_id(),
120 $this->get_object_instance_id(),
121 $this->object_link_instance->getVal('ordre'));
122 return $str;
123 }
124
125 /**
126 * Permet d'effectuer des actions lors de l'instanciation
127 *
128 * @param string $action L'action en cours (add, edit, delete)
129 *
130 * @return void
131 */
132 public function setup(string $action) {
133 $this->log(__METHOD__, 'BEGIN');
134 $this->log(__METHOD__, 'END');
135 }
136
137 /**
138 * Charge la configuration statique
139 *
140 * @return void
141 */
142 public function load_conf() {
143 $conf_path = $this->get_conf_path();
144 if (is_file($conf_path)) {
145 $conf_path_ext = pathinfo($conf_path, PATHINFO_EXTENSION);
146 switch($conf_path_ext) {
147 case 'php':
148 $this->conf = include $conf_path;
149 break;
150 case 'ini':
151 $this->conf = parse_ini_file($conf_path);
152 break;
153 case 'json':
154 $this->conf = json_decode(
155 file_get_contents($conf_path), true,
156 512, JSON_THROW_ON_ERROR);
157 break;
158 }
159 }
160 }
161
162 /**
163 * Renvoie le chemin vers la configuration statique du module
164 *
165 * @return string
166 */
167 protected function get_conf_path() {
168 $this->log(__METHOD__, 'BEGIN');
169 $module_name = $this->get_short_name();
170 $ret = $this->dir."/$module_name.conf.php";
171 $this->log(__METHOD__, 'return: '.var_export($ret, true));
172 $this->log(__METHOD__, 'END');
173 return $ret;
174 }
175
176 /**
177 * Renvoie le nom court du module
178 *
179 * @return string
180 */
181 public function get_short_name() {
182 $ref = new \ReflectionClass($this);
183 return $ref->getShortName();
184 }
185
186 /**
187 * Renvoie une URL (ou partie d'URL) pointant vers le répertoire contenant les "assets"
188 * (ressources publiques) du module
189 *
190 * @return string
191 */
192 public function get_url_assets_path_base() {
193 $this->log(__METHOD__, 'BEGIN');
194 $base_dir = $this->dir;
195 $app_dir = dirname(__DIR__);
196 if (strpos($base_dir, $app_dir) !== 0) {
197 throw new RuntimeException(
198 "Invalid module directory '$base_dir' or application directory '$app_dir'"
199 );
200 }
201 $base_url = str_replace($app_dir, '', $base_dir);
202 $url = "../$base_url";
203 $url_encoded = implode(
204 '/', array_map(
205 function ($v) { return rawurlencode($v); },
206 explode('/', $url)));
207 $ret = $url_encoded;
208 $this->log(__METHOD__, 'return: '.var_export($ret, true));
209 $this->log(__METHOD__, 'END');
210 return $ret;
211 }
212
213 /**
214 * Récupère la valeur d'une directive de configuration
215 *
216 * @param string $key Le nom de la directive de configuration dont on veut la valeur
217 *
218 * @return mixed
219 */
220 protected function conf(string $key) {
221 return $this->conf[$key] ?? null;
222 }
223
224 /**
225 * Assigne/Enregistre les paramètres du modules.
226 * Les formats d'entrée supportés sont INI et JSON.
227 *
228 * @param string $raw_params Une chaine contenant les paramètres dans un format supporté
229 * @param string $format Le nom du format de la chaine des paramètres
230 *
231 * @return void
232 */
233 public function set_parameters(string $raw_params, string $format = 'INI') {
234 $this->log(__METHOD__, "($format) BEGIN");
235 switch(strtoupper($format)) {
236 case 'INI':
237 $this->log(__METHOD__, "parsing INI string:");
238 $this->log(__METHOD__, var_export($raw_params, true));
239 $params = parse_ini_string($raw_params, true);
240 if ($params === false) {
241 $this->log(__METHOD__, "Failed to parse INI string: '$raw_params'", 'WARNING');
242 }
243 if (is_array($params)) {
244 $this->params = $params;
245 }
246 break;
247 case 'JSON':
248 $this->log(__METHOD__, "parsing JSON string:");
249 $this->log(__METHOD__, var_export($raw_params, true));
250 $params = json_decode(
251 $raw_params, true, 512/*, JSON_THROW_ON_ERROR*/);
252 if (json_last_error() !== JSON_ERROR_NONE) {
253 $this->log(__METHOD__, var_export(json_last_error_msg(), true), 'WARNING');
254 }
255 if (is_array($params)) {
256 $this->params = $params;
257 }
258 break;
259 }
260 $this->log(__METHOD__, 'END');
261 }
262
263 /**
264 * Renvoi le nom d'une méthode principale du module.
265 * Celle-ci sera appelée à chaque hook et aurait en argument:
266 * - le nom du hook
267 * - l'objet courant
268 * - les données du contaxte
269 *
270 * @return string|null
271 */
272 public function get_main_method() {
273 $this->log(__METHOD__, 'BEGIN');
274 $ret = null;
275 $this->log(__METHOD__, 'return: '.var_export($ret, true));
276 $this->log(__METHOD__, 'END');
277 return $ret;
278 }
279
280 /**
281 * Renvoie une liste d'action de portlet
282 *
283 * @return array
284 */
285 public function get_actions() {
286 $this->log(__METHOD__, 'BEGIN');
287 $ret = array();
288 $this->log(__METHOD__, 'return: '.var_export($ret, true));
289 $this->log(__METHOD__, 'END');
290 return $ret;
291 }
292
293 /**
294 * Renvoie la liste des déclencheurs (hooks) supporté par ce module
295 *
296 * @param boolean $in_business_term 'true' pour renvoyer la liste avec des termes business
297 *
298 * @return array
299 */
300 public function get_supported_hooks(bool $in_business_term = false) {
301 $this->log(__METHOD__, 'BEGIN');
302 $ret = array();
303 $this->log(__METHOD__, 'return: '.var_export($ret, true));
304 $this->log(__METHOD__, 'END');
305 return $ret;
306 }
307
308 /**
309 * Renvoie la liste des libellés des déclencheurs pour une liste de hook donnés.
310 * Le format est un tableau associatif:
311 * <hook> => <libellé>
312 *
313 * @param array $hooks Liste de hooks
314 *
315 * @return array
316 * @throw RuntimeException
317 */
318 protected function get_declencheurs_for_hooks(array $hooks) {
319 $all_hooks_data = $this->framework->module_manager->get_all_available_hooks();
320 $hooks_with_labels = array();
321 foreach($hooks as $hook) {
322 if (! isset($all_hooks_data[$hook])) {
323 throw new RuntimeException("No hook label found for '$hook'");
324 }
325 $hooks_with_labels[$hook] = $all_hooks_data[$hook];
326 }
327 return $hooks_with_labels;
328 }
329
330 /**
331 * Renvoie la liste des scripts Javascript a inclure dans la balise HTML <head>
332 *
333 * @return array
334 */
335 public function get_header_scripts_js() {
336 $this->log(__METHOD__, 'BEGIN');
337 $ret = array();
338 $this->log(__METHOD__, 'return: '.var_export($ret, true));
339 $this->log(__METHOD__, 'END');
340 return $ret;
341 }
342
343 /**
344 * Renvoie la liste des scripts Javascript a inclure dans le code HTML inline
345 *
346 * @param string $position 'top' pour inclure au début et 'bottom' à la fin
347 *
348 * @return array
349 */
350 public function get_inline_scripts_js(string $position) {
351 $this->log(__METHOD__, "($position) BEGIN");
352 if (! in_array($position, array('top', 'bottom'))) {
353 throw InvalidArgumentException("Invalid position '$position' (must be: 'top' or 'bottom')");
354 }
355 $ret = array();
356 $this->log(__METHOD__, 'return: '.var_export($ret, true));
357 $this->log(__METHOD__, 'END');
358 return $ret;
359 }
360
361 /**
362 * Renvoie la liste des styles CSS a inclure dans la balise HTML <head>
363 *
364 * @return array
365 */
366 public function get_header_styles_css() {
367 $this->log(__METHOD__, 'BEGIN');
368 $ret = array();
369 $this->log(__METHOD__, 'return: '.var_export($ret, true));
370 $this->log(__METHOD__, 'END');
371 return $ret;
372 }
373
374 /**
375 * Renvoie la liste des styles CSS a inclure dans le code HTML inline
376 *
377 * @param string $position 'top' pour inclure au début et 'bottom' à la fin
378 *
379 * @return array
380 */
381 public function get_inline_styles_css(string $position) {
382 $this->log(__METHOD__, "($position) BEGIN");
383 if (! in_array($position, array('top', 'bottom'))) {
384 throw InvalidArgumentException("Invalid position '$position' (must be: 'top' or 'bottom')");
385 }
386 $ret = array();
387 $this->log(__METHOD__, 'return: '.var_export($ret, true));
388 $this->log(__METHOD__, 'END');
389 return $ret;
390 }
391
392 /**
393 * Renvoie l'identifiant de la classe de l'objet lien, ou
394 * null s'il n'y a pas d'objet lien
395 *
396 * @return int|null
397 */
398 public function get_object_link_instance_id() {
399 //$this->log(__METHOD__, 'BEGIN');
400 if (! empty($this->object_link_instance)) {
401 $id_key = $this->object_link_instance->clePrimaire;
402 $ret = $this->object_link_instance->getVal($id_key);
403 //$this->log(__METHOD__, 'return: '.var_export($ret, true));
404 //$this->log(__METHOD__, 'END');
405 return $ret;
406 }
407 $ret = null;
408 //$this->log(__METHOD__, 'return: '.var_export($ret, true));
409 //$this->log(__METHOD__, 'END');
410 return $ret;
411 }
412
413 /**
414 * Renvoie l'identifiant de la classe de l'objet métier, ou
415 * null s'il n'y a pas d'objet métier
416 *
417 * @return int|null
418 */
419 public function get_object_instance_id() {
420 //$this->log(__METHOD__, 'BEGIN');
421 if (! empty($this->object)) {
422 $id_key = $this->object->clePrimaire;
423 $ret = $this->object->getVal($id_key);
424 //$this->log(__METHOD__, 'return: '.var_export($ret, true));
425 //$this->log(__METHOD__, 'END');
426 return $ret;
427 }
428 $ret = null;
429 //$this->log(__METHOD__, 'return: '.var_export($ret, true));
430 //$this->log(__METHOD__, 'END');
431 return $ret;
432 }
433
434 /**
435 * Renvoie le nom de l'objet auquel le champ dynamique est rattaché.
436 * Si ce nom est défini dans les paramètres du module, alors il a la précédence.
437 * Ensuite si un objet métier (om_dbform) a été associé à ce module, alors celui-ci est revoyé.
438 * Enfin, si un objet "lien" est associé à ce module, alors c'est le nom de l'objet défini
439 * dans l'objet "lien" qui est utilisé.
440 *
441 * @return string
442 */
443 protected function get_object_name() {
444 // le nom renseigné dans le paramétrage a précédence
445 $object_name = $this->params['object_name'] ?? null;
446 $this->log(__METHOD__, "object_name[params]: $object_name");
447 if (! empty($object_name)) return $object_name;
448
449 // puis le nom de la classe de l'objet métier rattaché à ce module
450 if (! empty($this->object)) {
451 $object_name = get_class($this->object);
452 $this->log(__METHOD__, "object_name[object]: $object_name");
453 if (! empty($object_name)) return $object_name;
454 }
455 // enfin le nom de l'objet défini dans l'object "lien" du module
456 if (! empty($this->object_link_instance)) {
457 $object_name = $this->object_link_instance->getVal('object_name');
458 $this->log(__METHOD__, "object_name[object_link]: $object_name");
459 if (! empty($object_name)) return $object_name;
460 }
461
462 return $object_name;
463 }
464
465 /**
466 * Log un message en lui ajoutant un préfixe.
467 *
468 * @param string $method La méthode d'où provient le message (càd: __METHOD__)
469 * @param string $message Le message à écire dans le ficheir de logs
470 * @param string $level Le niveau de log
471 *
472 * @return void
473 */
474 protected function log(string $method, string $message, string $level = 'DEBUG') {
475
476 // remplace la classe parente par la classe courante
477 $ref = new \ReflectionClass($this);
478 $parent_class_escaped = str_replace('\\', '\\\\', $ref->getParentClass()->getName());
479 $method = preg_replace(
480 '/^'.$parent_class_escaped.'/',
481 $ref->getName(),
482 $method);
483
484 $namespace_escaped = str_replace('\\', '\\\\', $ref->getNamespaceName());
485 $method_short = preg_replace('/^'.$namespace_escaped.'\\\\/', '', $method);
486
487 $this->framework->log($method_short, $message, $level);
488 //$this->framework->log($method_short, $message, $level, 'modules');
489 }
490
491 /**
492 * Transforme la valeur de declencheur de la table object_link_instance en un nom de hook propre
493 * @param boolean : $use_parent_name =>
494 *
495 * @return null|array
496 */
497 public function get_declencheur_hook_names($get_parent_hooks = true) {
498 $this->log(__METHOD__, 'BEGIN');
499 $hook_names = array();
500 if (!empty($this->object_link_instance) && !empty($this->object_link_instance->getVal('declencheur'))) {
501 if (strpos($this->object_link_instance->getVal('declencheur'),':') !== false) {
502 $explode_declencheur = explode(':', $this->object_link_instance->getVal('declencheur'));
503 $declencheur_object = $explode_declencheur[0];
504 $declencheur_hook = $explode_declencheur[1];
505
506 // Calcul des noms de hook pour les om_dbforms et les classe filles
507 if ($get_parent_hooks){
508 $object_class = null;
509
510 // Sans objet defini on cri
511 if (empty($this->object) ) {
512 $object_class = $this->get_object_name();
513 }else{
514 $object_class = get_class($this->object);
515 }
516
517 // On se sert de ReflectionClass pour recupèrer la class parent de l'object
518 $reflection_class = new ReflectionClass('\\'.$object_class);
519 $parent_class = $reflection_class->getParentClass();
520 if ($parent_class === false) {
521 throw new RuntimeException("Error '".get_class($this->object)."' has no parent class. Should Be Impossible, Expecting 'om_dbform' or child of 'om_dbform'");
522 }
523
524 $object_class_hook_name = $object_class.'_'.$declencheur_hook;
525
526 // Calcul le nom du hook en remplacant OMDBFORM par la classe object metier
527 // Ou calcul le nom du hook de la class objet métier à partir du déclencheur de la classe parent
528 if (($declencheur_object == 'om_dbform' || $declencheur_object == $parent_class->name)
529 && !in_array($object_class_hook_name, $hook_names)
530 ) {
531 $hook_names[] = $object_class_hook_name;
532 }
533 }
534
535 // Calcul le nom du hook du déclencheur parent
536 $hook_names[] = implode('_', $explode_declencheur);
537
538 }
539 }
540 $this->log(__METHOD__, 'return: '.var_export($hook_names, true));
541 $this->log(__METHOD__, 'END');
542 return $hook_names;
543 }
544
545 /**
546 * Renvoi la documentation du module au format HTML.
547 *
548 * Il est conseiller d'utiliser un fichier HTML à la racine du module nommé 'documentation.html',
549 * et de le renvoyer via cette méthode.
550 *
551 * @return string (html)
552 */
553 public function get_documentation() {
554 $this->log(__METHOD__, 'BEGIN');
555 $doc = '';
556 $module_name = $this->get_short_name();
557 $doc_path = $this->dir."/documentation.html";
558 $this->log(__METHOD__, 'doc path: '.var_export($doc_path, true));
559 if (file_exists($doc_path)) {
560 $doc = file_get_contents($doc_path);
561 }
562 $this->log(__METHOD__, 'END');
563 return $doc;
564 }
565 }

Properties

Name Value
svn:executable *

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26