GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — 3.0 ( de1771...791612 )
by Vermeulen
04:28
created

Application::getModules()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace BFW;
4
5
use \Exception;
6
use \BFW\Helpers\Constants;
7
8
/**
9
 * Application class
10
 * Manage all BFW application
11
 * Load and init components, modules, ...
12
 */
13
class Application
14
{
15
    /**
16
     * @const ERR_MEMCACHED_NOT_CLASS_DEFINED Exception code if memcache(d) is
17
     * enabled but the class to use is not defined.
18
     */
19
    const ERR_MEMCACHED_NOT_CLASS_DEFINED = 1301001;
20
    
21
    /**
22
     * @const ERR_MEMCACHED_CLASS_NOT_FOUND Exception code if the memcache(d)
23
     * class is not found.
24
     */
25
    const ERR_MEMCACHED_CLASS_NOT_FOUND = 1301002;
26
    
27
    /**
28
     * @const ERR_MEMCACHED_NOT_IMPLEMENT_INTERFACE Exception code the
29
     * memcache(d) class not implement the interface.
30
     */
31
    const ERR_MEMCACHED_NOT_IMPLEMENT_INTERFACE = 1301003;
32
    
33
    /**
34
     * @const ERR_SUBJECT_NAME_NOT_EXIST Exception code if a subject name is
35
     * not found.
36
     */
37
    const ERR_SUBJECT_NAME_NOT_EXIST = 1301004;
38
    
39
    /**
40
     * @var \BFW\Application|null $instance Application instance (Singleton)
41
     */
42
    protected static $instance = null;
43
44
    /**
45
     * @var string $rootDir Path to the application project directory
46
     */
47
    protected $rootDir = '';
48
49
    /**
50
     * @var \BFW\Config $config Config's instance for BFW
51
     */
52
    protected $config;
53
54
    /**
55
     * @var \BFW\Core\Options $options Option's instance for the core
56
     */
57
    protected $options;
58
59
    /**
60
     * @var \Composer\Autoload\ClassLoader $composerLoader Loader used by
61
     *  composer.
62
     */
63
    protected $composerLoader;
64
65
    /**
66
     * @var array[] $runSteps All steps used for run the application
67
     */
68
    protected $runSteps = [];
69
70
    /**
71
     * @var Object $memcached The class used to connect to memcache(d) server.
72
     * The class name should be declared into config file.
73
     */
74
    protected $memcached;
75
76
    /**
77
     * @var \BFW\Request $request Informations about the http request
78
     */
79
    protected $request;
80
81
    /**
82
     * @var \BFW\Modules $modules System who manage all modules
83
     */
84
    protected $modules;
85
    
86
    /**
87
     * @var \BFW\Core\Errors $errors System who manage personal errors page
88
     */
89
    protected $errors;
90
    
91
    /**
92
     * @var \BFW\Core\Cli $cli Cli system
93
     */
94
    protected $cli;
95
    
96
    /**
97
     * @var \BFW\Subjects[] $subjectsList List of all subjects declared
98
     */
99
    protected $subjectsList = [];
100
    
101
    /**
102
     * @var \stdClass $ctrlRouterInfos Infos from router for controller system
103
     */
104
    protected $ctrlRouterInfos;
105
106
    /**
107
     * Constructor
108
     * Init output buffering
109
     * Declare run steps
110
     * Set UTF-8 header
111
     * 
112
     * protected for Singleton pattern
113
     */
114
    protected function __construct()
115
    {
116
        //Start the output buffering
117
        ob_start();
118
119
        $this->declareRunSteps();
120
121
        //Defaut http header. Define here add possiblity to override him
122
        header('Content-Type: text/html; charset=utf-8');
123
        
124
        //Default charset to UTF-8. Define here add possiblity to override him
125
        ini_set('default_charset', 'UTF-8');
126
    }
127
128
    /**
129
     * Get the Application instance (Singleton pattern)
130
     * 
131
     * @return \BFW\Application The current instance of this class
132
     */
133 View Code Duplication
    public static function getInstance()
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
134
    {
135
        if (self::$instance === null) {
136
            $calledClass = get_called_class(); //Autorize extends this class
137
            self::$instance = new $calledClass;
138
        }
139
140
        return self::$instance;
141
    }
142
143
    /**
144
     * Getter to access to cli property
145
     * 
146
     * @return \BFW\Core\Cli
147
     */
148
    public function getCli()
149
    {
150
        return $this->cli;
151
    }
152
153
    /**
154
     * Getter to access to composerLoader property
155
     * 
156
     * @return \Composer\Autoload\ClassLoader The composer class loader
157
     */
158
    public function getComposerLoader()
159
    {
160
        return $this->composerLoader;
161
    }
162
163
    /**
164
     * Getter to access to the config instance
165
     * 
166
     * @return \BFW\Config
167
     */
168
    public function getConfig()
169
    {
170
        return $this->config;
171
    }
172
    
173
    /**
174
     * Getter to access to the errors instance
175
     * 
176
     * @return \BFW\Errors
177
     */
178
    public function getErrors()
179
    {
180
        return $this->errors;
181
    }
182
    
183
    /**
184
     * Getter to access to the ctrlRouterInfos property
185
     * 
186
     * @return null|\stdClass
187
     */
188
    public function getCtrlRouterInfos()
189
    {
190
        return $this->ctrlRouterInfos;
191
    }
192
    
193
    /**
194
     * Getter to access to memcache instance
195
     * 
196
     * @return Object|null
197
     */
198
    public function getMemcached()
199
    {
200
        return $this->memcached;
201
    }
202
    
203
    /**
204
     * Getter to access to modules system
205
     * 
206
     * @return \BFW\Modules
207
     */
208
    public function getModules()
209
    {
210
        return $this->modules;
211
    }
212
    
213
    /**
214
     * Getter to access to a module
215
     * 
216
     * @param string $moduleName The module name to access
217
     * 
218
     * @return \BFW\Module
219
     */
220
    public function getModuleForName($moduleName)
221
    {
222
        return $this->modules->getModuleForName($moduleName);
223
    }
224
225
    /**
226
     * Getter to access to the options system
227
     * 
228
     * @return mixed
229
     */
230
    public function getOptions()
231
    {
232
        return $this->options;
233
    }
234
    
235
    /**
236
     * Getter to access to the Request instance
237
     * 
238
     * @return \BFW\Request
239
     */
240
    public function getRequest()
241
    {
242
        return $this->request;
243
    }
244
    
245
    /**
246
     * Getter to access to the run step array
247
     * 
248
     * @return array
249
     */
250
    public function getRunSteps()
251
    {
252
        return $this->runSteps;
253
    }
254
255
    /**
256
     * Getter to access to the subjects list
257
     * 
258
     * @return \BFW\Subjects[]
259
     */
260
    public function getSubjectsList()
261
    {
262
        return $this->subjectsList;
263
    }
264
    
265
    /**
266
     * Initialize all components
267
     * 
268
     * @param array $options Options passed to application
269
     * 
270
     * @return void
271
     */
272
    public function initSystem($options)
273
    {
274
        $this->initOptions($options);
275
        $this->initConstants();
276
        $this->initComposerLoader();
277
        $this->initConfig();
278
        $this->initRequest();
279
        $this->initSession();
280
        $this->initErrors();
281
        $this->initCli();
282
        $this->initRunTasks();
283
        $this->initModules();
284
        
285
        return $this;
286
    }
287
288
    /**
289
     * Initialize options with the class \BFW\Core\Options
290
     * 
291
     * @param array $options The option passed when initialize this class
292
     */
293
    protected function initOptions($options)
294
    {
295
        $defaultOptions = [
296
            'rootDir'    => null,
297
            'vendorDir'  => null,
298
            'runSession' => true
299
        ];
300
301
        $this->options = new \BFW\Core\Options($defaultOptions, $options);
302
        $this->options
303
            ->searchPaths()
304
            ->checkPaths()
305
        ;
306
    }
307
308
    /**
309
     * Initialize all constants used by framework
310
     * Use helper Constants::create to allow override of constants
311
     * 
312
     * @return void
313
     */
314
    protected function initConstants()
315
    {
316
        Constants::create('ROOT_DIR', $this->options->getValue('rootDir'));
317
318
        Constants::create('APP_DIR', ROOT_DIR.'app/');
319
        Constants::create('SRC_DIR', ROOT_DIR.'src/');
320
        Constants::create('WEB_DIR', ROOT_DIR.'web/');
321
322
        Constants::create('CONFIG_DIR', APP_DIR.'config/');
323
        Constants::create('MODULES_DIR', APP_DIR.'modules/');
324
325
        Constants::create('CLI_DIR', SRC_DIR.'cli/');
326
        Constants::create('CTRL_DIR', SRC_DIR.'controllers/');
327
        Constants::create('MODELES_DIR', SRC_DIR.'modeles/');
328
        Constants::create('VIEW_DIR', SRC_DIR.'view/');
329
    }
330
331
    /**
332
     * Initialize composer loader
333
     * Obtain the composerLoader instance
334
     * Call addComposerNamespaces method to add Application namespaces
335
     * 
336
     * @return void
337
     */
338
    protected function initComposerLoader()
339
    {
340
        $this->composerLoader = require(
341
            $this->options->getValue('vendorDir').'autoload.php'
342
        );
343
        $this->addComposerNamespaces();
344
    }
345
346
    /**
347
     * Initialize the property config with \BFW\Config instance
348
     * The config class will search all file in "bfw" directory and load files
349
     * 
350
     * @return void
351
     */
352
    protected function initConfig()
353
    {
354
        $this->config = new \BFW\Config('bfw');
355
        $this->config->loadFiles();
356
    }
357
358
    /**
359
     * Initialize request property with the \BFW\Request class
360
     * 
361
     * @return void
362
     */
363
    protected function initRequest()
364
    {
365
        $this->request = \BFW\Request::getInstance();
366
        $this->request->runDetect();
367
    }
368
369
    /**
370
     * Initiliaze php session if option "runSession" is not (bool) false
371
     * 
372
     * @return void
373
     */
374
    protected function initSession()
375
    {
376
        if ($this->options->getValue('runSession') === false) {
377
            return;
378
        }
379
380
        //Destroy session cookie if browser quit
381
        session_set_cookie_params(0);
382
383
        //Run session
384
        session_start();
385
    }
386
387
    /**
388
     * Initialize errors property with the \BFW\Core\Errors class
389
     * 
390
     * @return void
391
     */
392
    protected function initErrors()
393
    {
394
        $this->errors = new \BFW\Core\Errors;
395
    }
396
397
    /**
398
     * Initialize cli property with the \BFW\Core\Cli class
399
     * 
400
     * @return void
401
     */
402
    protected function initCli()
403
    {
404
        $this->cli = new \BFW\Core\Cli;
405
    }
406
    
407
    /**
408
     * Initialize taskers
409
     * 
410
     * @return void
411
     */
412
    protected function initRunTasks()
413
    {
414
        $stepsToRun = [];
415
        $closureNb  = 0;
416
        
417
        foreach ($this->runSteps as $step) {
418
            if ($step instanceof \Closure) {
419
                $stepName = 'closure_'.$closureNb;
420
                $closureNb++;
421
            } else {
422
                $stepName = $step[1];
423
            }
424
            
425
            //To keep methods to run protected
426
            $stepsToRun[$stepName] = (object) [
427
                'callback' => function() use ($step) {
428
                    $step();
429
                }
430
            ];
431
        }
432
        
433
        $runTasks = new \BFW\RunTasks($stepsToRun, 'BfwApp');
434
        $this->addSubject($runTasks, 'ApplicationTasks');
435
    }
436
437
    /**
438
     * Initialize modules property with the \BFW\Modules class
439
     * 
440
     * @return void
441
     */
442
    protected function initModules()
443
    {
444
        $this->modules = new \BFW\Modules;
445
    }
446
447
    /**
448
     * Add namespaces used by a BFW Application to composer
449
     * 
450
     * @return void
451
     */
452
    protected function addComposerNamespaces()
453
    {
454
        $this->composerLoader->addPsr4('Controller\\', CTRL_DIR);
455
        $this->composerLoader->addPsr4('Modules\\', MODULES_DIR);
456
        $this->composerLoader->addPsr4('Modeles\\', MODELES_DIR);
457
    }
458
459
    /**
460
     * Declare all steps to run the application
461
     * 
462
     * @return void
463
     */
464
    protected function declareRunSteps()
465
    {
466
        $this->runSteps = [
467
            [$this, 'loadMemcached'],
468
            [$this, 'loadAllModules'],
469
            [$this, 'runAllCoreModules'],
470
            [$this, 'runAllAppModules'],
471
            [$this, 'runCliFile'],
472
            [$this, 'initCtrlRouterLink'],
473
            [$this, 'runCtrlRouterLink']
474
        ];
475
    }
476
477
    /**
478
     * Run the application
479
     * 
480
     * @return void
481
     */
482
    public function run()
483
    {
484
        $runTasks = $this->getSubjectForName('ApplicationTasks');
485
        
486
        $runTasks->run();
487
        $runTasks->sendNotify('bfw_run_done');
0 ignored issues
show
Bug introduced by
The method sendNotify() does not exist on BFW\Subjects. Did you maybe mean notify()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
488
    }
489
490
    /**
491
     * Connect to memcache(d) server with the class declared in config file
492
     * 
493
     * @return Object
494
     * 
495
     * @throws Exception If memcached is enabled but no class is define. Or if
496
     *  The class declared into the config is not found.
497
     */
498
    protected function loadMemcached()
499
    {
500
        $memcachedConfig = $this->config->getValue('memcached');
501
502
        if ($memcachedConfig['enabled'] === false) {
503
            return;
504
        }
505
506
        $class = $memcachedConfig['class'];
507
        if (empty($class)) {
508
            throw new Exception(
509
                'Memcached is active but no class is define',
510
                $this::ERR_MEMCACHED_NOT_CLASS_DEFINED
511
            );
512
        }
513
514
        if (class_exists($class) === false) {
515
            throw new Exception(
516
                'Memcache class '.$class.' not found.',
517
                $this::ERR_MEMCACHED_CLASS_NOT_FOUND
518
            );
519
        }
520
521
        $this->memcached = new $class;
522
        
523
        if (!($this->memcached instanceof \BFW\Memcache\MemcacheInterface)) {
524
            throw new Exception(
525
                'Memcache class '.$class.' not implement the interface.',
526
                $this::ERR_MEMCACHED_NOT_IMPLEMENT_INTERFACE
527
            );
528
        }
529
        
530
        $this->memcached->connectToServers();
531
    }
532
533
    /**
534
     * Read all directories in modules directory and add each module to Modules
535
     * class.
536
     * Generate the load tree.
537
     * Not initialize modules !
538
     * 
539
     * @return void
540
     */
541
    protected function loadAllModules()
542
    {
543
        $listModules = array_diff(scandir(MODULES_DIR), ['.', '..']);
544
545
        foreach ($listModules as $moduleName) {
546
            $modulePath = realpath(MODULES_DIR.$moduleName); //Symlink
547
548
            if (!is_dir($modulePath)) {
549
                continue;
550
            }
551
552
            $this->modules->addModule($moduleName);
553
        }
554
555
        $this->modules->readNeedMeDependencies();
556
        $this->modules->generateTree();
557
    }
558
559
    /**
560
     * Load core modules defined into config bfw file.
561
     * Only module for controller, router, database and template only.
562
     * 
563
     * @return void
564
     */
565
    protected function runAllCoreModules()
566
    {
567
        foreach ($this->config->getValue('modules') as $moduleInfos) {
568
            $moduleName    = $moduleInfos['name'];
569
            $moduleEnabled = $moduleInfos['enabled'];
570
571
            if (empty($moduleName) || $moduleEnabled === false) {
572
                continue;
573
            }
574
575
            $this->runModule($moduleName);
576
        }
577
    }
578
579
    /**
580
     * Load all modules (except core).
581
     * Get the load tree, read him and load all modules with the order
582
     * declared into the tree.
583
     * 
584
     * @return void
585
     */
586
    protected function runAllAppModules()
587
    {
588
        $tree = $this->modules->getLoadTree();
589
590
        foreach ($tree as $firstLine) {
591
            foreach ($firstLine as $secondLine) {
592
                foreach ($secondLine as $moduleName) {
593
                    $this->runModule($moduleName);
594
                }
595
            }
596
        }
597
    }
598
599
    /**
600
     * Load a module
601
     * 
602
     * @param string $moduleName The module's name to load
603
     * 
604
     * @return void
605
     */
606
    protected function runModule($moduleName)
607
    {
608
        $this->getSubjectForName('ApplicationTasks')
0 ignored issues
show
Bug introduced by
The method sendNotify() does not exist on BFW\Subjects. Did you maybe mean notify()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
609
            ->sendNotify('BfwApp_load_module_'.$moduleName);
610
        
611
        $this->modules->getModuleForName($moduleName)->runModule();
612
    }
613
614
    /**
615
     * Run the cli file if we're in cli mode
616
     * 
617
     * @return void
618
     * 
619
     * @throws Exception If no file is specified or if the file not exist.
620
     */
621
    protected function runCliFile()
622
    {
623
        if (PHP_SAPI !== 'cli') {
624
            return;
625
        }
626
627
        $this->getSubjectForName('ApplicationTasks')
0 ignored issues
show
Bug introduced by
The method sendNotify() does not exist on BFW\Subjects. Did you maybe mean notify()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
628
            ->sendNotify('run_cli_file');
629
        
630
        $fileToExec = $this->cli->obtainFileFromArg();
631
        $this->cli->run($fileToExec);
632
    }
633
    
634
    /**
635
     * Create a new observer to controller and router module.
636
     * 
637
     * @return void
638
     */
639
    protected function initCtrlRouterLink()
640
    {
641
        if (PHP_SAPI === 'cli') {
642
            return;
643
        }
644
645
        //Others properties can be dynamically added by modules
646
        $this->ctrlRouterInfos = (object) [
647
            'isFound' => false
648
        ];
649
        
650
        $ctrlRouterTask = new RunTasks(
651
            [
652
                'searchRoute' => (object) [
653
                    'context' => $this->ctrlRouterInfos
654
                ]
655
            ],
656
            'ctrlRouterLink'
657
        );
658
        
659
        $this->addSubject($ctrlRouterTask, 'ctrlRouterLink');
660
        
661
        $runTasks = $this->getSubjectForName('ApplicationTasks');
662
        $runTasks->sendNotify('bfw_ctrlRouterLink_subject_added');
1 ignored issue
show
Bug introduced by
The method sendNotify() does not exist on BFW\Subjects. Did you maybe mean notify()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
663
    }
664
    
665
    /**
666
     * Execute the ctrlRouter task to find the route and the controller.
667
     * If nothing is found (context object), return an 404 error.
668
     * Not executed in cli.
669
     * 
670
     * @return void
671
     */
672
    protected function runCtrlRouterLink()
673
    {
674
        if (PHP_SAPI === 'cli') {
675
            return;
676
        }
677
        
678
        $ctrlRouterTask = $this->getSubjectForName('ctrlRouterLink');
679
        $ctrlRouterTask->run();
680
        
681
        if ($this->ctrlRouterInfos->isFound === false) {
682
            http_response_code(404);
683
        }
684
    }
685
    
686
    /**
687
     * Add a new subject to the list
688
     * 
689
     * @param \BFW\Subjects $subject The new subject to add
690
     * @param string|null $subjectName (default null) The subject name, if null,
691
     * the name of the class will be used
692
     * 
693
     * @return void
694
     */
695
    public function addSubject(\BFW\Subjects $subject, $subjectName = null)
696
    {
697
        if ($subjectName === null) {
698
            $subjectName = get_class($subject);
699
        }
700
        
701
        $this->subjectsList[$subjectName] = $subject;
702
    }
703
    
704
    /**
705
     * Obtain a subject object with this name
706
     * 
707
     * @param string $subjectName The name of the subject object
708
     * 
709
     * @return \BFW\Subjects
710
     * 
711
     * @throws Exception If the subject name not exist
712
     */
713
    public function getSubjectForName($subjectName)
714
    {
715
        if (!array_key_exists($subjectName, $this->subjectsList)) {
716
            throw new Exception(
717
                'The subject '.$subjectName.' is not in the list.',
718
                self::ERR_SUBJECT_NAME_NOT_EXIST
719
            );
720
        }
721
        
722
        return $this->subjectsList[$subjectName];
723
    }
724
}
725