Passed
Push — master ( 4a7f51...9b2b82 )
by Julito
10:17
created

AppPlugin::load_plugin_lang_variables()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 10
nop 1
dl 0
loc 27
rs 8.8333
c 0
b 0
f 0
1
<?php
2
/* See license terms in /license.txt */
3
4
use ChamiloSession as Session;
5
6
/**
7
 * Class AppPlugin.
8
 */
9
class AppPlugin
10
{
11
    public $plugin_regions = [
12
        'main_top',
13
        'main_bottom',
14
        'login_top',
15
        'login_bottom',
16
        'menu_top',
17
        'menu_bottom',
18
        'content_top',
19
        'content_bottom',
20
        'header_main',
21
        'header_center',
22
        'header_left',
23
        'header_right',
24
        'pre_footer',
25
        'footer_left',
26
        'footer_center',
27
        'footer_right',
28
        'menu_administrator',
29
        'course_tool_plugin',
30
    ];
31
32
    public $installedPluginListName = [];
33
    public $installedPluginListObject = [];
34
35
    /**
36
     * Constructor.
37
     */
38
    public function __construct()
39
    {
40
    }
41
42
    /**
43
     * Read plugin from path.
44
     *
45
     * @return array
46
     */
47
    public function read_plugins_from_path()
48
    {
49
        /* We scan the plugin directory. Each folder is a potential plugin. */
50
        $pluginPath = api_get_path(SYS_PLUGIN_PATH);
51
        $plugins = [];
52
        $handle = @opendir($pluginPath);
53
        while (false !== ($file = readdir($handle))) {
0 ignored issues
show
Bug introduced by
It seems like $handle can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

53
        while (false !== ($file = readdir(/** @scrutinizer ignore-type */ $handle))) {
Loading history...
54
            if ($file != '.' && $file != '..' && is_dir(api_get_path(SYS_PLUGIN_PATH).$file)) {
55
                $plugins[] = $file;
56
            }
57
        }
58
        @closedir($handle);
0 ignored issues
show
Bug introduced by
Are you sure the usage of closedir($handle) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
It seems like $handle can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

58
        @closedir(/** @scrutinizer ignore-type */ $handle);
Loading history...
Security Best Practice introduced by
It seems like you do not handle an error condition for closedir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

58
        /** @scrutinizer ignore-unhandled */ @closedir($handle);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
59
        sort($plugins);
60
61
        return $plugins;
62
    }
63
64
    /**
65
     * @return array
66
     */
67
    public function get_installed_plugins_by_region()
68
    {
69
        $plugins = [];
70
        /* We retrieve all the active plugins. */
71
        $result = api_get_settings('Plugins');
72
        if (!empty($result)) {
73
            foreach ($result as $row) {
74
                $plugins[$row['variable']][] = $row['selected_value'];
75
            }
76
        }
77
78
        return $plugins;
79
    }
80
81
    /**
82
     * @return array
83
     */
84
    public function getInstalledPluginListName()
85
    {
86
        if (empty($this->installedPluginListName)) {
87
            $this->installedPluginListName = $this->get_installed_plugins();
88
        }
89
90
        return $this->installedPluginListName;
91
    }
92
93
    /**
94
     * @return array List of Plugin
95
     */
96
    public function getInstalledPluginListObject()
97
    {
98
        if (empty($this->installedPluginListObject)) {
99
            $this->setInstalledPluginListObject();
100
        }
101
102
        return $this->installedPluginListObject;
103
    }
104
105
    public function setInstalledPluginListObject()
106
    {
107
        $pluginListName = $this->getInstalledPluginListName();
108
        $pluginList = [];
109
        if (!empty($pluginListName)) {
110
            foreach ($pluginListName as $pluginName) {
111
                $pluginInfo = $this->getPluginInfo($pluginName, true);
112
                if (isset($pluginInfo['plugin_class'])) {
113
                    $pluginList[] = $pluginInfo['plugin_class']::create();
114
                }
115
            }
116
        }
117
        $this->installedPluginListObject = $pluginList;
118
    }
119
120
    /**
121
     * @return array
122
     */
123
    public function get_installed_plugins()
124
    {
125
        $installedPlugins = [];
126
        $plugins = api_get_settings_params(
127
            [
128
                'variable = ? AND selected_value = ? AND category = ? ' => ['status', 'installed', 'Plugins'],
129
            ]
130
        );
131
132
        if (!empty($plugins)) {
133
            foreach ($plugins as $row) {
134
                $installedPlugins[$row['subkey']] = true;
135
            }
136
            $installedPlugins = array_keys($installedPlugins);
137
        }
138
139
        return $installedPlugins;
140
    }
141
142
    /**
143
     * @param string $pluginName
144
     * @param int    $urlId
145
     */
146
    public function install($pluginName, $urlId = null)
147
    {
148
        if (empty($urlId)) {
149
            $urlId = api_get_current_access_url_id();
150
        } else {
151
            $urlId = intval($urlId);
152
        }
153
154
        api_add_setting(
155
            'installed',
156
            'status',
157
            $pluginName,
158
            'setting',
159
            'Plugins',
160
            $pluginName,
161
            '',
162
            '',
163
            '',
164
            $urlId,
165
            1
166
        );
167
168
        $pluginPath = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/install.php';
169
170
        if (is_file($pluginPath) && is_readable($pluginPath)) {
171
            // Execute the install procedure.
172
173
            require $pluginPath;
174
        }
175
    }
176
177
    /**
178
     * @param string $pluginName
179
     * @param int    $urlId
180
     */
181
    public function uninstall($pluginName, $urlId = null)
182
    {
183
        if (empty($urlId)) {
184
            $urlId = api_get_current_access_url_id();
185
        } else {
186
            $urlId = intval($urlId);
187
        }
188
189
        // First call the custom uninstall to allow full access to global settings
190
        $pluginPath = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/uninstall.php';
191
        if (is_file($pluginPath) && is_readable($pluginPath)) {
192
            // Execute the uninstall procedure.
193
194
            require $pluginPath;
195
        }
196
        // Second remove all remaining global settings
197
        api_delete_settings_params(
198
            ['category = ? AND access_url = ? AND subkey = ? ' => ['Plugins', $urlId, $pluginName]]
199
        );
200
    }
201
202
    /**
203
     * @param string $pluginName
204
     *
205
     * @return array
206
     */
207
    public function get_areas_by_plugin($pluginName)
208
    {
209
        $result = api_get_settings('Plugins');
210
        $areas = [];
211
        foreach ($result as $row) {
212
            if ($pluginName == $row['selected_value']) {
213
                $areas[] = $row['variable'];
214
            }
215
        }
216
217
        return $areas;
218
    }
219
220
    /**
221
     * @param string $location
222
     *
223
     * @return bool
224
     */
225
    public function is_valid_plugin_location($location)
226
    {
227
        return in_array($location, $this->plugin_list);
0 ignored issues
show
Bug introduced by
The property plugin_list does not exist on AppPlugin. Did you mean plugin_regions?
Loading history...
228
    }
229
230
    /**
231
     * @param string $pluginName
232
     *
233
     * @return bool
234
     */
235
    public function is_valid_plugin($pluginName)
236
    {
237
        if (is_dir(api_get_path(SYS_PLUGIN_PATH).$pluginName)) {
238
            if (is_file(api_get_path(SYS_PLUGIN_PATH).$pluginName.'/index.php')) {
239
                return true;
240
            }
241
        }
242
243
        return false;
244
    }
245
246
    /**
247
     * @return array
248
     */
249
    public function getPluginRegions()
250
    {
251
        sort($this->plugin_regions);
252
253
        return $this->plugin_regions;
254
    }
255
256
    /**
257
     * @param array            $pluginRegionList
258
     * @param string           $region
259
     * @param Twig_Environment $template
260
     * @param bool             $forced
261
     *
262
     * @return null|string
263
     */
264
    public function loadRegion($pluginName, $region, $template, $forced = false)
265
    {
266
        ob_start();
267
        $this->getAllPluginContentsByRegion($pluginName, $region, $template, $forced);
268
        $content = ob_get_contents();
269
        ob_end_clean();
270
271
        return $content;
272
    }
273
274
    /**
275
     * Loads the translation files inside a plugin if exists.
276
     * It loads by default english see the hello world plugin.
277
     *
278
     * @param string $plugin_name
279
     *
280
     * @todo add caching
281
     */
282
    public function load_plugin_lang_variables($plugin_name)
283
    {
284
        $language_interface = api_get_interface_language();
285
        $root = api_get_path(SYS_PLUGIN_PATH);
286
        $strings = null;
287
288
        // 1. Loading english if exists
289
        $english_path = $root.$plugin_name.'/lang/english.php';
290
        if (is_readable($english_path)) {
291
            include $english_path;
292
293
            foreach ($strings as $key => $string) {
0 ignored issues
show
Bug introduced by
The expression $strings of type null is not traversable.
Loading history...
294
                $GLOBALS[$key] = $string;
295
            }
296
        }
297
298
        // 2. Loading the system language
299
        if ($language_interface != 'english') {
300
            $path = $root.$plugin_name."/lang/$language_interface.php";
301
            if (is_readable($path)) {
302
                include $path;
303
                if (!empty($strings)) {
304
                    foreach ($strings as $key => $string) {
305
                        $GLOBALS[$key] = $string;
306
                    }
307
                }
308
            } else {
309
                /*$interfaceLanguageId = api_get_language_id($language_interface);
310
                $interfaceLanguageInfo = api_get_language_info($interfaceLanguageId);
311
                $languageParentId = intval($interfaceLanguageInfo['parent_id']);
312
313
                if ($languageParentId > 0) {
314
                    $languageParentInfo = api_get_language_info($languageParentId);
315
                    $languageParentFolder = $languageParentInfo['dokeos_folder'];
316
317
                    $parentPath = "{$root}{$plugin_name}/lang/{$languageParentFolder}.php";
318
                    if (is_readable($parentPath)) {
319
                        include $parentPath;
320
                        if (!empty($strings)) {
321
                            foreach ($strings as $key => $string) {
322
                                $this->strings[$key] = $string;
323
                            }
324
                        }
325
                    }
326
                }*/
327
            }
328
        }
329
    }
330
331
    /**
332
     * @param array    $_plugins
333
     * @param string   $region
334
     * @param Twig_Environment $template
335
     * @param bool     $forced
336
     *
337
     * @return bool
338
     *
339
     * @todo improve this function
340
     */
341
    public function getAllPluginContentsByRegion($plugin_name, $region, $template, $forced = false)
342
    {
343
        // The plugin_info variable is available inside the plugin index
344
        $plugin_info = $this->getPluginInfo($plugin_name, $forced);
345
346
        // We also know where the plugin is
347
        $plugin_info['current_region'] = $region;
348
349
        // Loading the plugin/XXX/index.php file
350
        $plugin_file = api_get_path(SYS_PLUGIN_PATH)."$plugin_name/index.php";
351
352
        if (file_exists($plugin_file)) {
353
            //Loading the lang variables of the plugin if exists
354
            self::load_plugin_lang_variables($plugin_name);
0 ignored issues
show
Bug Best Practice introduced by
The method AppPlugin::load_plugin_lang_variables() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

354
            self::/** @scrutinizer ignore-call */ 
355
                  load_plugin_lang_variables($plugin_name);
Loading history...
355
356
            // Printing the plugin index.php file
357
            require $plugin_file;
358
359
            // If the variable $_template is set we assign those values to be accessible in Twig
360
            if (isset($_template)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $_template seems to never exist and therefore isset should always be false.
Loading history...
361
                $_template['plugin_info'] = $plugin_info;
362
            } else {
363
                $_template = [];
364
                $_template['plugin_info'] = $plugin_info;
365
            }
366
367
            // Setting the plugin info available in the template if exists.
368
            //$template->addGlobal($plugin_name, $_template);
369
370
            // Loading the Twig template plugin files if exists
371
            $templateList = [];
372
            if (isset($plugin_info) && isset($plugin_info['templates'])) {
373
                $templateList = $plugin_info['templates'];
374
            }
375
376
            if (!empty($templateList)) {
377
                foreach ($templateList as $pluginTemplate) {
378
                    if (!empty($pluginTemplate)) {
379
                        $templatePluginFile = "$plugin_name/$pluginTemplate"; // for twig
380
                        //$template->render($templatePluginFile, []);
381
                    }
382
                }
383
            }
384
        }
385
386
        return true;
387
    }
388
389
    /**
390
     * Loads plugin info.
391
     *
392
     * @staticvar array $plugin_data
393
     *
394
     * @param string $pluginName
395
     * @param bool   $forced      load from DB or from the static array
396
     *
397
     * @return array
398
     *
399
     * @todo filter setting_form
400
     */
401
    public function getPluginInfo($pluginName, $forced = false)
402
    {
403
        //$pluginData = Session::read('plugin_data');
404
        if (0) {
405
        //if (isset($pluginData[$pluginName]) && $forced == false) {
406
            return $pluginData[$pluginName];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pluginData seems to be never defined.
Loading history...
407
        } else {
408
            $plugin_file = api_get_path(SYS_PLUGIN_PATH)."$pluginName/plugin.php";
409
410
            $plugin_info = [];
411
            if (file_exists($plugin_file)) {
412
                require $plugin_file;
413
            }
414
415
            // @todo check if settings are already added
416
            // Extra options
417
            $plugin_settings = api_get_settings_params(
418
                [
419
                    'subkey = ? AND category = ? AND type = ? AND access_url = ?' => [
420
                        $pluginName,
421
                        'Plugins',
422
                        'setting',
423
                        api_get_current_access_url_id(),
424
                    ],
425
                ]
426
            );
427
428
            $settings_filtered = [];
429
            foreach ($plugin_settings as $item) {
430
                if (!empty($item['selected_value'])) {
431
                    //if (unserialize($item['selected_value']) !== false) {
432
                        //$item['selected_value'] = unserialize($item['selected_value']);
433
                    //}
434
                }
435
                $settings_filtered[$item['variable']] = $item['selected_value'];
436
            }
437
438
            $plugin_info['settings'] = $settings_filtered;
439
            $pluginData[$pluginName] = $plugin_info;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$pluginData was never initialized. Although not strictly required by PHP, it is generally a good practice to add $pluginData = array(); before regardless.
Loading history...
440
            //Session::write('plugin_data', $pluginData);
441
442
            return $plugin_info;
443
        }
444
    }
445
446
    /**
447
     * Get the template list.
448
     *
449
     * @param string $pluginName
450
     *
451
     * @return bool
452
     */
453
    public function get_templates_list($pluginName)
454
    {
455
        $plugin_info = $this->getPluginInfo($pluginName);
456
        if (isset($plugin_info) && isset($plugin_info['templates'])) {
457
            return $plugin_info['templates'];
458
        } else {
459
            return false;
460
        }
461
    }
462
463
    /**
464
     * Remove all regions of an specific plugin.
465
     *
466
     * @param string $plugin
467
     */
468
    public function removeAllRegions($plugin)
469
    {
470
        if (!empty($plugin)) {
471
            api_delete_settings_params(
472
                [
473
                    'category = ? AND type = ? AND access_url = ? AND subkey = ? ' => [
474
                        'Plugins',
475
                        'region',
476
                        api_get_current_access_url_id(),
477
                        $plugin,
478
                    ],
479
                ]
480
            );
481
        }
482
    }
483
484
    /**
485
     * Add a plugin to a region.
486
     *
487
     * @param string $plugin
488
     * @param string $region
489
     */
490
    public function add_to_region($plugin, $region)
491
    {
492
        api_add_setting(
493
            $plugin,
494
            $region,
495
            $plugin,
496
            'region',
497
            'Plugins',
498
            $plugin,
499
            '',
500
            '',
501
            '',
502
            api_get_current_access_url_id(),
503
            1
504
        );
505
    }
506
507
    /**
508
     * @param int $courseId
509
     */
510
    public function install_course_plugins($courseId)
511
    {
512
        $pluginList = $this->getInstalledPluginListObject();
513
514
        if (!empty($pluginList)) {
515
            /** @var Plugin $obj */
516
            foreach ($pluginList as $obj) {
517
                $pluginName = $obj->get_name();
518
                $plugin_path = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/plugin.php';
519
520
                if (file_exists($plugin_path)) {
521
                    require $plugin_path;
522
                    if (isset($plugin_info) && isset($plugin_info['plugin_class']) && $obj->isCoursePlugin) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $plugin_info does not exist. Did you maybe mean $plugin_path?
Loading history...
523
                        $obj->course_install($courseId);
524
                    }
525
                }
526
            }
527
        }
528
    }
529
530
    /**
531
     * Add the course settings to the course settings form.
532
     *
533
     * @param FormValidator $form
534
     */
535
    public function add_course_settings_form($form)
536
    {
537
        $pluginList = $this->getInstalledPluginListObject();
538
        /** @var Plugin $obj */
539
        foreach ($pluginList as $obj) {
540
            $pluginName = $obj->get_name();
541
            $pluginTitle = $obj->get_title();
542
            if (!empty($obj->course_settings)) {
543
                if (is_file(api_get_path(SYS_CODE_PATH).'img/icons/'.ICON_SIZE_SMALL.'/'.$pluginName.'.png')) {
544
                    $icon = Display::return_icon(
545
                        $pluginName.'.png',
546
                        Security::remove_XSS($pluginTitle),
547
                        '',
548
                        ICON_SIZE_SMALL
549
                    );
550
                } else {
551
                    $icon = Display::return_icon(
552
                        'plugins.png',
553
                        Security::remove_XSS($pluginTitle),
554
                        '',
555
                        ICON_SIZE_SMALL
556
                    );
557
                }
558
559
                $form->addHtml('<div class="panel panel-default">');
560
                $form->addHtml('
561
                    <div class="panel-heading" role="tab" id="heading-'.$pluginName.'-settings">
562
                        <h4 class="panel-title">
563
                            <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse-'.$pluginName.'-settings" aria-expanded="false" aria-controls="collapse-'.$pluginName.'-settings">
564
                ');
565
                $form->addHtml($icon.' '.$pluginTitle);
566
                $form->addHtml('
567
                            </a>
568
                        </h4>
569
                    </div>
570
                ');
571
                $form->addHtml('
572
                    <div id="collapse-'.$pluginName.'-settings" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-'.$pluginName.'-settings">
573
                        <div class="panel-body">
574
                ');
575
576
                $groups = [];
577
                foreach ($obj->course_settings as $setting) {
578
                    if ($obj->validateCourseSetting($setting['name']) === false) {
579
                        continue;
580
                    }
581
                    if ($setting['type'] != 'checkbox') {
582
                        $form->addElement($setting['type'], $setting['name'], $obj->get_lang($setting['name']));
583
                    } else {
584
                        $element = &$form->createElement(
585
                            $setting['type'],
586
                            $setting['name'],
587
                            '',
588
                            $obj->get_lang($setting['name'])
589
                        );
590
                        if (isset($setting['init_value']) && $setting['init_value'] == 1) {
591
                            $element->setChecked(true);
592
                        }
593
                        $form->addElement($element);
594
595
                        if (isset($setting['group'])) {
596
                            $groups[$setting['group']][] = $element;
597
                        }
598
                    }
599
                }
600
                foreach ($groups as $k => $v) {
601
                    $form->addGroup($groups[$k], $k, [$obj->get_lang($k)]);
602
                }
603
                $form->addButtonSave(get_lang('SaveSettings'));
604
                $form->addHtml('
605
                        </div>
606
                    </div>
607
                ');
608
                $form->addHtml('</div>');
609
            }
610
        }
611
    }
612
613
    /**
614
     * Get all course settings from all installed plugins.
615
     *
616
     * @return array
617
     */
618
    public function getAllPluginCourseSettings()
619
    {
620
        $pluginList = $this->getInstalledPluginListObject();
621
        /** @var Plugin $obj */
622
        $courseSettings = [];
623
        if (!empty($pluginList)) {
624
            foreach ($pluginList as $obj) {
625
                $pluginCourseSetting = $obj->getCourseSettings();
626
                $courseSettings = array_merge($courseSettings, $pluginCourseSetting);
627
            }
628
        }
629
630
        return $courseSettings;
631
    }
632
633
    /**
634
     * When saving the plugin values in the course settings, check whether
635
     * a callback method should be called and send it the updated settings.
636
     *
637
     * @param array $values The new settings the user just saved
638
     */
639
    public function saveCourseSettingsHook($values)
640
    {
641
        $pluginList = $this->getInstalledPluginListObject();
642
643
        /** @var Plugin $obj */
644
        foreach ($pluginList as $obj) {
645
            $settings = $obj->getCourseSettings();
646
            $subValues = [];
647
            if (!empty($settings)) {
648
                foreach ($settings as $v) {
649
                    if (isset($values[$v])) {
650
                        $subValues[$v] = $values[$v];
651
                    }
652
                }
653
            }
654
655
            if (!empty($subValues)) {
656
                $obj->course_settings_updated($subValues);
657
            }
658
        }
659
    }
660
661
    /**
662
     * Get first SMS plugin name.
663
     *
664
     * @return string|bool
665
     */
666
    public function getSMSPluginName()
667
    {
668
        $installedPluginsList = $this->getInstalledPluginListObject();
669
        foreach ($installedPluginsList as $installedPlugin) {
670
            if ($installedPlugin->isMailPlugin) {
671
                return get_class($installedPlugin);
672
            }
673
        }
674
675
        return false;
676
    }
677
678
    /**
679
     * @return SmsPluginLibraryInterface
680
     */
681
    public function getSMSPluginLibrary()
682
    {
683
        $className = $this->getSMSPluginName();
684
        $className = str_replace('Plugin', '', $className);
685
686
        if (class_exists($className)) {
687
            return new $className();
688
        }
689
690
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type SmsPluginLibraryInterface.
Loading history...
691
    }
692
693
    /**
694
     * @param array            $pluginRegionList
695
     * @param string           $pluginRegion
696
     * @param Twig_Environment $twig
697
     *
698
     */
699
    public function setPluginRegion($pluginRegionList, $pluginRegion, $twig)
700
    {
701
        $regionContent = $this->loadRegion(
702
            $pluginRegionList,
703
            $pluginRegion,
704
            $twig,
705
            true //$this->force_plugin_load
706
        );
707
708
        //$twig->addGlobal('plugin_'.$pluginRegion, $regionContent);
709
    }
710
}
711