Passed
Branch develop (5cbde9)
by
unknown
26:38
created

DolibarrModules   F

Complexity

Total Complexity 358

Size/Duplication

Total Lines 2241
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 924
c 0
b 0
f 0
dl 0
loc 2241
rs 1.676
wmc 358

39 Methods

Rating   Name   Duplication   Size   Complexity  
A delete_tabs() 0 18 2
B insert_tabs() 0 58 10
A delete_dirs() 0 18 2
F _remove() 0 75 15
A getName() 0 27 6
A __construct() 0 3 1
A getDesc() 0 27 6
F _init() 0 92 18
A delete_permissions() 0 17 3
A getLastActivationInfo() 0 29 4
B isCoreOrExternalModule() 0 15 8
A delete_const() 0 28 6
D insert_cronjobs() 0 113 46
A getLastActivationDate() 0 25 3
B delete_boxes() 0 65 11
B getDescLong() 0 49 7
D _load_tables() 0 108 36
A insert_dirs() 0 32 3
B getChangeLog() 0 38 6
A getPublisherUrl() 0 3 1
A delete_cronjobs() 0 23 4
A getLangFilesArray() 0 3 1
B _active() 0 34 7
B delete_module_parts() 0 27 7
F insert_permissions() 0 135 26
A remove() 0 3 1
F insert_menus() 0 96 19
A _unactive() 0 18 3
A delete_menus() 0 22 3
A getImportDatasetLabel() 0 14 2
A init() 0 3 1
A getPublisher() 0 3 1
C create_dirs() 0 51 17
C insert_module_parts() 0 69 15
B getDescLongReadmeFound() 0 27 7
D insert_boxes() 0 89 23
A getExportDatasetLabel() 0 13 2
B getVersion() 0 24 10
F insert_const() 0 64 15

How to fix   Complexity   

Complex Class

Complex classes like DolibarrModules often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DolibarrModules, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* Copyright (C) 2003-2007  Rodolphe Quiedeville    <[email protected]>
3
 * Copyright (C) 2004       Sebastien Di Cintio     <[email protected]>
4
 * Copyright (C) 2004       Benoit Mortier          <[email protected]>
5
 * Copyright (C) 2004       Eric Seigne             <[email protected]>
6
 * Copyright (C) 2005-2013  Laurent Destailleur     <[email protected]>
7
 * Copyright (C) 2005-2012  Regis Houssin           <[email protected]>
8
 * Copyright (C) 2014       Raphaël Doursenaud      <[email protected]>
9
 * Copyright (C) 2018       Josep Lluís Amador      <[email protected]>
10
 * Copyright (C) 2019       Frédéric France         <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 3 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24
 */
25
26
/**
27
 * \file           htdocs/core/modules/DolibarrModules.class.php
28
 * \brief          File of parent class of module descriptor class files
29
 */
30
31
32
/**
33
 * Class DolibarrModules
34
 *
35
 * Parent class for module descriptor class files
36
 */
37
class DolibarrModules // Can not be abstract, because we need to instantiate it into unActivateModule to be able to disable a module whose files were removed.
38
{
39
    /**
40
     * @var DoliDb Database handler
41
     */
42
    public $db;
43
44
    /**
45
     * @var int Module unique ID
46
     * @see https://wiki.dolibarr.org/index.php/List_of_modules_id
47
     */
48
    public $numero;
49
50
    /**
51
     * @var   string Publisher name
52
     * @since 4.0.0
53
     */
54
    public $editor_name;
55
56
    /**
57
     * @var   string URL of module at publisher site
58
     * @since 4.0.0
59
     */
60
    public $editor_url;
61
62
    /**
63
     * @var string Family
64
     * @see familyinfo
65
     *
66
     * Native values: 'crm', 'financial', 'hr', 'projects', 'products', 'ecm', 'technic', 'other'.
67
     * Use familyinfo to declare a custom value.
68
     */
69
    public $family;
70
71
    /**
72
     * @var array Custom family informations
73
     * @see family
74
     *
75
     * e.g.:
76
     * array(
77
     *     'myownfamily' => array(
78
     *         'position' => '001',
79
     *         'label' => $langs->trans("MyOwnFamily")
80
     *     )
81
     * );
82
     */
83
    public $familyinfo;
84
85
    /**
86
     * @var string    Module position on 2 digits
87
     */
88
    public $module_position='50';
89
90
    /**
91
     * @var string Module name
92
     *
93
     * Only used if Module[ID]Name translation string is not found.
94
     *
95
     * You can use the following code to automatically derive it from your module's class name:
96
     * preg_replace('/^mod/i', '', get_class($this))
97
     */
98
    public $name;
99
100
    /**
101
     * @var string[] Paths to create when module is activated
102
     *
103
     * e.g.: array('/mymodule/temp')
104
     */
105
    public $dirs = array();
106
107
    /**
108
     * @var array Module boxes
109
     */
110
    public $boxes = array();
111
112
    /**
113
     * @var array Module constants
114
     */
115
    public $const = array();
116
117
    /**
118
     * @var array Module cron jobs entries
119
     */
120
    public $cronjobs = array();
121
122
    /**
123
     * @var array Module access rights
124
     */
125
    public $rights;
126
127
    /**
128
     * @var string Module access rights family
129
     */
130
    public $rights_class;
131
132
    /**
133
     * @var array Module menu entries
134
     */
135
    public $menu = array();
136
137
    /**
138
     * @var array Module parts
139
     *  array(
140
     *      // Set this to 1 if module has its own trigger directory (/mymodule/core/triggers)
141
     *      'triggers' => 0,
142
     *      // Set this to 1 if module has its own login method directory (/mymodule/core/login)
143
     *      'login' => 0,
144
     *      // Set this to 1 if module has its own substitution function file (/mymodule/core/substitutions)
145
     *      'substitutions' => 0,
146
     *      // Set this to 1 if module has its own menus handler directory (/mymodule/core/menus)
147
     *      'menus' => 0,
148
     *      // Set this to 1 if module has its own theme directory (/mymodule/theme)
149
     *      'theme' => 0,
150
     *      // Set this to 1 if module overwrite template dir (/mymodule/core/tpl)
151
     *      'tpl' => 0,
152
     *      // Set this to 1 if module has its own barcode directory (/mymodule/core/modules/barcode)
153
     *      'barcode' => 0,
154
     *      // Set this to 1 if module has its own models directory (/mymodule/core/modules/xxx)
155
     *      'models' => 0,
156
     *      // Set this to relative path of css file if module has its own css file
157
     *      'css' => '/mymodule/css/mymodule.css.php',
158
     *      // Set this to relative path of js file if module must load a js on all pages
159
     *      'js' => '/mymodule/js/mymodule.js',
160
     *      // Set here all hooks context managed by module
161
     *      'hooks' => array('hookcontext1','hookcontext2')
162
     *  )
163
     */
164
    public $module_parts = array();
165
166
    /**
167
     * @var        string Module documents ?
168
     * @deprecated Seems unused anywhere
169
     */
170
    public $docs;
171
172
    /**
173
     * @var        string ?
174
     * @deprecated Seems unused anywhere
175
     */
176
    public $dbversion = "-";
177
178
    /**
179
     * @var string Error message
180
     */
181
    public $error;
182
183
    /**
184
     * @var string Module version
185
     * @see http://semver.org
186
     *
187
     * The following keywords can also be used:
188
     * 'development'
189
     * 'experimental'
190
     * 'dolibarr': only for core modules that share its version
191
     * 'dolibarr_deprecated': only for deprecated core modules
192
     */
193
    public $version;
194
195
    /**
196
     * @var string Module description (short text)
197
     *
198
     * Only used if Module[ID]Desc translation string is not found.
199
     */
200
    public $description;
201
202
    /**
203
     * @var   string Module description (long text)
204
     * @since 4.0.0
205
     *
206
     * HTML content supported.
207
     */
208
    public $descriptionlong;
209
210
211
    // For exports
212
213
    /**
214
     * @var string Module export code
215
     */
216
    public $export_code;
217
218
    /**
219
     * @var string Module export label
220
     */
221
    public $export_label;
222
223
    public $export_permission;
224
    public $export_fields_array;
225
    public $export_TypeFields_array;
226
    public $export_entities_array;
227
    public $export_special_array;           // special or computed field
228
    public $export_dependencies_array;
229
    public $export_sql_start;
230
    public $export_sql_end;
231
    public $export_sql_order;
232
233
234
    // For import
235
236
    /**
237
     * @var string Module import code
238
     */
239
    public $import_code;
240
241
    /**
242
     * @var string Module import label
243
     */
244
    public $import_label;
245
246
247
    /**
248
     * @var string Module constant name
249
     */
250
    public $const_name;
251
252
    /**
253
     * @var bool Module can't be disabled
254
     */
255
    public $always_enabled;
256
257
    /**
258
     * @var int Module is enabled globally (Multicompany support)
259
     */
260
    public $core_enabled;
261
262
    /**
263
     * @var        string Relative path to module style sheet
264
     * @deprecated
265
     * @see        module_parts
266
     */
267
    public $style_sheet = '';
268
269
    /**
270
     * @var        0|1|2|3 Where to display the module in setup page
0 ignored issues
show
Documentation Bug introduced by
The doc comment 0|1|2|3 at position 0 could not be parsed: Unknown type name '0' at position 0 in 0|1|2|3.
Loading history...
271
     * @deprecated @since 4.0.0
272
     * @see        family
273
     * @see        familyinfo
274
     *
275
     * 0: common
276
     * 1: interface
277
     * 2: others
278
     * 3: very specific
279
     */
280
    public $special;
281
282
    /**
283
     * @var string Name of image file used for this module
284
     *
285
     * If file is in theme/yourtheme/img directory under name object_pictoname.png use 'pictoname'
286
     * If file is in module/img directory under name object_pictoname.png use 'pictoname@module'
287
     */
288
    public $picto;
289
290
    /**
291
     * @var string[] List of config pages
292
     *
293
     * Name of php pages stored into module/admin directory, used to setup module.
294
     * e.g.: "admin.php@module"
295
     */
296
    public $config_page_url;
297
298
299
    /**
300
     * @var string[] List of module class names that must be enabled if this module is enabled.
301
     *
302
     * e.g.: array('modAnotherModule', 'FR'=>'modYetAnotherModule')
303
     */
304
    public $depends;
305
306
    /**
307
     * @var int[] List of module ids to disable if this one is disabled.
308
     */
309
    public $requiredby;
310
311
    /**
312
     * @var string[] List of module class names as string this module is in conflict with.
313
     * @see depends
314
     */
315
    public $conflictwith;
316
317
    /**
318
     * @var string[] Module language files
319
     */
320
    public $langfiles;
321
322
    /**
323
     * @var array<string,string> Array of warnings to show when we activate the module
324
     *
325
     * array('always'='text') or array('FR'='text')
326
     */
327
    public $warnings_activation;
328
329
    /**
330
     * @var array<string,string> Array of warnings to show when we activate an external module
331
     *
332
     * array('always'='text') or array('FR'='text')
333
     */
334
    public $warnings_activation_ext;
335
336
337
    /**
338
     * @var array Minimum version of PHP required by module.
339
     * e.g.: PHP ≥ 5.4 = array(5, 4)
340
     */
341
    public $phpmin;
342
343
    /**
344
     * @var array Minimum version of Dolibarr required by module.
345
     * e.g.: Dolibarr ≥ 3.6 = array(3, 6)
346
     */
347
    public $need_dolibarr_version;
348
349
    /**
350
     * @var bool Whether to hide the module.
351
     */
352
    public $hidden = false;
353
354
355
356
357
358
    /**
359
     * Constructor. Define names, constants, directories, boxes, permissions
360
     *
361
     * @param DoliDB $db Database handler
362
     */
363
    public function __construct($db)
364
    {
365
        $this->db = $db;
366
    }
367
    // We should but can't set this as abstract because this will make dolibarr hang
368
    // after migration due to old module not implementing. We must wait PHP is able to make
369
    // a try catch on Fatal error to manage this correctly.
370
    // We need constructor into function unActivateModule into admin.lib.php
371
372
373
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
374
    /**
375
     * Enables a module.
376
     * Inserts all informations into database
377
     *
378
     * @param array  $array_sql SQL requests to be executed when enabling module
379
     * @param string $options   String with options when disabling module:
380
     *                          - 'noboxes' = Do not insert boxes -
381
     *                          'newboxdefonly' = For boxes, insert def of
382
     *                          boxes only and not boxes activation
383
     *
384
     * @return int                         1 if OK, 0 if KO
385
     */
386
    protected function _init($array_sql, $options = '')
387
    {
388
        // phpcs:enable
389
        global $conf;
390
        $err=0;
391
392
        $this->db->begin();
393
394
        // Insert activation module constant
395
        if (! $err) {
396
            $err+=$this->_active();
397
        }
398
399
        // Insert new pages for tabs (into llx_const)
400
        if (! $err) {
401
            $err+=$this->insert_tabs();
402
        }
403
404
        // Insert activation of module's parts
405
        if (! $err) {
406
            $err+=$this->insert_module_parts();
407
        }
408
409
        // Insert constant defined by modules (into llx_const)
410
        if (! $err && ! preg_match('/newboxdefonly/', $options)) {
411
            $err+=$this->insert_const();    // Test on newboxdefonly to avoid to erase value during upgrade
412
        }
413
414
        // Insert boxes def into llx_boxes_def and boxes setup (into llx_boxes)
415
        if (! $err && ! preg_match('/noboxes/', $options)) {
416
            $err+=$this->insert_boxes($options);
417
        }
418
419
        // Insert cron job entries (entry in llx_cronjobs)
420
        if (! $err) {
421
            $err+=$this->insert_cronjobs();
422
        }
423
424
        // Insert permission definitions of module into llx_rights_def. If user is admin, grant this permission to user.
425
        if (! $err) {
426
            $err+=$this->insert_permissions(1, null, 1);
427
        }
428
429
        // Insert specific menus entries into database
430
        if (! $err) {
431
            $err+=$this->insert_menus();
432
        }
433
434
        // Create module's directories
435
        if (! $err) {
436
            $err+=$this->create_dirs();
437
        }
438
439
        // Execute addons requests
440
        $num=count($array_sql);
441
        for ($i = 0; $i < $num; $i++)
442
        {
443
            if (! $err) {
444
                $val=$array_sql[$i];
445
                $sql=$val;
446
                $ignoreerror=0;
447
                if (is_array($val)) {
448
                    $sql=$val['sql'];
449
                    $ignoreerror=$val['ignoreerror'];
450
                }
451
                // Add current entity id
452
                $sql=str_replace('__ENTITY__', $conf->entity, $sql);
453
454
                dol_syslog(get_class($this)."::_init ignoreerror=".$ignoreerror."", LOG_DEBUG);
455
                $result=$this->db->query($sql, $ignoreerror);
456
                if (! $result) {
457
                    if (! $ignoreerror) {
458
                         $this->error=$this->db->lasterror();
459
                         $err++;
460
                    }
461
                    else
462
                    {
463
                         dol_syslog(get_class($this)."::_init Warning ".$this->db->lasterror(), LOG_WARNING);
464
                    }
465
                }
466
            }
467
        }
468
469
        // Return code
470
        if (! $err) {
471
            $this->db->commit();
472
            return 1;
473
        }
474
        else
475
        {
476
            $this->db->rollback();
477
            return 0;
478
        }
479
    }
480
481
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
482
    /**
483
     * Disable function. Deletes the module constants and boxes from the database.
484
     *
485
     * @param string[] $array_sql SQL requests to be executed when module is disabled
486
     * @param string   $options   Options when disabling module:
487
     *
488
     * @return int                     1 if OK, 0 if KO
489
     */
490
    protected function _remove($array_sql, $options = '')
491
    {
492
        // phpcs:enable
493
        $err=0;
494
495
        $this->db->begin();
496
497
        // Remove activation module line (constant MAIN_MODULE_MYMODULE in llx_const)
498
        if (! $err) {
499
            $err+=$this->_unactive();
500
        }
501
502
        // Remove activation of module's new tabs (MAIN_MODULE_MYMODULE_TABS_XXX in llx_const)
503
        if (! $err) {
504
            $err+=$this->delete_tabs();
505
        }
506
507
        // Remove activation of module's parts (MAIN_MODULE_MYMODULE_XXX in llx_const)
508
        if (! $err) {
509
            $err+=$this->delete_module_parts();
510
        }
511
512
        // Remove constants defined by modules
513
        if (! $err) {
514
            $err+=$this->delete_const();
515
        }
516
517
        // Remove list of module's available boxes (entry in llx_boxes)
518
        if (! $err && ! preg_match('/(newboxdefonly|noboxes)/', $options)) {
519
            $err+=$this->delete_boxes();    // We don't have to delete if option ask to keep boxes safe or ask to add new box def only
520
        }
521
522
        // Remove list of module's cron job entries (entry in llx_cronjobs)
523
        if (! $err) {
524
            $err+=$this->delete_cronjobs();
525
        }
526
527
        // Remove module's permissions from list of available permissions (entries in llx_rights_def)
528
        if (! $err) {
529
            $err+=$this->delete_permissions();
530
        }
531
532
        // Remove module's menus (entries in llx_menu)
533
        if (! $err) {
534
            $err+=$this->delete_menus();
535
        }
536
537
        // Remove module's directories
538
        if (! $err) {
539
            $err+=$this->delete_dirs();
540
        }
541
542
        // Run complementary sql requests
543
        $num=count($array_sql);
544
        for ($i = 0; $i < $num; $i++)
545
        {
546
            if (! $err) {
547
                dol_syslog(get_class($this)."::_remove", LOG_DEBUG);
548
                $result=$this->db->query($array_sql[$i]);
549
                if (! $result) {
550
                    $this->error=$this->db->error();
551
                    $err++;
552
                }
553
            }
554
        }
555
556
        // Return code
557
        if (! $err) {
558
            $this->db->commit();
559
            return 1;
560
        }
561
        else
562
        {
563
            $this->db->rollback();
564
            return 0;
565
        }
566
    }
567
568
569
    /**
570
     * Gives the translated module name if translation exists in admin.lang or into language files of module.
571
     * Otherwise return the module key name.
572
     *
573
     * @return string  Translated module name
574
     */
575
    public function getName()
576
    {
577
        global $langs;
578
        $langs->load("admin");
579
580
        if ($langs->transnoentitiesnoconv("Module".$this->numero."Name") != ("Module".$this->numero."Name")) {
581
            // If module name translation exists
582
            return $langs->transnoentitiesnoconv("Module".$this->numero."Name");
583
        }
584
        else
585
        {
586
            // If module name translation using it's unique id does not exist, we try to use its name to find translation
587
            if (is_array($this->langfiles)) {
1 ignored issue
show
introduced by
The condition is_array($this->langfiles) is always true.
Loading history...
588
                foreach($this->langfiles as $val)
589
                {
590
                    if ($val) { $langs->load($val);
591
                    }
592
                }
593
            }
594
595
            if ($langs->trans("Module".$this->name."Name") != ("Module".$this->name."Name")) {
596
                // If module name translation exists
597
                return $langs->transnoentitiesnoconv("Module".$this->name."Name");
598
            }
599
600
            // Last chance with simple label
601
            return $langs->transnoentitiesnoconv($this->name);
602
        }
603
    }
604
605
606
    /**
607
     * Gives the translated module description if translation exists in admin.lang or the default module description
608
     *
609
     * @return string  Translated module description
610
     */
611
    public function getDesc()
612
    {
613
        global $langs;
614
        $langs->load("admin");
615
616
        if ($langs->transnoentitiesnoconv("Module".$this->numero."Desc") != ("Module".$this->numero."Desc")) {
617
            // If module description translation exists
618
            return $langs->transnoentitiesnoconv("Module".$this->numero."Desc");
619
        }
620
        else
621
        {
622
            // If module description translation does not exist using its unique id, we can use its name to find translation
623
            if (is_array($this->langfiles)) {
1 ignored issue
show
introduced by
The condition is_array($this->langfiles) is always true.
Loading history...
624
                foreach($this->langfiles as $val)
625
                {
626
                    if ($val) { $langs->load($val);
627
                    }
628
                }
629
            }
630
631
            if ($langs->transnoentitiesnoconv("Module".$this->name."Desc") != ("Module".$this->name."Desc")) {
632
                // If module name translation exists
633
                return $langs->trans("Module".$this->name."Desc");
634
            }
635
636
            // Last chance with simple label
637
            return $langs->trans($this->description);
638
        }
639
    }
640
641
    /**
642
     * Gives the long description of a module. First check README-la_LA.md then README.md
643
     * If no markdown files found, it returns translated value of the key ->descriptionlong.
644
     *
645
     * @return string     Long description of a module from README.md of from property.
646
     */
647
    public function getDescLong()
648
    {
649
        global $langs;
650
        $langs->load("admin");
651
652
        include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
653
        include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
654
655
        $pathoffile = $this->getDescLongReadmeFound();
656
657
        if ($pathoffile)     // Mostly for external modules
658
        {
659
            $content = file_get_contents($pathoffile);
660
661
            if ((float) DOL_VERSION >= 6.0) {
662
                @include_once DOL_DOCUMENT_ROOT.'/core/lib/parsemd.lib.php';
663
664
                $content = dolMd2Html(
665
                    $content,
666
                    'parsedown',
667
                    array(
668
                        'doc/' => dol_buildpath(strtolower($this->name).'/doc/', 1),
669
                        'img/' => dol_buildpath(strtolower($this->name).'/img/', 1),
670
                        'images/' => dol_buildpath(strtolower($this->name).'/images/', 1),
671
                    )
672
                );
673
            }
674
            else
675
            {
676
                $content = nl2br($content);
677
            }
678
        }
679
        else
680
        {
681
            // Mostly for internal modules
682
            if (! empty($this->descriptionlong)) {
683
                if (is_array($this->langfiles)) {
1 ignored issue
show
introduced by
The condition is_array($this->langfiles) is always true.
Loading history...
684
                    foreach($this->langfiles as $val)
685
                    {
686
                        if ($val) { $langs->load($val);
687
                        }
688
                    }
689
                }
690
691
                $content = $langs->transnoentitiesnoconv($this->descriptionlong);
692
            }
693
        }
694
695
        return $content;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $content does not seem to be defined for all execution paths leading up to this point.
Loading history...
696
    }
697
698
    /**
699
     * Return path of file if a README file was found.
700
     *
701
     * @return string      Path of file if a README file was found.
702
     */
703
    public function getDescLongReadmeFound()
704
    {
705
        global $langs;
706
707
        $filefound= false;
708
709
        // Define path to file README.md.
710
        // First check README-la_LA.md then README-la.md then README.md
711
        $pathoffile = dol_buildpath(strtolower($this->name).'/README-'.$langs->defaultlang.'.md', 0);
712
        if (dol_is_file($pathoffile)) {
713
            $filefound = true;
714
        }
715
        if (! $filefound) {
716
            $tmp=explode('_', $langs->defaultlang);
717
            $pathoffile = dol_buildpath(strtolower($this->name).'/README-'.$tmp[0].'.md', 0);
718
            if (dol_is_file($pathoffile)) {
719
                $filefound = true;
720
            }
721
        }
722
        if (! $filefound) {
723
            $pathoffile = dol_buildpath(strtolower($this->name).'/README.md', 0);
724
            if (dol_is_file($pathoffile)) {
725
                $filefound = true;
726
            }
727
        }
728
729
        return ($filefound?$pathoffile:'');
730
    }
731
732
733
    /**
734
     * Gives the changelog. First check ChangeLog-la_LA.md then ChangeLog.md
735
     *
736
     * @return string  Content of ChangeLog
737
     */
738
    public function getChangeLog()
739
    {
740
        global $langs;
741
        $langs->load("admin");
742
743
        include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
744
        include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
745
746
        $filefound= false;
747
748
        // Define path to file README.md.
749
        // First check ChangeLog-la_LA.md then ChangeLog.md
750
        $pathoffile = dol_buildpath(strtolower($this->name).'/ChangeLog-'.$langs->defaultlang.'.md', 0);
751
        if (dol_is_file($pathoffile)) {
752
            $filefound = true;
753
        }
754
        if (! $filefound) {
755
            $pathoffile = dol_buildpath(strtolower($this->name).'/ChangeLog.md', 0);
756
            if (dol_is_file($pathoffile)) {
757
                $filefound = true;
758
            }
759
        }
760
761
        if ($filefound)     // Mostly for external modules
762
        {
763
            $content = file_get_contents($pathoffile);
764
765
            if ((float) DOL_VERSION >= 6.0) {
766
                @include_once DOL_DOCUMENT_ROOT.'/core/lib/parsemd.lib.php';
767
                $content = dolMd2Html($content, 'parsedown', array('doc/'=>dol_buildpath(strtolower($this->name).'/doc/', 1)));
768
            }
769
            else
770
            {
771
                $content = nl2br($content);
772
            }
773
        }
774
775
        return $content;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $content does not seem to be defined for all execution paths leading up to this point.
Loading history...
776
    }
777
778
    /**
779
     * Gives the publisher name
780
     *
781
     * @return string  Publisher name
782
     */
783
    public function getPublisher()
784
    {
785
        return $this->editor_name;
786
    }
787
788
    /**
789
     * Gives the publisher url
790
     *
791
     * @return string  Publisher url
792
     */
793
    public function getPublisherUrl()
794
    {
795
        return $this->editor_url;
796
    }
797
798
    /**
799
     * Gives module version (translated if param $translated is on)
800
     * For 'experimental' modules, gives 'experimental' translation
801
     * For 'dolibarr' modules, gives Dolibarr version
802
     *
803
     * @param  int $translated 1=Special version keys are translated, 0=Special version keys are not translated
804
     * @return string                  Module version
805
     */
806
    public function getVersion($translated = 1)
807
    {
808
        global $langs;
809
        $langs->load("admin");
810
811
        $ret='';
812
813
        $newversion=preg_replace('/_deprecated/', '', $this->version);
814
        if ($newversion == 'experimental') {
815
            $ret=($translated?$langs->transnoentitiesnoconv("VersionExperimental"):$newversion);
816
        } elseif ($newversion == 'development') {
817
            $ret=($translated?$langs->transnoentitiesnoconv("VersionDevelopment"):$newversion);
818
        } elseif ($newversion == 'dolibarr') {
819
            $ret=DOL_VERSION;
820
        } elseif ($newversion) {
821
            $ret=$newversion;
822
        } else {
823
            $ret=($translated?$langs->transnoentitiesnoconv("VersionUnknown"):'unknown');
824
        }
825
826
        if (preg_match('/_deprecated/', $this->version)) {
827
            $ret.=($translated?' ('.$langs->transnoentitiesnoconv("Deprecated").')':$this->version);
828
        }
829
        return $ret;
830
    }
831
832
833
    /**
834
     * Tells if module is core or external
835
     *
836
     * @return string  'core', 'external' or 'unknown'
837
     */
838
    public function isCoreOrExternalModule()
839
    {
840
        if ($this->version == 'dolibarr' || $this->version == 'dolibarr_deprecated') {
841
            return 'core';
842
        }
843
        if (! empty($this->version) && ! in_array($this->version, array('experimental','development'))) {
844
            return 'external';
845
        }
846
        if (! empty($this->editor_name) || ! empty($this->editor_url)) {
847
            return 'external';
848
        }
849
        if ($this->numero >= 100000) {
850
            return 'external';
851
        }
852
        return 'unknown';
853
    }
854
855
856
    /**
857
     * Gives module related language files list
858
     *
859
     * @return string[]    Language files list
860
     */
861
    public function getLangFilesArray()
862
    {
863
        return $this->langfiles;
864
    }
865
866
    /**
867
     * Gives translated label of an export dataset
868
     *
869
     * @param int $r Dataset index
870
     *
871
     * @return string       Translated databaset label
872
     */
873
    public function getExportDatasetLabel($r)
874
    {
875
        global $langs;
876
877
        $langstring="ExportDataset_".$this->export_code[$r];
878
        if ($langs->trans($langstring) == $langstring) {
879
            // Translation not found
880
            return $langs->trans($this->export_label[$r]);
881
        }
882
        else
883
        {
884
            // Translation found
885
            return $langs->trans($langstring);
886
        }
887
    }
888
889
890
    /**
891
     * Gives translated label of an import dataset
892
     *
893
     * @param int $r Dataset index
894
     *
895
     * @return string      Translated dataset label
896
     */
897
    public function getImportDatasetLabel($r)
898
    {
899
        global $langs;
900
901
        $langstring="ImportDataset_".$this->import_code[$r];
902
        //print "x".$langstring;
903
        if ($langs->trans($langstring) == $langstring) {
904
            // Translation not found
905
            return $langs->transnoentitiesnoconv($this->import_label[$r]);
906
        }
907
        else
908
        {
909
            // Translation found
910
            return $langs->transnoentitiesnoconv($langstring);
911
        }
912
    }
913
914
915
    /**
916
     * Gives the last date of activation
917
     *
918
     * @return timestamp|string       Date of last activation
0 ignored issues
show
Bug introduced by
The type timestamp was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
919
     */
920
    public function getLastActivationDate()
921
    {
922
        global $conf;
923
924
        $err = 0;
925
926
        $sql = "SELECT tms FROM ".MAIN_DB_PREFIX."const";
927
        $sql.= " WHERE ".$this->db->decrypt('name')." = '".$this->db->escape($this->const_name)."'";
928
        $sql.= " AND entity IN (0, ".$conf->entity.")";
929
930
        dol_syslog(get_class($this)."::getLastActiveDate", LOG_DEBUG);
931
        $resql=$this->db->query($sql);
932
        if (! $resql)
933
        {
934
            $err++;
935
        }
936
        else
937
        {
938
            $obj=$this->db->fetch_object($resql);
939
            if ($obj) {
940
                return $this->db->jdate($obj->tms);
941
            }
942
        }
943
944
        return '';
945
    }
946
947
948
    /**
949
     * Gives the last author of activation
950
     *
951
     * @return array       Array array('authorid'=>Id of last activation user, 'lastactivationdate'=>Date of last activation)
952
     */
953
    public function getLastActivationInfo()
954
    {
955
        global $conf;
956
957
        $err = 0;
958
959
		$sql = "SELECT tms, note FROM ".MAIN_DB_PREFIX."const";
960
		$sql.= " WHERE ".$this->db->decrypt('name')." = '".$this->db->escape($this->const_name)."'";
961
		$sql.= " AND entity IN (0, ".$conf->entity.")";
962
963
        dol_syslog(get_class($this)."::getLastActiveDate", LOG_DEBUG);
964
        $resql=$this->db->query($sql);
965
        if (! $resql)
966
        {
967
            $err++;
968
        }
969
        else
970
        {
971
            $obj=$this->db->fetch_object($resql);
972
            $tmp=array();
973
            if ($obj->note) {
974
                $tmp=json_decode($obj->note, true);
975
            }
976
            if ($obj) {
977
                return array('authorid'=>$tmp['authorid'], 'ip'=>$tmp['ip'], 'lastactivationdate'=>$this->db->jdate($obj->tms));
978
            }
979
        }
980
981
        return array();
982
    }
983
984
985
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
986
    /**
987
     * Insert constants for module activation
988
     *
989
     * @return int Error count (0 if OK)
990
     */
991
    protected function _active()
992
    {
993
        // phpcs:enable
994
        global $conf, $user;
995
996
        $err = 0;
997
998
        // Common module
999
        $entity = ((! empty($this->always_enabled) || ! empty($this->core_enabled)) ? 0 : $conf->entity);
1000
1001
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."const";
1002
        $sql.= " WHERE ".$this->db->decrypt('name')." = '".$this->db->escape($this->const_name)."'";
1003
        $sql.= " AND entity IN (0, ".$entity.")";
1004
1005
        dol_syslog(get_class($this)."::_active delete activation constant", LOG_DEBUG);
1006
        $resql=$this->db->query($sql);
1007
        if (! $resql) {
1008
            $err++;
1009
        }
1010
1011
        $note=json_encode(array('authorid'=>(is_object($user)?$user->id:0), 'ip'=>(empty($_SERVER['REMOTE_ADDR'])?'':$_SERVER['REMOTE_ADDR'])));
1012
1013
        $sql = "INSERT INTO ".MAIN_DB_PREFIX."const (name, value, visible, entity, note) VALUES";
1014
        $sql.= " (".$this->db->encrypt($this->const_name, 1);
1015
        $sql.= ", ".$this->db->encrypt('1', 1);
1016
        $sql.= ", 0, ".$entity;
1017
        $sql.= ", '".$this->db->escape($note)."')";
1018
1019
        dol_syslog(get_class($this)."::_active insert activation constant", LOG_DEBUG);
1020
        $resql=$this->db->query($sql);
1021
        if (! $resql) { $err++;
1022
        }
1023
1024
        return $err;
1025
    }
1026
1027
1028
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1029
    /**
1030
     * Module deactivation
1031
     *
1032
     * @return int Error count (0 if OK)
1033
     */
1034
    protected function _unactive()
1035
    {
1036
        // phpcs:enable
1037
        global $conf;
1038
1039
        $err = 0;
1040
1041
        // Common module
1042
        $entity = ((! empty($this->always_enabled) || ! empty($this->core_enabled)) ? 0 : $conf->entity);
1043
1044
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."const";
1045
        $sql.= " WHERE ".$this->db->decrypt('name')." = '".$this->db->escape($this->const_name)."'";
1046
        $sql.= " AND entity IN (0, ".$entity.")";
1047
1048
        dol_syslog(get_class($this)."::_unactive", LOG_DEBUG);
1049
        $this->db->query($sql);
1050
1051
        return $err;
1052
    }
1053
1054
1055
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps,PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1056
    /**
1057
     * Create tables and keys required by module.
1058
     * Files module.sql and module.key.sql with create table and create keys
1059
     * commands must be stored in directory reldir='/module/sql/'
1060
     * This function is called by this->init
1061
     *
1062
     * @param  string $reldir Relative directory where to scan files
1063
     * @return int             <=0 if KO, >0 if OK
1064
     */
1065
    protected function _load_tables($reldir)
1066
    {
1067
        // phpcs:enable
1068
        global $conf;
1069
1070
        $error=0;
1071
        $dirfound=0;
1072
1073
        if (empty($reldir)) {
1074
            return 1;
1075
        }
1076
1077
        include_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
1078
1079
        $ok = 1;
1080
        foreach($conf->file->dol_document_root as $dirroot)
1081
        {
1082
            if ($ok) {
1083
                $dir = $dirroot.$reldir;
1084
                $ok = 0;
1085
1086
                $handle=@opendir($dir);         // Dir may not exists
1087
                if (is_resource($handle)) {
1088
                    $dirfound++;
1089
1090
                    // Run llx_mytable.sql files, then llx_mytable_*.sql
1091
                    $files = array();
1092
                    while (($file = readdir($handle))!==false)
1093
                    {
1094
                        $files[] = $file;
1095
                    }
1096
                    sort($files);
1097
                    foreach ($files as $file)
1098
                    {
1099
                        if (preg_match('/\.sql$/i', $file) && ! preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'llx_' && substr($file, 0, 4) != 'data') {
1100
                            $result=run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG)?1:0, '', 1);
1101
                            if ($result <= 0) { $error++;
1102
                            }
1103
                        }
1104
                    }
1105
1106
                    rewinddir($handle);
1107
1108
                    // Run llx_mytable.key.sql files (Must be done after llx_mytable.sql) then then llx_mytable_*.key.sql
1109
                    $files = array();
1110
                    while (($file = readdir($handle))!==false)
1111
                    {
1112
                        $files[] = $file;
1113
                    }
1114
                    sort($files);
1115
                    foreach ($files as $file)
1116
                    {
1117
                        if (preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'llx_' && substr($file, 0, 4) != 'data') {
1118
                            $result=run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG)?1:0, '', 1);
1119
                            if ($result <= 0) { $error++;
1120
                            }
1121
                        }
1122
                    }
1123
1124
                    rewinddir($handle);
1125
1126
                    // Run data_xxx.sql files (Must be done after llx_mytable.key.sql)
1127
                    $files = array();
1128
                    while (($file = readdir($handle))!==false)
1129
                    {
1130
                               $files[] = $file;
1131
                    }
1132
                    sort($files);
1133
                    foreach ($files as $file)
1134
                    {
1135
                        if (preg_match('/\.sql$/i', $file) && ! preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'data') {
1136
                            $result=run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG)?1:0, '', 1);
1137
                            if ($result <= 0) { $error++;
1138
                            }
1139
                        }
1140
                    }
1141
1142
                    rewinddir($handle);
1143
1144
                    // Run update_xxx.sql files
1145
                    $files = array();
1146
                    while (($file = readdir($handle))!==false)
1147
                    {
1148
                               $files[] = $file;
1149
                    }
1150
                    sort($files);
1151
                    foreach ($files as $file)
1152
                    {
1153
                        if (preg_match('/\.sql$/i', $file) && ! preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 6) == 'update') {
1154
                            $result=run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG)?1:0, '', 1);
1155
                            if ($result <= 0) { $error++;
1156
                            }
1157
                        }
1158
                    }
1159
1160
                    closedir($handle);
1161
                }
1162
1163
                if ($error == 0) {
1164
                    $ok = 1;
1165
                }
1166
            }
1167
        }
1168
1169
        if (! $dirfound) {
1170
            dol_syslog("A module ask to load sql files into ".$reldir." but this directory was not found.", LOG_WARNING);
1171
        }
1172
        return $ok;
1173
    }
1174
1175
1176
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1177
    /**
1178
     * Adds boxes
1179
     *
1180
     * @param string $option Options when disabling module ('newboxdefonly'=insert only boxes definition)
1181
     *
1182
     * @return int             Error count (0 if OK)
1183
     */
1184
    public function insert_boxes($option = '')
1185
    {
1186
        // phpcs:enable
1187
        include_once DOL_DOCUMENT_ROOT . '/core/class/infobox.class.php';
1188
1189
        global $conf;
1190
1191
        $err=0;
1192
1193
        if (is_array($this->boxes)) {
1 ignored issue
show
introduced by
The condition is_array($this->boxes) is always true.
Loading history...
1194
            dol_syslog(get_class($this)."::insert_boxes", LOG_DEBUG);
1195
1196
            $pos_name = InfoBox::getListOfPagesForBoxes();
1197
1198
            foreach ($this->boxes as $key => $value)
1199
            {
1200
                $file  = isset($this->boxes[$key]['file'])?$this->boxes[$key]['file']:'';
1201
                $note  = isset($this->boxes[$key]['note'])?$this->boxes[$key]['note']:'';
1202
                $enabledbydefaulton = isset($this->boxes[$key]['enabledbydefaulton'])?$this->boxes[$key]['enabledbydefaulton']:'Home';
1203
1204
                if (empty($file)) { $file  = isset($this->boxes[$key][1])?$this->boxes[$key][1]:'';    // For backward compatibility
1205
                }
1206
                if (empty($note)) { $note  = isset($this->boxes[$key][2])?$this->boxes[$key][2]:'';    // For backward compatibility
1207
                }
1208
1209
                // Search if boxes def already present
1210
                $sql = "SELECT count(*) as nb FROM ".MAIN_DB_PREFIX."boxes_def";
1211
                $sql.= " WHERE file = '".$this->db->escape($file)."'";
1212
                $sql.= " AND entity = ".$conf->entity;
1213
                if ($note) { $sql.=" AND note ='".$this->db->escape($note)."'";
1214
                }
1215
1216
                $result=$this->db->query($sql);
1217
                if ($result) {
1218
                    $obj = $this->db->fetch_object($result);
1219
                    if ($obj->nb == 0) {
1220
                        $this->db->begin();
1221
1222
                        if (! $err) {
1223
                            $sql = "INSERT INTO ".MAIN_DB_PREFIX."boxes_def (file, entity, note)";
1224
                            $sql.= " VALUES ('".$this->db->escape($file)."', ";
1225
                            $sql.= $conf->entity.", ";
1226
                            $sql.= $note?"'".$this->db->escape($note)."'":"null";
1227
                            $sql.= ")";
1228
1229
                            dol_syslog(get_class($this)."::insert_boxes", LOG_DEBUG);
1230
                            $resql=$this->db->query($sql);
1231
                            if (! $resql) { $err++;
1232
                            }
1233
                        }
1234
                        if (! $err && ! preg_match('/newboxdefonly/', $option)) {
1235
                            $lastid=$this->db->last_insert_id(MAIN_DB_PREFIX."boxes_def", "rowid");
1236
1237
                            foreach ($pos_name as $key2 => $val2)
1238
                            {
1239
                                    //print 'key2='.$key2.'-val2='.$val2."<br>\n";
1240
                                if ($enabledbydefaulton && $val2 != $enabledbydefaulton) { continue;        // Not enabled by default onto this page.
1241
                                }
1242
1243
                                $sql = "INSERT INTO ".MAIN_DB_PREFIX."boxes (box_id,position,box_order,fk_user,entity)";
1244
                                $sql.= " VALUES (".$lastid.", ".$key2.", '0', 0, ".$conf->entity.")";
1245
1246
                                dol_syslog(get_class($this)."::insert_boxes onto page ".$key2."=".$val2."", LOG_DEBUG);
1247
                                $resql=$this->db->query($sql);
1248
                                if (! $resql) { $err++;
1249
                                }
1250
                            }
1251
                        }
1252
1253
                        if (! $err) {
1254
                            $this->db->commit();
1255
                        }
1256
                        else
1257
                        {
1258
                                  $this->error=$this->db->lasterror();
1259
                                  $this->db->rollback();
1260
                        }
1261
                    }
1262
                    // else box already registered into database
1263
                }
1264
                else
1265
                {
1266
                    $this->error=$this->db->lasterror();
1267
                    $err++;
1268
                }
1269
            }
1270
        }
1271
1272
        return $err;
1273
    }
1274
1275
1276
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1277
    /**
1278
     * Removes boxes
1279
     *
1280
     * @return int Error count (0 if OK)
1281
     */
1282
    public function delete_boxes()
1283
    {
1284
        // phpcs:enable
1285
        global $conf;
1286
1287
        $err=0;
1288
1289
        if (is_array($this->boxes)) {
1 ignored issue
show
introduced by
The condition is_array($this->boxes) is always true.
Loading history...
1290
            foreach ($this->boxes as $key => $value)
1291
            {
1292
                //$titre = $this->boxes[$key][0];
1293
                $file  = $this->boxes[$key]['file'];
1294
                //$note  = $this->boxes[$key][2];
1295
1296
                // TODO If the box is also included by another module and the other module is still on, we should not remove it.
1297
                // For the moment, we manage this with hard coded exception
1298
                //print "Remove box ".$file.'<br>';
1299
                if ($file == 'box_graph_product_distribution.php') {
1300
                    if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) {
1301
                        dol_syslog("We discard disabling of module ".$file." because another module still active require it.");
1302
                        continue;
1303
                    }
1304
                }
1305
1306
                if (empty($file)) { $file  = isset($this->boxes[$key][1])?$this->boxes[$key][1]:'';    // For backward compatibility
1307
                }
1308
1309
                if ($this->db->type == 'sqlite3') {
1310
                    // sqlite doesn't support "USING" syntax.
1311
                    // TODO: remove this dependency.
1312
                    $sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes ";
1313
                    $sql .= "WHERE ".MAIN_DB_PREFIX."boxes.box_id IN (";
1314
                    $sql .= "SELECT ".MAIN_DB_PREFIX."boxes_def.rowid ";
1315
                    $sql .= "FROM ".MAIN_DB_PREFIX."boxes_def ";
1316
                    $sql .= "WHERE ".MAIN_DB_PREFIX."boxes_def.file = '".$this->db->escape($file)."') ";
1317
                    $sql .= "AND ".MAIN_DB_PREFIX."boxes.entity = ".$conf->entity;
1318
                } else {
1319
                    $sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes";
1320
                    $sql.= " USING ".MAIN_DB_PREFIX."boxes, ".MAIN_DB_PREFIX."boxes_def";
1321
                    $sql.= " WHERE ".MAIN_DB_PREFIX."boxes.box_id = ".MAIN_DB_PREFIX."boxes_def.rowid";
1322
                    $sql.= " AND ".MAIN_DB_PREFIX."boxes_def.file = '".$this->db->escape($file)."'";
1323
                    $sql.= " AND ".MAIN_DB_PREFIX."boxes.entity = ".$conf->entity;
1324
                }
1325
1326
                dol_syslog(get_class($this)."::delete_boxes", LOG_DEBUG);
1327
                $resql=$this->db->query($sql);
1328
                if (! $resql) {
1329
                    $this->error=$this->db->lasterror();
1330
                    $err++;
1331
                }
1332
1333
                $sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes_def";
1334
                $sql.= " WHERE file = '".$this->db->escape($file)."'";
1335
                $sql.= " AND entity = ".$conf->entity;
1336
1337
                dol_syslog(get_class($this)."::delete_boxes", LOG_DEBUG);
1338
                $resql=$this->db->query($sql);
1339
                if (! $resql) {
1340
                    $this->error=$this->db->lasterror();
1341
                    $err++;
1342
                }
1343
            }
1344
        }
1345
1346
        return $err;
1347
    }
1348
1349
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1350
    /**
1351
     * Adds cronjobs
1352
     *
1353
     * @return int             Error count (0 if OK)
1354
     */
1355
    public function insert_cronjobs()
1356
    {
1357
        // phpcs:enable
1358
        include_once DOL_DOCUMENT_ROOT . '/core/class/infobox.class.php';
1359
1360
        global $conf;
1361
1362
        $err=0;
1363
1364
        if (is_array($this->cronjobs)) {
1 ignored issue
show
introduced by
The condition is_array($this->cronjobs) is always true.
Loading history...
1365
            dol_syslog(get_class($this)."::insert_cronjobs", LOG_DEBUG);
1366
1367
            foreach ($this->cronjobs as $key => $value)
1368
            {
1369
                $entity  = isset($this->cronjobs[$key]['entity'])?$this->cronjobs[$key]['entity']:$conf->entity;
1370
                $label  = isset($this->cronjobs[$key]['label'])?$this->cronjobs[$key]['label']:'';
1371
                $jobtype  = isset($this->cronjobs[$key]['jobtype'])?$this->cronjobs[$key]['jobtype']:'';
1372
                $class  = isset($this->cronjobs[$key]['class'])?$this->cronjobs[$key]['class']:'';
1373
                $objectname  = isset($this->cronjobs[$key]['objectname'])?$this->cronjobs[$key]['objectname']:'';
1374
                $method = isset($this->cronjobs[$key]['method'])?$this->cronjobs[$key]['method']:'';
1375
                $command  = isset($this->cronjobs[$key]['command'])?$this->cronjobs[$key]['command']:'';
1376
                $parameters  = isset($this->cronjobs[$key]['parameters'])?$this->cronjobs[$key]['parameters']:'';
1377
                $comment = isset($this->cronjobs[$key]['comment'])?$this->cronjobs[$key]['comment']:'';
1378
                $frequency = isset($this->cronjobs[$key]['frequency'])?$this->cronjobs[$key]['frequency']:'';
1379
                $unitfrequency = isset($this->cronjobs[$key]['unitfrequency'])?$this->cronjobs[$key]['unitfrequency']:'';
1380
                $priority = isset($this->cronjobs[$key]['priority'])?$this->cronjobs[$key]['priority']:'';
1381
                $datestart = isset($this->cronjobs[$key]['datestart'])?$this->cronjobs[$key]['datestart']:'';
1382
                $dateend = isset($this->cronjobs[$key]['dateend'])?$this->cronjobs[$key]['dateend']:'';
1383
                $status = isset($this->cronjobs[$key]['status'])?$this->cronjobs[$key]['status']:'';
1384
                $test = isset($this->cronjobs[$key]['test'])?$this->cronjobs[$key]['test']:'';                    // Line must be enabled or not (so visible or not)
1385
1386
                // Search if cron entry already present
1387
                $sql = "SELECT count(*) as nb FROM ".MAIN_DB_PREFIX."cronjob";
1388
                $sql.= " WHERE module_name = '".$this->db->escape(empty($this->rights_class)?strtolower($this->name):$this->rights_class)."'";
1389
                if ($class) {
1390
                    $sql.= " AND classesname = '".$this->db->escape($class)."'";
1391
                }
1392
                if ($objectname) {
1393
                    $sql.= " AND objectname = '".$this->db->escape($objectname)."'";
1394
                }
1395
                if ($method) {
1396
                    $sql.= " AND methodename = '".$this->db->escape($method)."'";
1397
                }
1398
                if ($command) {
1399
                    $sql.= " AND command = '".$this->db->escape($command)."'";
1400
                }
1401
                $sql.= " AND entity = ".$entity;    // Must be exact entity
1402
1403
                $now=dol_now();
1404
1405
                $result=$this->db->query($sql);
1406
                if ($result) {
1407
                    $obj = $this->db->fetch_object($result);
1408
                    if ($obj->nb == 0) {
1409
                        $this->db->begin();
1410
1411
                        if (! $err) {
1412
                            $sql = "INSERT INTO ".MAIN_DB_PREFIX."cronjob (module_name, datec, datestart, dateend, label, jobtype, classesname, objectname, methodename, command, params, note,";
1413
                            if (is_int($frequency)) { $sql.= ' frequency,'; }
1414
                            if (is_int($unitfrequency)) { $sql.= ' unitfrequency,'; }
1415
                            if (is_int($priority)) { $sql.= ' priority,'; }
1416
                            if (is_int($status)) { $sql.= ' status,'; }
1417
                            $sql.= " entity, test)";
1418
                            $sql.= " VALUES (";
1419
                            $sql.= "'".$this->db->escape(empty($this->rights_class)?strtolower($this->name):$this->rights_class)."', ";
1420
                            $sql.= "'".$this->db->idate($now)."', ";
1421
                            $sql.= ($datestart ? "'".$this->db->idate($datestart)."'" : "'".$this->db->idate($now)."'").", ";
1422
                            $sql.= ($dateend   ? "'".$this->db->idate($dateend)."'"   : "NULL").", ";
1423
                            $sql.= "'".$this->db->escape($label)."', ";
1424
                            $sql.= "'".$this->db->escape($jobtype)."', ";
1425
                            $sql.= ($class?"'".$this->db->escape($class)."'":"null").",";
1426
                            $sql.= ($objectname?"'".$this->db->escape($objectname)."'":"null").",";
1427
                            $sql.= ($method?"'".$this->db->escape($method)."'":"null").",";
1428
                            $sql.= ($command?"'".$this->db->escape($command)."'":"null").",";
1429
                            $sql.= ($parameters?"'".$this->db->escape($parameters)."'":"null").",";
1430
                            $sql.= ($comment?"'".$this->db->escape($comment)."'":"null").",";
1431
                            if(is_int($frequency)) { $sql.= "'".$this->db->escape($frequency)."', ";
1432
                            }
1433
                            if(is_int($unitfrequency)) { $sql.= "'".$this->db->escape($unitfrequency)."', ";
1434
                            }
1435
                            if(is_int($priority)) {$sql.= "'".$this->db->escape($priority)."', ";
1436
                            }
1437
                            if(is_int($status)) { $sql.= "'".$this->db->escape($status)."', ";
1438
                            }
1439
                            $sql.= $entity.",";
1440
                            $sql.= "'".$this->db->escape($test)."'";
1441
                            $sql.= ")";
1442
1443
                            $resql=$this->db->query($sql);
1444
                            if (! $resql) { $err++;
1445
                            }
1446
                        }
1447
1448
                        if (! $err) {
1449
                            $this->db->commit();
1450
                        }
1451
                        else
1452
                        {
1453
                            $this->error=$this->db->lasterror();
1454
                            $this->db->rollback();
1455
                        }
1456
                    }
1457
                    // else box already registered into database
1458
                }
1459
                else
1460
                {
1461
                    $this->error=$this->db->lasterror();
1462
                    $err++;
1463
                }
1464
            }
1465
        }
1466
1467
        return $err;
1468
    }
1469
1470
1471
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1472
    /**
1473
     * Removes boxes
1474
     *
1475
     * @return int Error count (0 if OK)
1476
     */
1477
    public function delete_cronjobs()
1478
    {
1479
        // phpcs:enable
1480
        global $conf;
1481
1482
        $err=0;
1483
1484
        if (is_array($this->cronjobs)) {
1 ignored issue
show
introduced by
The condition is_array($this->cronjobs) is always true.
Loading history...
1485
            $sql = "DELETE FROM ".MAIN_DB_PREFIX."cronjob";
1486
            $sql.= " WHERE module_name = '".$this->db->escape(empty($this->rights_class)?strtolower($this->name):$this->rights_class)."'";
1487
            $sql.= " AND entity = ".$conf->entity;
1488
            $sql.= " AND test = '1'";        // We delete on lines that are not set with a complete test that is '$conf->module->enabled' so when module is disabled, the cron is also removed.
1489
              // For crons declared with a '$conf->module->enabled', there is no need to delete the line, so we don't loose setup if we reenable module.
1490
1491
            dol_syslog(get_class($this)."::delete_cronjobs", LOG_DEBUG);
1492
            $resql=$this->db->query($sql);
1493
            if (! $resql) {
1494
                $this->error=$this->db->lasterror();
1495
                $err++;
1496
            }
1497
        }
1498
1499
        return $err;
1500
    }
1501
1502
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1503
    /**
1504
     * Removes tabs
1505
     *
1506
     * @return int Error count (0 if OK)
1507
     */
1508
    public function delete_tabs()
1509
    {
1510
        // phpcs:enable
1511
        global $conf;
1512
1513
        $err=0;
1514
1515
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."const";
1516
        $sql.= " WHERE ".$this->db->decrypt('name')." like '".$this->db->escape($this->const_name)."_TABS_%'";
1517
        $sql.= " AND entity = ".$conf->entity;
1518
1519
        dol_syslog(get_class($this)."::delete_tabs", LOG_DEBUG);
1520
        if (! $this->db->query($sql)) {
1521
            $this->error=$this->db->lasterror();
1522
            $err++;
1523
        }
1524
1525
        return $err;
1526
    }
1527
1528
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1529
    /**
1530
     * Adds tabs
1531
     *
1532
     * @return int  Error count (0 if ok)
1533
     */
1534
    public function insert_tabs()
1535
    {
1536
        // phpcs:enable
1537
        global $conf;
1538
1539
        $err=0;
1540
1541
        if (! empty($this->tabs)) {
1542
            dol_syslog(get_class($this)."::insert_tabs", LOG_DEBUG);
1543
1544
            $i=0;
1545
            foreach ($this->tabs as $key => $value)
1546
            {
1547
                if (is_array($value) && count($value) == 0) { continue;    // Discard empty arrays
1548
                }
1549
1550
                $entity=$conf->entity;
1551
                $newvalue = $value;
1552
1553
                if (is_array($value)) {
1554
                    $newvalue = $value['data'];
1555
                    if (isset($value['entity'])) { $entity = $value['entity'];
1556
                    }
1557
                }
1558
1559
                if ($newvalue) {
1560
                    $sql = "INSERT INTO ".MAIN_DB_PREFIX."const (";
1561
                    $sql.= "name";
1562
                    $sql.= ", type";
1563
                    $sql.= ", value";
1564
                    $sql.= ", note";
1565
                    $sql.= ", visible";
1566
                    $sql.= ", entity";
1567
                    $sql.= ")";
1568
                    $sql.= " VALUES (";
1569
                    $sql.= $this->db->encrypt($this->const_name."_TABS_".$i, 1);
1570
                    $sql.= ", 'chaine'";
1571
                    $sql.= ", ".$this->db->encrypt($newvalue, 1);
1572
                    $sql.= ", null";
1573
                    $sql.= ", '0'";
1574
                    $sql.= ", ".$entity;
1575
                    $sql.= ")";
1576
1577
                    $resql = $this->db->query($sql);
1578
                    if (! $resql) {
1579
                         dol_syslog($this->db->lasterror(), LOG_ERR);
1580
                        if ($this->db->lasterrno() != 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1581
                            $this->error = $this->db->lasterror();
1582
                            $this->errors[] = $this->db->lasterror();
1583
                            $err++;
1584
                            break;
1585
                        }
1586
                    }
1587
                }
1588
                $i++;
1589
            }
1590
        }
1591
        return $err;
1592
    }
1593
1594
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1595
    /**
1596
     * Adds constants
1597
     *
1598
     * @return int Error count (0 if OK)
1599
     */
1600
    public function insert_const()
1601
    {
1602
        // phpcs:enable
1603
        global $conf;
1604
1605
        $err=0;
1606
1607
        if (empty($this->const)) { return 0;
1608
        }
1609
1610
        dol_syslog(get_class($this)."::insert_const", LOG_DEBUG);
1611
1612
        foreach ($this->const as $key => $value)
1613
        {
1614
            $name      = $this->const[$key][0];
1615
            $type      = $this->const[$key][1];
1616
            $val       = $this->const[$key][2];
1617
            $note      = isset($this->const[$key][3])?$this->const[$key][3]:'';
1618
            $visible   = isset($this->const[$key][4])?$this->const[$key][4]:0;
1619
            $entity    = (! empty($this->const[$key][5]) && $this->const[$key][5]!='current')?0:$conf->entity;
1620
1621
            // Clean
1622
            if (empty($visible)) { $visible='0';
1623
            }
1624
            if (empty($val) && $val != '0') { $val='';
1625
            }
1626
1627
            $sql = "SELECT count(*)";
1628
            $sql.= " FROM ".MAIN_DB_PREFIX."const";
1629
            $sql.= " WHERE ".$this->db->decrypt('name')." = '".$this->db->escape($name)."'";
1630
            $sql.= " AND entity = ".$entity;
1631
1632
            $result=$this->db->query($sql);
1633
            if ($result) {
1634
                $row = $this->db->fetch_row($result);
1635
1636
                if ($row[0] == 0)   // If not found
1637
                {
1638
                    $sql = "INSERT INTO ".MAIN_DB_PREFIX."const (name,type,value,note,visible,entity)";
1639
                    $sql.= " VALUES (";
1640
                    $sql.= $this->db->encrypt($name, 1);
1641
                    $sql.= ",'".$type."'";
1642
                    $sql.= ",".(($val != '')?$this->db->encrypt($val, 1):"''");
1643
                    $sql.= ",".($note?"'".$this->db->escape($note)."'":"null");
1644
                    $sql.= ",'".$visible."'";
1645
                    $sql.= ",".$entity;
1646
                    $sql.= ")";
1647
1648
                    if (! $this->db->query($sql) ) {
1649
                        $err++;
1650
                    }
1651
                }
1652
                else
1653
                {
1654
                    dol_syslog(get_class($this)."::insert_const constant '".$name."' already exists", LOG_WARNING);
1655
                }
1656
            }
1657
            else
1658
            {
1659
                $err++;
1660
            }
1661
        }
1662
1663
        return $err;
1664
    }
1665
1666
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1667
    /**
1668
     * Removes constants tagged 'deleteonunactive'
1669
     *
1670
     * @return int <0 if KO, 0 if OK
1671
     */
1672
    public function delete_const()
1673
    {
1674
        // phpcs:enable
1675
        global $conf;
1676
1677
        $err=0;
1678
1679
        if (empty($this->const)) { return 0;
1680
        }
1681
1682
        foreach ($this->const as $key => $value)
1683
        {
1684
            $name      = $this->const[$key][0];
1685
            $deleteonunactive = (! empty($this->const[$key][6]))?1:0;
1686
1687
            if ($deleteonunactive) {
1688
                $sql = "DELETE FROM ".MAIN_DB_PREFIX."const";
1689
                $sql.= " WHERE ".$this->db->decrypt('name')." = '".$name."'";
1690
                $sql.= " AND entity in (0, ".$conf->entity.")";
1691
                dol_syslog(get_class($this)."::delete_const", LOG_DEBUG);
1692
                if (! $this->db->query($sql)) {
1693
                    $this->error=$this->db->lasterror();
1694
                    $err++;
1695
                }
1696
            }
1697
        }
1698
1699
        return $err;
1700
    }
1701
1702
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1703
    /**
1704
     * Adds access rights
1705
     *
1706
     * @param  int $reinitadminperms If 1, we also grant them to all admin users
1707
     * @param  int $force_entity     Force current entity
1708
     * @param  int $notrigger        1=Does not execute triggers, 0= execute triggers
1709
     * @return int                     Error count (0 if OK)
1710
     */
1711
    public function insert_permissions($reinitadminperms = 0, $force_entity = null, $notrigger = 0)
1712
    {
1713
        // phpcs:enable
1714
        global $conf,$user;
1715
1716
        $err=0;
1717
        $entity=(! empty($force_entity) ? $force_entity : $conf->entity);
1718
1719
        dol_syslog(get_class($this)."::insert_permissions", LOG_DEBUG);
1720
1721
        // Test if module is activated
1722
        $sql_del = "SELECT ".$this->db->decrypt('value')." as value";
1723
        $sql_del.= " FROM ".MAIN_DB_PREFIX."const";
1724
        $sql_del.= " WHERE ".$this->db->decrypt('name')." = '".$this->db->escape($this->const_name)."'";
1725
        $sql_del.= " AND entity IN (0,".$entity.")";
1726
1727
        $resql=$this->db->query($sql_del);
1728
1729
        if ($resql) {
1730
            $obj=$this->db->fetch_object($resql);
1731
            if ($obj !== null && ! empty($obj->value) && ! empty($this->rights)) {
1732
                // If the module is active
1733
                foreach ($this->rights as $key => $value)
1734
                {
1735
                    $r_id       = $this->rights[$key][0];
1736
                    $r_desc     = $this->rights[$key][1];
1737
                    $r_type     = isset($this->rights[$key][2])?$this->rights[$key][2]:'';
1738
                    $r_def      = $this->rights[$key][3];
1739
                    $r_perms    = $this->rights[$key][4];
1740
                    $r_subperms = isset($this->rights[$key][5])?$this->rights[$key][5]:'';
1741
                    $r_modul = empty($this->rights_class)?strtolower($this->name):$this->rights_class;
1742
1743
                    if (empty($r_type)) { $r_type='w'; }
1744
                    if (empty($r_def)) { $r_def=0; }
1745
1746
                    // Search if perm already present
1747
                    $sql = "SELECT count(*) as nb FROM ".MAIN_DB_PREFIX."rights_def";
1748
                    $sql.= " WHERE id = ".$r_id." AND entity = ".$entity;
1749
1750
                    $resqlselect=$this->db->query($sql);
1751
                    if ($resqlselect) {
1752
                        $objcount = $this->db->fetch_object($resqlselect);
1753
                        if ($objcount && $objcount->nb == 0) {
1754
                            if (dol_strlen($r_perms) ) {
1755
                                if (dol_strlen($r_subperms) ) {
1756
                                    $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def";
1757
                                    $sql.= " (id, entity, libelle, module, type, bydefault, perms, subperms)";
1758
                                    $sql.= " VALUES ";
1759
                                    $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."','".$r_subperms."')";
1760
                                }
1761
                                else
1762
                                   {
1763
                                    $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def";
1764
                                    $sql.= " (id, entity, libelle, module, type, bydefault, perms)";
1765
                                    $sql.= " VALUES ";
1766
                                    $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."')";
1767
                                }
1768
                            }
1769
                            else
1770
                            {
1771
                                 $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def ";
1772
                                 $sql .= " (id, entity, libelle, module, type, bydefault)";
1773
                                 $sql .= " VALUES ";
1774
                                 $sql .= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.")";
1775
                            }
1776
1777
                            $resqlinsert=$this->db->query($sql, 1);
1778
1779
                            if (! $resqlinsert) {
1780
                                if ($this->db->errno() != "DB_ERROR_RECORD_ALREADY_EXISTS") {
1781
                                    $this->error=$this->db->lasterror();
1782
                                    $err++;
1783
                                    break;
1784
                                }
1785
                                else { dol_syslog(get_class($this)."::insert_permissions record already exists", LOG_INFO);
1786
                                }
1787
                            }
1788
1789
                            $this->db->free($resqlinsert);
1790
                        }
1791
1792
                        $this->db->free($resqlselect);
1793
                    }
1794
1795
                    // If we want to init permissions on admin users
1796
                    if ($reinitadminperms) {
1797
                        if (! class_exists('User')) {
1798
                            include_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
1799
                        }
1800
                        $sql="SELECT rowid FROM ".MAIN_DB_PREFIX."user WHERE admin = 1";
1801
                        dol_syslog(get_class($this)."::insert_permissions Search all admin users", LOG_DEBUG);
1802
                        $resqlseladmin=$this->db->query($sql, 1);
1803
                        if ($resqlseladmin) {
1804
                            $num=$this->db->num_rows($resqlseladmin);
1805
                            $i=0;
1806
                            while ($i < $num)
1807
                            {
1808
                                  $obj2=$this->db->fetch_object($resqlseladmin);
1809
                                  dol_syslog(get_class($this)."::insert_permissions Add permission to user id=".$obj2->rowid);
1810
1811
                                  $tmpuser=new User($this->db);
1812
                                  $result = $tmpuser->fetch($obj2->rowid);
1813
                                if ($result > 0) {
1814
                                    $tmpuser->addrights($r_id, '', '', 0, 1);
1815
                                }
1816
                                else
1817
                                 {
1818
                                    dol_syslog(get_class($this)."::insert_permissions Failed to add the permission to user because fetch return an error", LOG_ERR);
1819
                                }
1820
                                 $i++;
1821
                            }
1822
                        }
1823
                        else
1824
                        {
1825
                            dol_print_error($this->db);
1826
                        }
1827
                    }
1828
                }
1829
1830
                if ($reinitadminperms && ! empty($user->admin))  // Reload permission for current user if defined
1831
                {
1832
                    // We reload permissions
1833
                    $user->clearrights();
1834
                    $user->getrights();
1835
                }
1836
            }
1837
            $this->db->free($resql);
1838
        }
1839
        else
1840
        {
1841
            $this->error=$this->db->lasterror();
1842
            $err++;
1843
        }
1844
1845
        return $err;
1846
    }
1847
1848
1849
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1850
    /**
1851
     * Removes access rights
1852
     *
1853
     * @return int                     Error count (0 if OK)
1854
     */
1855
    public function delete_permissions()
1856
    {
1857
        // phpcs:enable
1858
        global $conf;
1859
1860
        $err=0;
1861
1862
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."rights_def";
1863
        $sql.= " WHERE module = '".$this->db->escape(empty($this->rights_class)?strtolower($this->name):$this->rights_class)."'";
1864
        $sql.= " AND entity = ".$conf->entity;
1865
        dol_syslog(get_class($this)."::delete_permissions", LOG_DEBUG);
1866
        if (! $this->db->query($sql)) {
1867
            $this->error=$this->db->lasterror();
1868
            $err++;
1869
        }
1870
1871
        return $err;
1872
    }
1873
1874
1875
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1876
    /**
1877
     * Adds menu entries
1878
     *
1879
     * @return int     Error count (0 if OK)
1880
     */
1881
    public function insert_menus()
1882
    {
1883
        // phpcs:enable
1884
        global $user;
1885
1886
        if (! is_array($this->menu) || empty($this->menu)) { return 0;
1 ignored issue
show
introduced by
The condition is_array($this->menu) is always true.
Loading history...
1887
        }
1888
1889
        include_once DOL_DOCUMENT_ROOT . '/core/class/menubase.class.php';
1890
1891
        dol_syslog(get_class($this)."::insert_menus", LOG_DEBUG);
1892
1893
        $err=0;
1894
1895
        $this->db->begin();
1896
1897
        foreach ($this->menu as $key => $value)
1898
        {
1899
            $menu = new Menubase($this->db);
1900
            $menu->menu_handler='all';
1901
1902
            //$menu->module=strtolower($this->name);    TODO When right_class will be same than module name
1903
            $menu->module=empty($this->rights_class)?strtolower($this->name):$this->rights_class;
1904
1905
            if (! $this->menu[$key]['fk_menu']) {
1906
                $menu->fk_menu=0;
1907
            }
1908
            else
1909
            {
1910
                $foundparent=0;
1911
                $fk_parent=$this->menu[$key]['fk_menu'];
1912
                if (preg_match('/^r=/', $fk_parent))    // old deprecated method
1913
                {
1914
                    $fk_parent=str_replace('r=', '', $fk_parent);
1915
                    if (isset($this->menu[$fk_parent]['rowid'])) {
1916
                        $menu->fk_menu=$this->menu[$fk_parent]['rowid'];
1917
                        $foundparent=1;
1918
                    }
1919
                }
1920
                elseif (preg_match('/^fk_mainmenu=([a-zA-Z0-9_]+),fk_leftmenu=([a-zA-Z0-9_]+)$/', $fk_parent, $reg)) {
1921
                    $menu->fk_menu=-1;
1922
                    $menu->fk_mainmenu=$reg[1];
1923
                    $menu->fk_leftmenu=$reg[2];
1924
                    $foundparent=1;
1925
                }
1926
                elseif (preg_match('/^fk_mainmenu=([a-zA-Z0-9_]+)$/', $fk_parent, $reg)) {
1927
                    $menu->fk_menu=-1;
1928
                    $menu->fk_mainmenu=$reg[1];
1929
                    $menu->fk_leftmenu='';
1930
                    $foundparent=1;
1931
                }
1932
                if (! $foundparent) {
1933
                    $this->error="ErrorBadDefinitionOfMenuArrayInModuleDescriptor";
1934
                    dol_syslog(get_class($this)."::insert_menus ".$this->error." ".$this->menu[$key]['fk_menu'], LOG_ERR);
1935
                    $err++;
1936
                }
1937
            }
1938
            $menu->type=$this->menu[$key]['type'];
1939
            $menu->mainmenu=isset($this->menu[$key]['mainmenu'])?$this->menu[$key]['mainmenu']:(isset($menu->fk_mainmenu)?$menu->fk_mainmenu:'');
1940
            $menu->leftmenu=isset($this->menu[$key]['leftmenu'])?$this->menu[$key]['leftmenu']:'';
1941
            $menu->titre=$this->menu[$key]['titre'];	// deprecated
1942
            $menu->title=$this->menu[$key]['titre'];
1943
            $menu->url=$this->menu[$key]['url'];
1944
            $menu->langs=$this->menu[$key]['langs'];
1945
            $menu->position=$this->menu[$key]['position'];
1946
            $menu->perms=$this->menu[$key]['perms'];
1947
            $menu->target=isset($this->menu[$key]['target'])?$this->menu[$key]['target']:'';
1948
            $menu->user=$this->menu[$key]['user'];
1949
            $menu->enabled=isset($this->menu[$key]['enabled'])?$this->menu[$key]['enabled']:0;
1950
            $menu->position=$this->menu[$key]['position'];
1951
1952
            if (! $err) {
1953
                $result=$menu->create($user);    // Save menu entry into table llx_menu
1954
                if ($result > 0) {
1955
                    $this->menu[$key]['rowid']=$result;
1956
                }
1957
                else
1958
                {
1959
                    $this->error=$menu->error;
1960
                    dol_syslog(get_class($this).'::insert_menus result='.$result." ".$this->error, LOG_ERR);
1961
                    $err++;
1962
                    break;
1963
                }
1964
            }
1965
        }
1966
1967
        if (! $err) {
1968
            $this->db->commit();
1969
        }
1970
        else
1971
        {
1972
            dol_syslog(get_class($this)."::insert_menus ".$this->error, LOG_ERR);
1973
            $this->db->rollback();
1974
        }
1975
1976
        return $err;
1977
    }
1978
1979
1980
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1981
    /**
1982
     * Removes menu entries
1983
     *
1984
     * @return int Error count (0 if OK)
1985
     */
1986
    public function delete_menus()
1987
    {
1988
        // phpcs:enable
1989
        global $conf;
1990
1991
        $err=0;
1992
1993
        //$module=strtolower($this->name);        TODO When right_class will be same than module name
1994
        $module=empty($this->rights_class)?strtolower($this->name):$this->rights_class;
1995
1996
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."menu";
1997
        $sql.= " WHERE module = '".$this->db->escape($module)."'";
1998
        $sql.= " AND entity = ".$conf->entity;
1999
2000
        dol_syslog(get_class($this)."::delete_menus", LOG_DEBUG);
2001
        $resql=$this->db->query($sql);
2002
        if (! $resql) {
2003
            $this->error=$this->db->lasterror();
2004
            $err++;
2005
        }
2006
2007
        return $err;
2008
    }
2009
2010
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2011
    /**
2012
     * Creates directories
2013
     *
2014
     * @return int Error count (0 if OK)
2015
     */
2016
    public function create_dirs()
2017
    {
2018
        // phpcs:enable
2019
        global $langs, $conf;
2020
2021
        $err=0;
2022
2023
        if (isset($this->dirs) && is_array($this->dirs)) {
2024
            foreach ($this->dirs as $key => $value)
2025
            {
2026
                $addtodatabase=0;
2027
2028
                if (! is_array($value)) { $dir=$value;    // Default simple mode
2029
                } else {
2030
                    $constname = $this->const_name."_DIR_";
2031
                    $dir       = $this->dirs[$key][1];
2032
                    $addtodatabase = empty($this->dirs[$key][2])?'':$this->dirs[$key][2]; // Create constante in llx_const
2033
                    $subname   = empty($this->dirs[$key][3])?'':strtoupper($this->dirs[$key][3]); // Add submodule name (ex: $conf->module->submodule->dir_output)
2034
                    $forcename = empty($this->dirs[$key][4])?'':strtoupper($this->dirs[$key][4]); // Change the module name if different
2035
2036
                    if (! empty($forcename)) { $constname = 'MAIN_MODULE_'.$forcename."_DIR_";
2037
                    }
2038
                    if (! empty($subname)) {   $constname = $constname.$subname."_";
2039
                    }
2040
2041
                    $name = $constname.strtoupper($this->dirs[$key][0]);
2042
                }
2043
2044
                // Define directory full path ($dir must start with "/")
2045
                if (empty($conf->global->MAIN_MODULE_MULTICOMPANY) || $conf->entity == 1) { $fulldir = DOL_DATA_ROOT.$dir;
2046
                } else { $fulldir = DOL_DATA_ROOT."/".$conf->entity.$dir;
2047
                }
2048
                // Create dir if it does not exists
2049
                if (! empty($fulldir) && ! file_exists($fulldir)) {
2050
                    if (dol_mkdir($fulldir, DOL_DATA_ROOT) < 0) {
2051
                         $this->error = $langs->trans("ErrorCanNotCreateDir", $fulldir);
2052
                         dol_syslog(get_class($this)."::_init ".$this->error, LOG_ERR);
2053
                         $err++;
2054
                    }
2055
                }
2056
2057
                // Define the constant in database if requested (not the default mode)
2058
                if (! empty($addtodatabase)) {
2059
                    $result = $this->insert_dirs($name, $dir);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $name does not seem to be defined for all execution paths leading up to this point.
Loading history...
2060
                    if ($result) { $err++;
2061
                    }
2062
                }
2063
            }
2064
        }
2065
2066
        return $err;
2067
    }
2068
2069
2070
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2071
    /**
2072
     * Adds directories definitions
2073
     *
2074
     * @param string $name Name
2075
     * @param string $dir  Directory
2076
     *
2077
     * @return int             Error count (0 if OK)
2078
     */
2079
    public function insert_dirs($name, $dir)
2080
    {
2081
        // phpcs:enable
2082
        global $conf;
2083
2084
        $err=0;
2085
2086
        $sql = "SELECT count(*)";
2087
        $sql.= " FROM ".MAIN_DB_PREFIX."const";
2088
        $sql.= " WHERE ".$this->db->decrypt('name')." = '".$name."'";
2089
        $sql.= " AND entity = ".$conf->entity;
2090
2091
        dol_syslog(get_class($this)."::insert_dirs", LOG_DEBUG);
2092
        $result=$this->db->query($sql);
2093
        if ($result) {
2094
            $row = $this->db->fetch_row($result);
2095
2096
            if ($row[0] == 0) {
2097
                $sql = "INSERT INTO ".MAIN_DB_PREFIX."const (name,type,value,note,visible,entity)";
2098
                $sql.= " VALUES (".$this->db->encrypt($name, 1).",'chaine',".$this->db->encrypt($dir, 1).",'Directory for module ".$this->name."','0',".$conf->entity.")";
2099
2100
                dol_syslog(get_class($this)."::insert_dirs", LOG_DEBUG);
2101
                $this->db->query($sql);
2102
            }
2103
        }
2104
        else
2105
        {
2106
            $this->error=$this->db->lasterror();
2107
            $err++;
2108
        }
2109
2110
        return $err;
2111
    }
2112
2113
2114
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2115
    /**
2116
     * Removes directories
2117
     *
2118
     * @return int Error count (0 if OK)
2119
     */
2120
    public function delete_dirs()
2121
    {
2122
        // phpcs:enable
2123
        global $conf;
2124
2125
        $err=0;
2126
2127
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."const";
2128
        $sql.= " WHERE ".$this->db->decrypt('name')." LIKE '".$this->db->escape($this->const_name)."_DIR_%'";
2129
        $sql.= " AND entity = ".$conf->entity;
2130
2131
        dol_syslog(get_class($this)."::delete_dirs", LOG_DEBUG);
2132
        if (! $this->db->query($sql)) {
2133
            $this->error=$this->db->lasterror();
2134
            $err++;
2135
        }
2136
2137
        return $err;
2138
    }
2139
2140
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2141
    /**
2142
     * Adds generic parts
2143
     *
2144
     * @return int Error count (0 if OK)
2145
     */
2146
    public function insert_module_parts()
2147
    {
2148
        // phpcs:enable
2149
        global $conf;
2150
2151
        $error=0;
2152
2153
        if (is_array($this->module_parts) && ! empty($this->module_parts)) {
2154
            foreach($this->module_parts as $key => $value)
2155
            {
2156
                if (is_array($value) && count($value) == 0) { continue;    // Discard empty arrays
2157
                }
2158
2159
                $entity=$conf->entity; // Reset the current entity
2160
                $newvalue = $value;
2161
2162
                // Serialize array parameters
2163
                if (is_array($value)) {
2164
                    // Can defined other parameters
2165
                    // Example when $key='hooks', then $value is an array('data'=>array('hookcontext1','hookcontext2'), 'entity'=>X)
2166
                    if (isset($value['data']) && is_array($value['data'])) {
2167
                        $newvalue = json_encode($value['data']);
2168
                        if (isset($value['entity'])) { $entity = $value['entity'];
2169
                        }
2170
                    }
2171
                    elseif (isset($value['data']) && !is_array($value['data'])) {
2172
                        $newvalue = $value['data'];
2173
                        if (isset($value['entity'])) { $entity = $value['entity'];
2174
                        }
2175
                    }
2176
                    else    // when hook is declared with syntax 'hook'=>array('hookcontext1','hookcontext2',...)
2177
                    {
2178
                        $newvalue = json_encode($value);
2179
                    }
2180
                }
2181
2182
                $sql = "INSERT INTO ".MAIN_DB_PREFIX."const (";
2183
                $sql.= "name";
2184
                $sql.= ", type";
2185
                $sql.= ", value";
2186
                $sql.= ", note";
2187
                $sql.= ", visible";
2188
                $sql.= ", entity";
2189
                $sql.= ")";
2190
                $sql.= " VALUES (";
2191
                $sql.= $this->db->encrypt($this->const_name."_".strtoupper($key), 1);
2192
                $sql.= ", 'chaine'";
2193
                $sql.= ", ".$this->db->encrypt($newvalue, 1);
2194
                $sql.= ", null";
2195
                $sql.= ", '0'";
2196
                $sql.= ", ".$entity;
2197
                $sql.= ")";
2198
2199
                dol_syslog(get_class($this)."::insert_module_parts for key=".$this->const_name."_".strtoupper($key), LOG_DEBUG);
2200
2201
                $resql=$this->db->query($sql, 1);
2202
                if (! $resql) {
2203
                    if ($this->db->lasterrno() != 'DB_ERROR_RECORD_ALREADY_EXISTS') {
2204
                         $error++;
2205
                         $this->error=$this->db->lasterror();
2206
                    }
2207
                    else
2208
                    {
2209
                         dol_syslog(get_class($this)."::insert_module_parts for ".$this->const_name."_".strtoupper($key)." Record already exists.", LOG_WARNING);
2210
                    }
2211
                }
2212
            }
2213
        }
2214
        return $error;
2215
    }
2216
2217
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2218
    /**
2219
     * Removes generic parts
2220
     *
2221
     * @return int Error count (0 if OK)
2222
     */
2223
    public function delete_module_parts()
2224
    {
2225
        // phpcs:enable
2226
        global $conf;
2227
2228
        $err=0;
2229
        $entity=$conf->entity;
2230
2231
        if (is_array($this->module_parts) && ! empty($this->module_parts)) {
2232
            foreach($this->module_parts as $key => $value)
2233
            {
2234
                // If entity is defined
2235
                if (is_array($value) && isset($value['entity'])) { $entity = $value['entity'];
2236
                }
2237
2238
                $sql = "DELETE FROM ".MAIN_DB_PREFIX."const";
2239
                $sql.= " WHERE ".$this->db->decrypt('name')." LIKE '".$this->db->escape($this->const_name)."_".strtoupper($key)."'";
2240
                $sql.= " AND entity = ".$entity;
2241
2242
                dol_syslog(get_class($this)."::delete_const_".$key."", LOG_DEBUG);
2243
                if (! $this->db->query($sql)) {
2244
                    $this->error=$this->db->lasterror();
2245
                    $err++;
2246
                }
2247
            }
2248
        }
2249
        return $err;
2250
    }
2251
2252
    /**
2253
     * Function called when module is enabled.
2254
     * The init function adds tabs, constants, boxes, permissions and menus (defined in constructor) into Dolibarr database.
2255
     * It also creates data directories
2256
     *
2257
     * @param  string $options Options when enabling module ('', 'newboxdefonly', 'noboxes')
2258
     *                         'noboxes' = Do not insert boxes 'newboxdefonly' = For boxes,
2259
     *                         insert def of boxes only and not boxes activation
2260
     * @return int                1 if OK, 0 if KO
2261
     */
2262
    public function init($options = '')
2263
    {
2264
        return $this->_init(array(), $options);
2265
    }
2266
2267
    /**
2268
     * Function called when module is disabled.
2269
     * The remove function removes tabs, constants, boxes, permissions and menus from Dolibarr database.
2270
     * Data directories are not deleted
2271
     *
2272
     * @param  string $options Options when enabling module ('', 'noboxes')
2273
     * @return int                     1 if OK, 0 if KO
2274
     */
2275
    public function remove($options = '')
2276
    {
2277
        return $this->_remove(array(), $options);
2278
    }
2279
}
2280