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 ( 556c32...858d73 )
by Vermeulen
02:59
created

Application::addSubject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
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_CLI_NO_FILE_SPECIFIED Exception code if the cli file to run
29
     * is not specified
30
     */
31
    const ERR_CLI_NO_FILE_SPECIFIED = 1301003;
32
    
33
    /**
34
     * @const ERR_CLI_FILE_NOT_FOUND Exception code if the cli file to run is
35
     * not found.
36
     */
37
    const ERR_CLI_FILE_NOT_FOUND = 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\Subjects[] $subjectsList List of all subjects declared
93
     */
94
    protected $subjectsList;
95
    
96
    /**
97
     * @var \stdClass $ctrlRouterInfos Infos from router for controller system
98
     */
99
    protected $ctrlRouterInfos;
100
101
    /**
102
     * Constructor
103
     * Init output buffering
104
     * Declare run steps
105
     * Set UTF-8 header
106
     * 
107
     * protected for Singleton pattern
108
     */
109
    protected function __construct()
110
    {
111
        //Start the output buffering
112
        ob_start();
113
114
        $this->declareRunSteps();
115
116
        //Defaut http header. Define here add possiblity to override him
117
        header('Content-Type: text/html; charset=utf-8');
118
        
119
        //Default charset to UTF-8. Define here add possiblity to override him
120
        ini_set('default_charset', 'UTF-8');
121
    }
122
123
    /**
124
     * Get the Application instance (Singleton pattern)
125
     * 
126
     * @param array $options Options passed to application
127
     * 
128
     * @return \BFW\Application The current instance of this class
129
     */
130
    public static function getInstance($options = [])
131
    {
132
        if (self::$instance === null) {
133
            $calledClass = get_called_class(); //Autorize extends this class
134
            self::$instance = new $calledClass;
135
            self::$instance->initSystem($options);
136
        }
137
138
        return self::$instance;
139
    }
140
141
    /**
142
     * Like getInstance. This is to have a keyword easier for users who want
143
     * initialize the application
144
     * 
145
     * @param array $options Options passed to application
146
     * 
147
     * @return \BFW\Application The current instance of this class
148
     */
149
    public static function init($options = [])
150
    {
151
        $calledClass = get_called_class(); //Autorize extends this class
152
        return $calledClass::getInstance($options);
153
    }
154
155
    /**
156
     * Getter to access to composerLoader property
157
     * 
158
     * @return \Composer\Autoload\ClassLoader The composer class loader
159
     */
160
    public function getComposerLoader()
161
    {
162
        return $this->composerLoader;
163
    }
164
165
    /**
166
     * Getter to access to the config instance
167
     * 
168
     * @return \BFW\Config
169
     */
170
    public function getConfig()
171
    {
172
        return $this->config;
173
    }
174
    
175
    /**
176
     * Getter to access to memcache instance
177
     * 
178
     * @return Object|null
179
     */
180
    public function getMemcached()
181
    {
182
        return $this->memcached;
183
    }
184
    
185
    /**
186
     * Getter to access to a module
187
     * 
188
     * @param string $moduleName The module name to access
189
     * 
190
     * @return \BFW\Module
191
     */
192
    public function getModule($moduleName)
193
    {
194
        return $this->modules->getModule($moduleName);
195
    }
196
197
    /**
198
     * Getter to access to an option's value
199
     * 
200
     * @param string $optionKey The key for the option
201
     * 
202
     * @return mixed
203
     */
204
    public function getOption($optionKey)
205
    {
206
        return $this->options->getValue($optionKey);
207
    }
208
    
209
    /**
210
     * Getter to access to the Request instance
211
     * 
212
     * @return \BFW\Request
213
     */
214
    public function getRequest()
215
    {
216
        return $this->request;
217
    }
218
    
219
    /**
220
     * Getter to access to the run step array
221
     * 
222
     * @return array
223
     */
224
    public function getRunSteps()
225
    {
226
        return $this->runSteps;
227
    }
228
    
229
    /**
230
     * Initialize all components
231
     * 
232
     * @param array $options Options passed to application
233
     * 
234
     * @return void
235
     */
236
    protected function initSystem($options)
237
    {
238
        $this->initOptions($options);
239
        $this->initConstants();
240
        $this->initComposerLoader();
241
        $this->initConfig();
242
        $this->initRequest();
243
        $this->initSession();
244
        $this->initErrors();
245
        $this->initRunTasks();
246
        $this->initModules();
247
    }
248
249
    /**
250
     * Initialize options with the class \BFW\Core\Options
251
     * 
252
     * @param array $options The option passed when initialize this class
253
     */
254
    protected function initOptions($options)
255
    {
256
        $defaultOptions = [
257
            'rootDir'    => null,
258
            'vendorDir'  => null,
259
            'runSession' => true
260
        ];
261
262
        $this->options = new \BFW\Core\Options($defaultOptions, $options);
263
    }
264
265
    /**
266
     * Initialize all constants used by framework
267
     * Use helper Constants::create to allow override of constants
268
     * 
269
     * @return void
270
     */
271
    protected function initConstants()
272
    {
273
        Constants::create('ROOT_DIR', $this->options->getValue('rootDir'));
274
275
        Constants::create('APP_DIR', ROOT_DIR.'app/');
276
        Constants::create('SRC_DIR', ROOT_DIR.'src/');
277
        Constants::create('WEB_DIR', ROOT_DIR.'web/');
278
279
        Constants::create('CONFIG_DIR', APP_DIR.'config/');
280
        Constants::create('MODULES_DIR', APP_DIR.'modules/');
281
282
        Constants::create('CLI_DIR', SRC_DIR.'cli/');
283
        Constants::create('CTRL_DIR', SRC_DIR.'controllers/');
284
        Constants::create('MODELES_DIR', SRC_DIR.'modeles/');
285
        Constants::create('VIEW_DIR', SRC_DIR.'view/');
286
    }
287
288
    /**
289
     * Initialize composer loader
290
     * Obtain the composerLoader instance
291
     * Call addComposerNamespaces method to add Application namespaces
292
     * 
293
     * @return void
294
     */
295
    protected function initComposerLoader()
296
    {
297
        $this->composerLoader = require(
298
            $this->options->getValue('vendorDir').'autoload.php'
299
        );
300
        $this->addComposerNamespaces();
301
    }
302
303
    /**
304
     * Initialize the property config with \BFW\Config instance
305
     * The config class will search all file in "bfw" directory and load files
306
     * 
307
     * @return void
308
     */
309
    protected function initConfig()
310
    {
311
        $this->config = new \BFW\Config('bfw');
312
        $this->config->loadFiles();
313
    }
314
315
    /**
316
     * Initialize request property with the \BFW\Request class
317
     * 
318
     * @return void
319
     */
320
    protected function initRequest()
321
    {
322
        $this->request = \BFW\Request::getInstance();
323
    }
324
325
    /**
326
     * Initiliaze php session if option "runSession" is not (bool) false
327
     * 
328
     * @return void
329
     */
330
    protected function initSession()
331
    {
332
        if ($this->options->getValue('runSession') === false) {
333
            return;
334
        }
335
336
        //Destroy session cookie if browser quit
337
        session_set_cookie_params(0);
338
339
        //Run session
340
        session_start();
341
    }
342
343
    /**
344
     * Initialize errors property with the \BFW\Core\Errors class
345
     * 
346
     * @return void
347
     */
348
    protected function initErrors()
349
    {
350
        $this->errors = new \BFW\Core\Errors();
351
    }
352
    
353
    /**
354
     * Initialize taskers
355
     * 
356
     * @return void
357
     */
358
    protected function initRunTasks()
359
    {
360
        $stepsToRun = [];
361
        foreach ($this->runSteps as $step) {
362
            $stepName = $step[1];
363
            
364
            //To keep methods to run protected
365
            $stepsToRun[$stepName] = (object) [
366
                'callback' => function() use ($step) {
367
                    $step();
368
                }
369
            ];
370
        }
371
        
372
        $runTasks = new \BFW\RunTasks($stepsToRun, 'BfwApp');
373
        $this->addSubject($runTasks, 'ApplicationTasks');
374
    }
375
376
    /**
377
     * Initialize modules property with the \BFW\Modules class
378
     * 
379
     * @return void
380
     */
381
    protected function initModules()
382
    {
383
        $this->modules = new \BFW\Modules;
384
    }
385
386
    /**
387
     * Add namespaces used by a BFW Application to composer
388
     * 
389
     * @return void
390
     */
391
    protected function addComposerNamespaces()
392
    {
393
        $this->composerLoader->addPsr4('Controller\\', CTRL_DIR);
394
        $this->composerLoader->addPsr4('Modules\\', MODULES_DIR);
395
        $this->composerLoader->addPsr4('Modeles\\', MODELES_DIR);
396
    }
397
398
    /**
399
     * Declare all steps to run the application
400
     * 
401
     * @return void
402
     */
403
    protected function declareRunSteps()
404
    {
405
        $this->runSteps = [
406
            [$this, 'loadMemcached'],
407
            [$this, 'readAllModules'],
408
            [$this, 'loadAllCoreModules'],
409
            [$this, 'loadAllAppModules'],
410
            [$this, 'runCliFile'],
411
            [$this, 'initCtrlRouterLink']
412
        ];
413
    }
414
415
    /**
416
     * Run the application
417
     * 
418
     * @return void
419
     */
420
    public function run()
421
    {
422
        $runTasks = $this->getSubjectForName('ApplicationTasks');
423
        
424
        $runTasks->run();
425
        $runTasks->sendNotify('bfw_run_finish');
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...
426
    }
427
428
    /**
429
     * Connect to memcache(d) server with the class declared in config file
430
     * 
431
     * @return Object
432
     * 
433
     * @throws Exception If memcached is enabled but no class is define. Or if
434
     *  The class declared into the config is not found.
435
     */
436
    protected function loadMemcached()
437
    {
438
        $memcachedConfig = $this->config->getValue('memcached');
439
440
        if ($memcachedConfig['enabled'] === false) {
441
            return;
442
        }
443
444
        $class = $memcachedConfig['class'];
445
        if (empty($class)) {
446
            throw new Exception(
447
                'Memcached is active but no class is define',
448
                $this::ERR_MEMCACHED_NOT_CLASS_DEFINED
449
            );
450
        }
451
452
        if (class_exists($class) === false) {
453
            throw new Exception(
454
                'Memcache class '.$class.' not found.',
455
                $this::ERR_MEMCACHED_CLASS_NOT_FOUND
456
            );
457
        }
458
459
        $this->memcached = new $class;
460
    }
461
462
    /**
463
     * Read all directories in modules directory and add each module to Modules
464
     * class.
465
     * Generate the load tree.
466
     * Not initialize modules !
467
     * 
468
     * @return void
469
     */
470
    protected function readAllModules()
471
    {
472
        $listModules = array_diff(scandir(MODULES_DIR), ['.', '..']);
473
474
        foreach ($listModules as $moduleName) {
475
            $modulePath = realpath(MODULES_DIR.$moduleName); //Symlink
476
477
            if (!is_dir($modulePath)) {
478
                continue;
479
            }
480
481
            $this->modules->addModule($moduleName);
482
        }
483
484
        $this->modules->readNeedMeDependencies();
485
        $this->modules->generateTree();
486
    }
487
488
    /**
489
     * Load core modules defined into config bfw file.
490
     * Only module for controller, router, database and template only.
491
     * 
492
     * @return void
493
     */
494
    protected function loadAllCoreModules()
495
    {
496
        foreach ($this->config->getValue('modules') as $moduleInfos) {
497
            $moduleName    = $moduleInfos['name'];
498
            $moduleEnabled = $moduleInfos['enabled'];
499
500
            if (empty($moduleName) || $moduleEnabled === false) {
501
                continue;
502
            }
503
504
            $this->loadModule($moduleName);
505
        }
506
    }
507
508
    /**
509
     * Load all modules (except core).
510
     * Get the load tree, read him and load all modules with the order
511
     * declared into the tree.
512
     * 
513
     * @return void
514
     */
515
    protected function loadAllAppModules()
516
    {
517
        $tree = $this->modules->getLoadTree();
518
519
        foreach ($tree as $firstLine) {
520
            foreach ($firstLine as $secondLine) {
521
                foreach ($secondLine as $moduleName) {
522
                    $this->loadModule($moduleName);
523
                }
524
            }
525
        }
526
    }
527
528
    /**
529
     * Load a module
530
     * 
531
     * @param string $moduleName The module's name to load
532
     * 
533
     * @return void
534
     */
535
    protected function loadModule($moduleName)
536
    {
537
        $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...
538
            ->sendNotify('BfwApp_load_module_'.$moduleName);
539
        
540
        $this->modules->getModule($moduleName)->runModule();
541
    }
542
543
    /**
544
     * Run the cli file if we're in cli mode
545
     * 
546
     * @return void
547
     * 
548
     * @throws Exception If no file is specified or if the file not exist.
549
     */
550
    protected function runCliFile()
551
    {
552
        if (PHP_SAPI !== 'cli') {
553
            return;
554
        }
555
556
        $cliArgs = getopt('f:');
557
        if (!isset($cliArgs['f'])) {
558
            throw new Exception(
559
                'Error: No file specified.',
560
                $this::ERR_CLI_NO_FILE_SPECIFIED
561
            );
562
        }
563
564
        $file = $cliArgs['f'];
565
        if (!file_exists(CLI_DIR.$file.'.php')) {
566
            throw new Exception(
567
                'File to execute not found.',
568
                $this::ERR_CLI_FILE_NOT_FOUND
569
            );
570
        }
571
572
        $fctRunCliFile = function() use ($file) {
573
            require_once(CLI_DIR.$file.'.php');
574
        };
575
576
        $this->addNotification('run_cli_file');
0 ignored issues
show
Bug introduced by
The method addNotification() does not seem to exist on object<BFW\Application>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
577
        $fctRunCliFile();
578
    }
579
    
580
    /**
581
     * Create a new observer to controller and router module.
582
     * 
583
     * @return void
584
     */
585
    protected function initCtrlRouterLink()
586
    {
587
        if (PHP_SAPI === 'cli') {
588
            return;
589
        }
590
591
        //Others properties will be dynamically added by modules
592
        $this->ctrlRouterInfos = (object) [
593
            'isFound' => false
594
        ];
595
        
596
        $ctrlRouterTask = new RunTasks(
597
            [
598
                'searchRoute' => (object) [
599
                    'context' => $this->ctrlRouterInfos
600
                ]
601
            ],
602
            'ctrlRouterLink'
603
        );
604
        
605
        $this->addSubject($ctrlRouterTask, 'ctrlRouterLink');
606
        $ctrlRouterTask->run();
607
        
608
        if ($this->ctrlRouterInfos->isFound === false) {
609
            http_response_code(404);
610
        }
611
    }
612
    
613
    /**
614
     * Add a new subject to the list
615
     * 
616
     * @param \BFW\Subjects $subject The new subject to add
617
     * @param string|null $subjectName (default null) The subject name, if null,
618
     * the name of the class will be used
619
     * 
620
     * @return void
621
     */
622
    public function addSubject(\BFW\Subjects $subject, $subjectName = null)
623
    {
624
        if ($subjectName === null) {
625
            $subjectName = get_class($subject);
626
        }
627
        
628
        $this->subjectsList[$subjectName] = $subject;
629
    }
630
    
631
    /**
632
     * Obtain a subject object with this name
633
     * 
634
     * @param string $subjectName The name of the subject object
635
     * 
636
     * @return \BFW\Subjects
637
     * 
638
     * @throws Exception If the subject name not exist
639
     */
640
    public function getSubjectForName($subjectName)
641
    {
642
        if (!array_key_exists($subjectName, $this->subjectsList)) {
643
            throw new Exception(
644
                'The subject '.$subjectName.' is not in the list.',
645
                self::ERR_SUBJECT_NAME_NOT_EXIST
646
            );
647
        }
648
        
649
        return $this->subjectsList[$subjectName];
650
    }
651
}
652