Passed
Pull Request — dev (#6)
by Rafael
79:24 queued 24:08
created

Interfaces::getTriggersList()   F

Complexity

Conditions 29
Paths 17080

Size

Total Lines 154
Code Lines 101

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 29
eloc 101
nc 17080
nop 1
dl 0
loc 154
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* Copyright (C) 2005-2009  Laurent Destailleur         <[email protected]>
4
 * Copyright (C) 2006       Rodolphe Quiedeville        <[email protected]>
5
 * Copyright (C) 2010       Regis Houssin               <[email protected]>
6
 * Copyright (C) 2024		MDW							<[email protected]>
7
 * Copyright (C) 2024       Rafael San José             <[email protected]>
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
namespace Dolibarr\Code\Core\Classes;
24
25
use DoliDB;
26
27
/**
28
 *   \file          htdocs/core/class/interfaces.class.php
29
 *   \ingroup       core
30
 *   \brief         Fichier de la class de gestion des triggers
31
 */
32
33
require_once constant('DOL_DOCUMENT_ROOT') . '/core/triggers/dolibarrtriggers.class.php';
34
35
36
/**
37
 *   Class to manage triggers
38
 */
39
class Interfaces
40
{
41
    /**
42
     * @var DoliDB Database handler.
43
     */
44
    public $db;
45
46
    public $dir; // Directory with all core and external triggers files
47
48
    /**
49
     * @var string      Last module name in error
50
     */
51
    public $lastmoduleerror;
52
53
    /**
54
     * @var string[] Error codes (or messages)
55
     */
56
    public $errors = array();
57
58
    /**
59
     *  Constructor
60
     *
61
     *  @param      DoliDB      $db      Database handler
62
     */
63
    public function __construct($db)
64
    {
65
        $this->db = $db;
66
    }
67
68
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
69
    /**
70
     *   Function called when a Dolibarr business event occurs
71
     *   This function call all qualified triggers.
72
     *
73
     *   @param     string      $action     Trigger event code
74
     *   @param     object      $object     Object concerned. Some context information may also be provided into array property object->context.
75
     *   @param     User        $user       Object user
76
     *   @param     Translate   $langs      Object lang
77
     *   @param     Conf        $conf       Object conf
78
     *   @return    int                     Nb of triggers ran if no error, -Nb of triggers with errors otherwise.
79
     */
80
    public function run_triggers($action, $object, $user, $langs, $conf)
81
    {
82
		// phpcs:enable
83
84
        if (getDolGlobalInt('MAIN_TRIGGER_DEBUG')) {
85
            // This his too much verbose, enabled if const enabled only
86
            dol_syslog(get_class($this) . "::run_triggers action=" . $action . " Launch run_triggers", LOG_DEBUG);
87
        }
88
89
        // Check parameters
90
        if (!is_object($object) || !is_object($conf)) { // Error
91
            $error = 'function run_triggers called with wrong parameters action=' . $action . ' object=' . ((string) (int) is_object($object)) . ' user=' . ((string) (int) is_object($user)) . ' langs=' . ((string) (int) is_object($langs)) . ' conf=' . ((string) (int) is_object($conf));
92
            dol_syslog(get_class($this) . '::run_triggers ' . $error, LOG_ERR);
93
            $this->errors[] = $error;
94
            return -1;
95
        }
96
        if (!is_object($langs)) {   // Warning
97
            dol_syslog(get_class($this) . '::run_triggers was called with wrong parameters action=' . $action . ' object=' . ((string) (int) is_object($object)) . ' user=' . ((string) (int) is_object($user)) . ' langs=' . ((string) (int) is_object($langs)) . ' conf=' . ((string) (int) is_object($conf)), LOG_WARNING);
98
        }
99
        if (!is_object($user)) {        // Warning
100
            dol_syslog(get_class($this) . '::run_triggers was called with wrong parameters action=' . $action . ' object=' . ((string) (int) is_object($object)) . ' user=' . ((string) (int) is_object($user)) . ' langs=' . ((string) (int) is_object($langs)) . ' conf=' . ((string) (int) is_object($conf)), LOG_WARNING);
101
            $user = new User($this->db);
102
        }
103
104
        $nbfile = $nbtotal = $nbok = $nbko = 0;
105
        $this->lastmoduleerror = '';
106
107
        $files = array();
108
        $modules = array();
109
        $orders = array();
110
        $i = 0;
111
112
        $dirtriggers = array_merge(array('/core/triggers'), $conf->modules_parts['triggers']);
113
        foreach ($dirtriggers as $reldir) {
114
            $dir = dol_buildpath($reldir, 0);
115
            $newdir = dol_osencode($dir);
116
            //print "xx".$dir;exit;
117
118
            // Check if directory exists (we do not use dol_is_dir to avoir loading files.lib.php at each call)
119
            if (!is_dir($newdir)) {
120
                continue;
121
            }
122
123
            $handle = opendir($newdir);
124
            if (is_resource($handle)) {
125
                $fullpathfiles = array();
126
                while (($file = readdir($handle)) !== false) {
127
                    $reg = array();
128
                    if (is_readable($newdir . "/" . $file) && preg_match('/^interface_([0-9]+)_([^_]+)_(.+)\.class\.php$/i', $file, $reg)) {
129
                        $part1 = $reg[1];
130
                        $part2 = $reg[2];
131
                        $part3 = $reg[3];
132
133
                        $nbfile++;
134
135
                        // Check if trigger file is disabled by name
136
                        if (preg_match('/NORUN$/i', $file)) {
137
                            continue;
138
                        }
139
                        // Check if trigger file is for a particular module
140
                        $qualified = true;
141
                        if (strtolower($reg[2]) != 'all') {
142
                            $module = preg_replace('/^mod/i', '', $reg[2]);
143
                            if (!isModEnabled(strtolower($module))) {
144
                                $qualified = false;
145
                            }
146
                        }
147
148
                        if (!$qualified) {
149
                            //dol_syslog(get_class($this)."::run_triggers action=".$action." Triggers for file '".$file."' need module to be enabled", LOG_DEBUG);
150
                            continue;
151
                        }
152
153
                        $modName = "Interface" . ucfirst($reg[3]);
154
                        //print "file=$file - modName=$modName\n";
155
                        if (in_array($modName, $modules)) {    // $modules = list of modName already loaded
156
                            $langs->load("errors");
157
                            dol_syslog(get_class($this) . "::run_triggers action=" . $action . " " . $langs->trans("ErrorDuplicateTrigger", $newdir . "/" . $file, $fullpathfiles[$modName]), LOG_WARNING);
158
                            continue;
159
                        }
160
161
                        try {
162
                            //print 'Todo for '.$modName." : ".$newdir.'/'.$file."\n";
163
                            include_once $newdir . '/' . $file;
164
                            //print 'Done for '.$modName."\n";
165
                        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Core\Classes\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
166
                            dol_syslog('ko for ' . $modName . " " . $e->getMessage() . "\n", LOG_ERR);
167
                        }
168
169
                        $modules[$i] = $modName;
170
                        $files[$i] = $file;
171
                        $fullpathfiles[$modName] = $newdir . '/' . $file;
172
                        $orders[$i] = $part1 . '_' . $part2 . '_' . $part3; // Set sort criteria value
173
174
                        $i++;
175
                    }
176
                }
177
178
                closedir($handle);
179
            }
180
        }
181
182
        asort($orders, SORT_NATURAL);
183
184
        // Loop on each trigger
185
        foreach ($orders as $key => $value) {
186
            $modName = $modules[$key];
187
            if (empty($modName)) {
188
                continue;
189
            }
190
191
            $objMod = new $modName($this->db);
192
            if ($objMod) {
193
                $dblevelbefore = $this->db->transaction_opened;
194
195
                $result = 0;
196
197
                if (method_exists($objMod, 'runTrigger')) { // New method to implement
198
                    //dol_syslog(get_class($this)."::run_triggers action=".$action." Launch runTrigger for file '".$files[$key]."'", LOG_DEBUG);
199
                    $result = $objMod->runTrigger($action, $object, $user, $langs, $conf);
200
                } elseif (method_exists($objMod, 'run_trigger')) {  // Deprecated method
201
                    dol_syslog(get_class($this) . "::run_triggers action=" . $action . " Launch old method run_trigger (rename your trigger into runTrigger) for file '" . $files[$key] . "'", LOG_WARNING);
202
                    $result = $objMod->run_trigger($action, $object, $user, $langs, $conf);
203
                } else {
204
                    dol_syslog(get_class($this) . "::run_triggers action=" . $action . " A trigger was declared for class " . get_class($objMod) . " but method runTrigger was not found", LOG_ERR);
205
                }
206
207
                $dblevelafter = $this->db->transaction_opened;
208
209
                if ($dblevelbefore != $dblevelafter) {
210
                    $errormessage = "Error, the balance begin/close of db transactions has been broken into trigger " . $modName . " with action=" . $action . " before=" . $dblevelbefore . " after=" . $dblevelafter;
211
                    $this->errors[] = $errormessage;
212
                    dol_syslog($errormessage, LOG_ERR);
213
                    $result = -1;
214
                }
215
216
                if ($result > 0) {
217
                    // Action OK
218
                    $nbtotal++;
219
                    $nbok++;
220
                }
221
                if ($result == 0) {
222
                    // Aucune action faite
223
                    $nbtotal++;
224
                }
225
                if ($result < 0) {
226
                    // Action KO
227
                    //dol_syslog("Error in trigger ".$action." - result = ".$result." - Nb of error string returned = ".count($objMod->errors), LOG_ERR);
228
                    $nbtotal++;
229
                    $nbko++;
230
                    $this->lastmoduleerror = $modName;
231
                    if (!empty($objMod->errors)) {
232
                        $this->errors = array_merge($this->errors, $objMod->errors);
233
                    } elseif (!empty($objMod->error)) {
234
                        $this->errors[] = $objMod->error;
235
                    }
236
                    //dol_syslog("Error in trigger ".$action." - Nb of error string returned = ".count($this->errors), LOG_ERR);
237
                }
238
            } else {
239
                dol_syslog(get_class($this) . "::run_triggers action=" . $action . " Failed to instantiate trigger for file '" . $files[$key] . "'", LOG_ERR);
240
            }
241
        }
242
243
        if ($nbko) {
244
            dol_syslog(get_class($this) . "::run_triggers action=" . $action . " Files found: " . $nbfile . ", Files launched: " . $nbtotal . ", Done: " . $nbok . ", Failed: " . $nbko . ($this->lastmoduleerror ? " - Last module in error: " . $this->lastmoduleerror : "") . " - Nb of error string returned in this->errors = " . count($this->errors), LOG_ERR);
245
            return -$nbko;
246
        } else {
247
            //dol_syslog(get_class($this)."::run_triggers Files found: ".$nbfile.", Files launched: ".$nbtotal.", Done: ".$nbok.", Failed: ".$nbko, LOG_DEBUG);
248
            return $nbok;
249
        }
250
    }
251
252
    /**
253
     *  Return list of triggers. Function used by admin page htdoc/admin/triggers.
254
     *  List is sorted by trigger filename so by priority to run.
255
     *
256
     *  @param  array       $forcedirtriggers       null=All default directories. This parameter is used by modulebuilder module only.
257
     *  @return array                               Array list of triggers
258
     */
259
    public function getTriggersList($forcedirtriggers = null)
260
    {
261
        global $conf, $langs, $db;
262
263
        $files = array();
264
        $fullpath = array();
265
        $relpath = array();
266
        $iscoreorexternal = array();
267
        $modules = array();
268
        $orders = array();
269
        $i = 0;
270
271
        $dirtriggers = array_merge(array('/core/triggers/'), $conf->modules_parts['triggers']);
272
        if (is_array($forcedirtriggers)) {
273
            $dirtriggers = $forcedirtriggers;
274
        }
275
276
        foreach ($dirtriggers as $reldir) {
277
            $dir = dol_buildpath($reldir, 0);
278
            $newdir = dol_osencode($dir);
279
280
            // Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php at each call)
281
            if (!is_dir($newdir)) {
282
                continue;
283
            }
284
285
            $handle = opendir($newdir);
286
            if (is_resource($handle)) {
287
                while (($file = readdir($handle)) !== false) {
288
                    $reg = array();
289
                    if (is_readable($newdir . '/' . $file) && preg_match('/^interface_([0-9]+)_([^_]+)_(.+)\.class\.php/', $file, $reg)) {
290
                        if (preg_match('/\.back$/', $file)) {
291
                            continue;
292
                        }
293
294
                        $part1 = $reg[1];
295
                        $part2 = $reg[2];
296
                        $part3 = $reg[3];
297
298
                        $modName = 'Interface' . ucfirst($reg[3]);
299
                        //print "file=$file"; print "modName=$modName"; exit;
300
                        if (in_array($modName, $modules)) {
301
                            $langs->load("errors");
302
                            print '<div class="error">' . $langs->trans("Error") . ' : ' . $langs->trans("ErrorDuplicateTrigger", $modName, "/htdocs/core/triggers/") . '</div>';
303
                        } else {
304
                            include_once $newdir . '/' . $file;
305
                        }
306
307
                        $files[$i] = $file;
308
                        $fullpath[$i] = $dir . '/' . $file;
309
                        $relpath[$i] = preg_replace('/^\//', '', $reldir) . '/' . $file;
310
                        $iscoreorexternal[$i] = ($reldir == '/core/triggers/' ? 'internal' : 'external');
311
                        $modules[$i] = $modName;
312
                        $orders[$i] = $part1 . '_' . $part2 . '_' . $part3; // Set sort criteria value
313
314
                        $i++;
315
                    }
316
                }
317
                closedir($handle);
318
            }
319
        }
320
321
        asort($orders, SORT_NATURAL);
322
323
        $triggers = array();
324
        $j = 0;
325
326
        // Loop on each trigger
327
        foreach ($orders as $key => $value) {
328
            $modName = $modules[$key];
329
            if (empty($modName)) {
330
                continue;
331
            }
332
333
            if (!class_exists($modName)) {
334
                print 'Error: A trigger file was found but its class "' . $modName . '" was not found.' . "<br>\n";
335
                continue;
336
            }
337
338
            $text = '';
339
340
            try {
341
                $objMod = new $modName($db);
342
343
                if (is_subclass_of($objMod, 'DolibarrTriggers')) {
344
                    // Define disabledbyname and disabledbymodule
345
                    $disabledbyname = 0;
346
                    $disabledbymodule = 1;
347
                    $module = '';
348
349
                    // Check if trigger file is disabled by name
350
                    if (preg_match('/NORUN$/i', $files[$key])) {
351
                        $disabledbyname = 1;
352
                    }
353
                    // Check if trigger file is for a particular module
354
                    if (preg_match('/^interface_([0-9]+)_([^_]+)_(.+)\.class\.php/i', $files[$key], $reg)) {
355
                        $module = preg_replace('/^mod/i', '', $reg[2]);
356
                        if (strtolower($module) == 'all') {
357
                            $disabledbymodule = 0;
358
                        } elseif (!isModEnabled(strtolower($module))) {
359
                            $disabledbymodule = 2;
360
                        }
361
                        $triggers[$j]['module'] = strtolower($module);
362
                    }
363
364
                    // We set info of modules
365
                    $triggers[$j]['picto'] = (!empty($objMod->picto)) ? img_object('', $objMod->picto, 'class="valignmiddle pictomodule "') : img_object('', 'generic', 'class="valignmiddle pictomodule "');
366
                    $triggers[$j]['file'] = $files[$key];
367
                    $triggers[$j]['fullpath'] = $fullpath[$key];
368
                    $triggers[$j]['relpath'] = $relpath[$key];
369
                    $triggers[$j]['iscoreorexternal'] = $iscoreorexternal[$key];
370
                    $triggers[$j]['version'] = $objMod->getVersion();
371
                    $triggers[$j]['status'] = img_picto($langs->trans("Active"), 'tick');
372
                    if ($disabledbyname > 0 || $disabledbymodule > 1) {
373
                        $triggers[$j]['status'] = '';
374
                    }
375
376
                    $text = '<b>' . $langs->trans("Description") . ':</b><br>';
377
                    $text .= $objMod->getDesc() . '<br>';
378
                    $text .= '<br><b>' . $langs->trans("Status") . ':</b><br>';
379
                    if ($disabledbyname == 1) {
380
                        $text .= $langs->trans("TriggerDisabledByName") . '<br>';
381
                        if ($disabledbymodule == 2) {
382
                            $text .= $langs->trans("TriggerDisabledAsModuleDisabled", $module) . '<br>';
383
                        }
384
                    } else {
385
                        if ($disabledbymodule == 0) {
386
                            $text .= $langs->trans("TriggerAlwaysActive") . '<br>';
387
                        }
388
                        if ($disabledbymodule == 1) {
389
                            $text .= $langs->trans("TriggerActiveAsModuleActive", $module) . '<br>';
390
                        }
391
                        if ($disabledbymodule == 2) {
392
                            $text .= $langs->trans("TriggerDisabledAsModuleDisabled", $module) . '<br>';
393
                        }
394
                    }
395
                } else {
396
                    $triggers[$j]['picto'] = (!empty($objMod->picto)) ? img_object('', $objMod->picto, 'class="valignmiddle pictomodule "') : img_object('', 'generic', 'class="valignmiddle pictomodule "');
397
                    $triggers[$j]['file'] = $files[$key];
398
                    $triggers[$j]['fullpath'] = $fullpath[$key];
399
                    $triggers[$j]['relpath'] = $relpath[$key];
400
                    $triggers[$j]['status'] = img_picto('Error: Trigger ' . $modName . ' does not extends DolibarrTriggers', 'warning');
401
402
                    //print 'Error: Trigger '.$modName.' does not extends DolibarrTriggers<br>';
403
                    $text = 'Error: Trigger ' . $modName . ' does not extends DolibarrTriggers';
404
                }
405
            } catch (Exception $e) {
406
                print $e->getMessage();
407
            }
408
409
            $triggers[$j]['info'] = $text;
410
            $j++;
411
        }
412
        return $triggers;
413
    }
414
}
415