Completed
Push — master ( 3e9332...26b945 )
by Vitaly
31:30 queued 21:32
created

Core::createMetadata()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 18
c 0
b 0
f 0
nc 1
nop 4
dl 0
loc 24
ccs 0
cts 0
cp 0
crap 2
rs 8.9713
1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of the SamsonPHP\Core package.
4
 * (c) 2013 Vitaly Iegorov <[email protected]>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
namespace samson\core;
10
11
use Doctrine\Common\Annotations\AnnotationReader;
12
use samsonframework\container\Builder;
13
use samsonframework\container\metadata\ClassMetadata;
14
use samsonframework\container\metadata\MethodMetadata;
15
use samsonframework\container\metadata\PropertyMetadata;
16
use samsonframework\containerannotation\AnnotationClassResolver;
17
use samsonframework\containerannotation\AnnotationMetadataCollector;
18
use samsonframework\containerannotation\AnnotationMethodResolver;
19
use samsonframework\containerannotation\AnnotationPropertyResolver;
20
use samsonframework\containerannotation\AnnotationResolver;
21
use samsonframework\containerannotation\Inject;
22
use samsonframework\containerannotation\Injectable;
23
use samsonframework\containerannotation\InjectArgument;
24
use samsonframework\core\SystemInterface;
25
use samsonframework\di\ContainerInterface;
26
use samsonframework\resource\ResourceMap;
27
use samsonphp\config\Scheme;
28
use samsonphp\core\exception\CannotLoadModule;
29
use samsonphp\core\exception\ViewPathNotFound;
30
use samsonphp\event\Event;
31
use samsonframework\container\ContainerBuilderInterface;
32
33
/**
34
 * SamsonPHP Core.
35
 *
36
 * @author Vitaly Iegorov <[email protected]>
37
 */
38
class Core implements SystemInterface
39
{
40
    /** @var ContainerInterface */
41
    protected $container;
42
43
    /** @var ClassMetadata[] */
44
    protected $metadataCollection = [];
45
46
    /** @var ContainerBuilderInterface */
47
    protected $builder;
48
49
    /** @var string Current system environment */
50
    protected $environment;
51
52
    /* Rendering models */
53
    /** @deprecated Standard algorithm for view rendering */
54
    const RENDER_STANDART = 1;
55
    /** @deprecated View rendering algorithm from array of view variables */
56
    const RENDER_VARIABLE = 3;
57
58
    /** @deprecated @var  ResourceMap Current web-application resource map */
59
    public $map;
60
   
61
    /** @deprecated @var string Path to current web-application */
62
    public $system_path = __SAMSON_CWD__;
63
    /** @deprecated @var string View path loading mode */
64
    public $render_mode = self::RENDER_STANDART;
65
    /** @var Module Pointer to current active module */
66
    protected $active = null;
67
    /** @var bool Flag for outputting layout template, used for asynchronous requests */
68
    protected $async = false;
69
    /** @var string Path to main system template */
70
    protected $template_path = __SAMSON_DEFAULT_TEMPLATE;
71
72
    /** @return \Container Get system container */
73
    public function getContainer()
74
    {
75
        return $this->container;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->container; (samsonframework\di\ContainerInterface) is incompatible with the return type declared by the interface samsonframework\core\SystemInterface::getContainer of type samsonframework\container\ContainerInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
76
    }
77
78
    /**
79
     * Core constructor.
80
     *
81
     * @param ContainerBuilderInterface $builder Container builder
82
     * @param ResourceMap|null $map system resources
83
     */
84
    public function __construct(ContainerBuilderInterface $builder, ResourceMap $map = null)
85
    {
86
        $this->builder = $builder;
87
88
        if (!isset($map)) {
89
            // Get correct web-application path
90
            $this->system_path = __SAMSON_CWD__;
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$system_path has been deprecated with message: @var string Path to current web-application

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
91
92
            // Get web-application resource map
93
            $this->map = ResourceMap::get($this->system_path, false, array('src/'));
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$map has been deprecated with message: @var ResourceMap Current web-application resource map

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
Deprecated Code introduced by
The property samson\core\Core::$system_path has been deprecated with message: @var string Path to current web-application

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
94
        } else { // Use data from passed map
95
            $this->map = $map;
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$map has been deprecated with message: @var ResourceMap Current web-application resource map

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
96
            $this->system_path = $map->entryPoint;
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$system_path has been deprecated with message: @var string Path to current web-application

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
97
        }
98
99
        // Temporary add template worker
100
        $this->subscribe('core.rendered', array($this, 'generateTemplate'));
101
102
        // Fire core creation event
103
        Event::fire('core.created', array(&$this));
104
105
        // Signal core configure event
106
        Event::signal('core.configure', array($this->system_path . __SAMSON_CONFIG_PATH));
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$system_path has been deprecated with message: @var string Path to current web-application

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
107
    }
108
109
    /**
110 1
     * Generic wrap for Event system subscription.
111
     * @see \samson\core\\samsonphp\event\Event::subscribe()
112
     *
113
     * @param string   $key     Event identifier
114
     * @param callable $handler Event handler
115
     * @param array    $params  Event parameters
116
     *
117
     * @return $this Chaining
118
     */
119
    public function subscribe($key, $handler, $params = array())
120
    {
121 1
        Event::subscribe($key, $handler, $params);
122
123
        return $this;
124
    }
125
126
    /**
127
     * Change current system working environment or receive
128
     * current system enviroment if no arguments are passed.
129
     *
130
     * @param string $environment Environment identifier
131
     *
132
     * TODO: Function has two different logics - needs to be changed!
133
     * @return $this|string Chaining or current system environment
134
     */
135
    public function environment($environment = Scheme::BASE)
136
    {
137
        if (func_num_args() !== 0) {
138
            $this->environment = $environment;
139
140
            // Signal core environment change
141
            Event::signal('core.environment.change', array($environment, &$this));
142
            return $this;
143
        }
144
145
        return $this->environment;
146
    }
147
148
    /**
149
     * Generate special response header triggering caching mechanisms
150
     * @param int $cacheLife Amount of seconds for cache(default 3600 - 1 hour)
151
     * @param string $accessibility Cache-control accessibility value(default public)
152
     */
153
    public function cached($cacheLife = 3600, $accessibility = 'public')
154
    {
155
        static $cached;
156
        // Protect sending cached headers once
157
        if (!isset($cached) or $cached !== true) {
158
            header('Expires: ' . gmdate('D, d M Y H:i:s T', time() + $cacheLife));
159
            header('Cache-Control: ' . $accessibility . ', max-age=' . $cacheLife);
160
            header('Pragma: cache');
161
162
            $cached = true;
163
        }
164
    }
165
166
    /**
167
     * Set asynchronous mode.
168
     * This mode will not output template and will just path everything that
169
     * was outputted to client.
170
     *
171
     * @param bool $async True to switch to asynchronous output mode
172
     *
173
     * @return $this Chaining
174
     */
175
    public function async($async)
176
    {
177
        $this->async = $async;
178
179
        return $this;
180
    }
181
182
    /** @see iCore::path() */
183
    public function path($path = null)
184
    {
185
        // Если передан аргумент
186
        if (func_num_args()) {
187
            // Сформируем новый относительный путь к главному шаблону системы
188
            $this->template_path = $path . $this->template_path;
189
190
            // Сохраним относительный путь к Веб-приложению
191
            $this->system_path = $path;
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$system_path has been deprecated with message: @var string Path to current web-application

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
192
193
            // Продолжил цепирование
194
            return $this;
195
        }
196
197
        // Вернем текущее значение
198
        return $this->system_path;
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$system_path has been deprecated with message: @var string Path to current web-application

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
199
    }
200
201
    /**    @see iModule::active() */
202
    public function &active(&$module = null)
203
    {
204
        // Сохраним старый текущий модуль
205
        $old = &$this->active;
206
207
        // Если передано значение модуля для установки как текущий - проверим и установим его
208
        if (isset($module)) {
209
            $this->active = &$module;
210
        }
211
212
        // Вернем значение текущего модуля
213
        return $old;
214
    }
215
216
    /**
217
     * Retrieve module instance by identifier.
218
     *
219
     * @param string|null $module Module identifier
220
     *
221
     * @return null|Module Found or active module
222
     */
223
    public function &module($module = null)
224
    {
225
        $return = null;
226
227
        // Ничего не передано - вернем текущуй модуль системы
228
        if (!isset($module) && isset($this->active)) {
229
            $return = &$this->active;
230
        } elseif (is_object($module)) {
231
            $return = &$module;
232
        } elseif (is_string($module)) {
233
            $return = $this->container->get($module);
234
        }
235
236
        // Ничего не получилось вернем ошибку
237
        if ($return === null) {
238
            e('Не возможно получить модуль(##) системы', E_SAMSON_CORE_ERROR, array($module));
0 ignored issues
show
Deprecated Code introduced by
The function e() has been deprecated with message: Use custom exceptions

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
239
        }
240
241
        return $return;
242
    }
243
244
    /**
245
     * Unload module from core.
246
     *
247
     * @param string $moduleID Module identifier
248
     */
249
    public function unload($moduleID)
250
    {
251
        if (isset($this->module_stack[$moduleID])) {
0 ignored issues
show
Bug introduced by
The property module_stack does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
252
            unset($this->module_stack[$moduleID]);
253
        }
254
    }
255
256
    /**
257
     * Insert generic html template tags and data
258
     *
259
     * @param string $templateHtml Generated HTML
260
     *
261
     * @deprecated Must be moved to a new HTML output object
262
     * @return mixed Changed HTML template
263
     */
264 2
    public function generateTemplate(&$templateHtml)
265
    {
266
        // Добавим путь к ресурсам для браузера
267
        $headHtml = "\n" . '<base href="' . url()->base() . '">';
268
        // Добавим отметку времени для JavaScript
269
        $headHtml .= "\n" . '<script type="text/javascript">var __SAMSONPHP_STARTED = new Date().getTime();</script>';
270
271 2
        // Добавим поддержку HTML для старых IE
272
        $headHtml .= "\n" . '<!--[if lt IE 9]>';
273
        $headHtml .= "\n" . '<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>';
274 2
        $headHtml .= "\n" . '<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>';
275
        $headHtml .= "\n" . '<![endif]-->';
276
277
        // Выполним вставку главного тега <base> от которого зависят все ссылки документа
278 2
        // также подставим МЕТА-теги для текущего модуля и сгенерированный минифицированный CSS
279
        $templateHtml = str_ireplace('<head>', '<head>' . $headHtml, $templateHtml);
280 2
281
        // Вставим указатель JavaScript ресурсы в конец HTML документа
282 2
        $templateHtml = str_ireplace('</html>', '</html>' . __SAMSON_COPYRIGHT, $templateHtml);
283 2
284
        return $templateHtml;
285
    }
286 2
287
    /**
288 2
     * Start SamsonPHP framework.
289
     *
290 2
     * @param string $default Default module identifier
291
     *
292
     * @throws ViewPathNotFound
293
     */
294
    public function start($default)
295 2
    {
296
        // TODO: Change ExternalModule::init() signature
297
        // Fire core started event
298
        Event::fire('core.started');
299
300
        // TODO: Does not see why it should be here
301
        // Set main template path
302
        $this->template($this->template_path);
303
304
        // Security layer
305
        $securityResult = true;
306
        // Fire core security event
307
        Event::fire('core.security', array(&$this, &$securityResult));
308
309
        /** @var mixed $result External route controller action result */
310
        $result = false;
311
312
        // If we have passed security application layer
313
        if ($securityResult) {
314
            // Fire core routing event - go to routing application layer
315
            Event::signal('core.routing', array(&$this, &$result, $default));
316
        }
317
318
        // If no one has passed back routing callback
319
        if (!isset($result) || $result === false) {
320 2
            // Fire core e404 - routing failed event
321
            $result = Event::signal('core.e404', array(url()->module, url()->method));
322
        }
323 2
324
        // Response
325
        $output = '';
326 2
327
        // If this is not asynchronous response and controller has been executed
328
        if (!$this->async && ($result !== false)) {
329 2
            // Store module data
330
            $data = $this->active->toView();
331
332 2
            // Render main template
333
            $output = $this->render($this->template_path, $data);
334
335 2
            // Fire after render event
336
            Event::fire('core.rendered', array(&$output));
337
        }
338 2
339
        // Output results to client
340
        echo $output;
341
342
        // Fire ended event
343
        Event::fire('core.ended', array(&$output));
344
    }
345
346
    /**	@see iCore::template() */
347
    public function template( $template = NULL, $absolutePath = false )
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces between opening bracket and argument "$template"; 1 found
Loading history...
Coding Style introduced by
TRUE, FALSE and NULL must be lowercase; expected null, but found NULL.
Loading history...
Coding Style introduced by
Expected 0 spaces between argument "$absolutePath" and closing bracket; 1 found
Loading history...
348
    {
349
        // Если передан аргумент
350
        if( func_num_args() ){
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
Coding Style introduced by
Expected 0 spaces before closing bracket; 1 found
Loading history...
351
            $this->template_path = ($absolutePath)?$template:$this->active->path().$template;
352 7
        }
353
354 7
        // Аргументы не переданы - вернем текущий путь к шаблону системы
355
        return $this->template_path;
356 7
    }
357
358
    /**
359
     * Render file to a buffer.
360
     *
361
     * @param string $view Path to file
362
     * @param array  $data Collection of variables to path to file
363
     *
364
     * @return string Rendered file contents
365
     * @throws ViewPathNotFound
366
     */
367
    public function render($view, $data = array())
368
    {
369
        // TODO: Make rendering as external system, to split up these 3 rendering options
370
371
        // Объявить ассоциативный массив переменных в данном контексте
372
        if (is_array($data)) {
373
            extract($data);
374
        }
375
376
        // Начать вывод в буффер
377
        ob_start();
378
379
        // Path to another template view, by default we are using default template folder path,
380
        // for meeting first condition
381
        $templateView = $view;
382
383
        if (locale() != SamsonLocale::DEF) {
384
            // Modify standard view path with another template
385
            $templateView = str_replace(__SAMSON_VIEW_PATH, __SAMSON_VIEW_PATH . locale() . '/', $templateView);
386
        }
387
388
        // Depending on core view rendering model
389
        switch ($this->render_mode) {
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$render_mode has been deprecated with message: @var string View path loading mode

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
390
            // Standard algorithm for view rendering
391
            case self::RENDER_STANDART:
0 ignored issues
show
Deprecated Code introduced by
The constant samson\core\Core::RENDER_STANDART has been deprecated with message: Standard algorithm for view rendering

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
392
                // Trying to find another template path, by default it's an default template path
393
                if (file_exists($templateView)) {
394
                    include($templateView);
395
                } elseif (file_exists($view)) {
396
                    // If another template wasn't found - we will use default template path
397
                    include($view);
398
                } else { // Error no template view was found
399
                    throw(new ViewPathNotFound($view));
400
                }
401
                break;
402
403 2
            // View rendering algorithm from array of view variables
404
            case self::RENDER_VARIABLE:
0 ignored issues
show
Deprecated Code introduced by
The constant samson\core\Core::RENDER_VARIABLE has been deprecated with message: View rendering algorithm from array of view variables

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
405
                // Collection of views
406 2
                $views = &$GLOBALS['__compressor_files'];
407
                // Trying to find another template path, by default it's an default template path
408
                if (isset($views[$templateView])) {
409 2
                    eval(' ?>' . $views[$templateView] . '<?php ');
410 2
                } elseif (isset($views[$view])) {
411 2
                    // If another template wasn't found - we will use default template path
412
                    eval(' ?>' . $views[$view] . '<?php ');
413
                } else { // Error no template view was found
414 2
                    throw(new ViewPathNotFound($view));
415
                }
416
                break;
417
        }
418
419
        // Получим данные из буффера вывода
420
        $html = ob_get_contents();
421
422
        // Очистим буффер
423
        ob_end_clean();
424
425
        // Fire core render event
426
        Event::fire('core.render', array(&$html, &$data, &$this->active));
427
428
        ////elapsed('End rendering '.$__view);
429
        return $html;
430
    }
431
432
    //[PHPCOMPRESSOR(remove,start)]
433
434
    /**
435
     * Load system from composer.json
436
     * @param string $dependencyFilePath Path to dependencies file
437
     * @return $this Chaining
438
     */
439
    public function composer($dependencyFilePath = null)
440
    {
441
        $composerModules = array();
442
443
        Event::fire(
444
            'core.composer.create',
445
            array(
446
                &$composerModules,
447
                isset($dependencyFilePath) ? $dependencyFilePath : $this->system_path,
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$system_path has been deprecated with message: @var string Path to current web-application

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
448
                array(
449
                    'vendorsList' => array('samsonphp/', 'samsonos/', 'samsoncms/', 'samsonjavascript/'),
450
                    'ignoreKey' => 'samson_module_ignore',
451
                    'includeKey' => 'samson_module_include'
452
                )
453
            )
454
        );
455
456
        $modulesToLoad = [];
457
458
        // Iterate requirements
459
        foreach ($composerModules as $requirement => $parameters) {
460
            $moduleName = $this->load(__SAMSON_CWD__ . __SAMSON_VENDOR_PATH . $requirement,
461
            array_merge(
462
                is_array($parameters) ? $parameters : array($parameters),
463
                array('module_id' => $requirement)
464
            ));
465
466
            $modulesToLoad[$moduleName] = $parameters;
467
        }
468
469
        $localModulesPath = '../src';
470
        ResourceMap::get('cache');
471
        // TODO: Nested modules relation
472
        for ($i = 0; $i < 2; $i++) {
473
            $resourceMap = ResourceMap::get($localModulesPath);
474
475
            foreach ($resourceMap->modules as $moduleFile) {
476
                $modulePath = str_replace(realpath($localModulesPath), '', $moduleFile[1]);
477
                $modulePath = explode('/', $modulePath);
478
                $modulePath = $localModulesPath . '/' . $modulePath[1];
479
                $moduleName = $this->load($modulePath, $parameters);
0 ignored issues
show
Bug introduced by
The variable $parameters seems to be defined by a foreach iteration on line 459. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
480
                $modulesToLoad[$moduleName] = $parameters;
481
            }
482
        }
483
484
        //$this->active = new VirtualModule($this->system_path, $this->map, $this, 'local');
485
486
        // Create local module and set it as active
487
        $this->createMetadata(VirtualModule::class, 'local', $this->system_path);
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$system_path has been deprecated with message: @var string Path to current web-application

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
488
489
        // TODO: This should be changed to one single logic
490
        // Require all local module model files
491
        foreach ($this->map->models as $model) {
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$map has been deprecated with message: @var ResourceMap Current web-application resource map

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
492
            // TODO: Why have to require once?
493
            require_once($model);
494
        }
495
496
        // Create all local modules
497
        foreach ($this->map->controllers as $controller) {
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$map has been deprecated with message: @var ResourceMap Current web-application resource map

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
498
            // Require class into PHP
499
            require($controller);
500
501
            //new VirtualModule($this->system_path, $this->map, $this, basename($controller, '.php'));
502
503
            $this->createMetadata(VirtualModule::class, basename($controller, '.php'), $this->system_path);
0 ignored issues
show
Deprecated Code introduced by
The property samson\core\Core::$system_path has been deprecated with message: @var string Path to current web-application

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
504
        }
505
506
        $metadata = new ClassMetadata();
507
        $metadata->className = get_class($this);
508
        $metadata->name = 'core';
509
        $metadata->scopes[] = Builder::SCOPE_SERVICES;
510
        $metadata->methodsMetadata['__construct'] = new MethodMetadata($metadata);
511
        $metadata->methodsMetadata['__construct']->dependencies['map'] = ResourceMap::class;
512
513
        $this->metadataCollection[$metadata->name] = $metadata;
514
515
        $metadata = new ClassMetadata();
516
        $metadata->className = ResourceMap::class;
517
        $metadata->name = 'resource_map';
518
        $metadata->scopes[] = Builder::SCOPE_SERVICES;
519
520
        $this->metadataCollection[$metadata->name] = $metadata;
521
522
        // Load annotations
523
        $classes = [];
524
        foreach ($this->metadataCollection as $alias => $metadata) {
525
            $classes[$alias] = $metadata->className;
526
        }
527
528
        // Load annotation and parse classes
529
        new Injectable();
530
        new InjectArgument(['var' => 'type']);
531
532
        $reader = new AnnotationReader();
533
        $resolver = new AnnotationResolver(
534
            new AnnotationClassResolver($reader),
535
            new AnnotationPropertyResolver($reader),
536
            new AnnotationMethodResolver($reader)
537
        );
538
        $annotationCollector = new AnnotationMetadataCollector($resolver);
539
        $this->metadataCollection = $annotationCollector->collect($classes, $this->metadataCollection);
540
541
        $i18nProperties = $this->metadataCollection['security']->propertiesMetadata['i18n'];
0 ignored issues
show
Unused Code introduced by
$i18nProperties is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
542
543
        // Gather all interface implementations
544
        $implementsByAlias = [];
545
        foreach (get_declared_interfaces() as $interface) {
546
            foreach (get_declared_classes() as $class) {
547
                if (in_array($interface, class_implements($class), true)) {
548
                    // TODO: We should already have metadata by classname collection
549
                    foreach ($this->metadataCollection as $alias => $metadata) {
550
                        if ($metadata->className === $class) {
551
                            $implementsByAlias['\\'.$interface][] = $alias;
552
                            break;
553
                        }
554
                    }
555
                }
556
            }
557
        }
558 7
559
        /**
560
         * TODO: now we need to implement not forcing to load fixed dependencies into modules
561 7
         * to give ability to change constructors and inject old variable into properties
562
         * and them after refactoring remove them. With this we can only specify needed dependencies
563
         * in new modules, and still have old ones working.
564 7
         */
565
566
        foreach ($this->metadataCollection as $alias => $metadata) {
567 7
            foreach ($metadata->propertiesMetadata as $property => $propertyMetadata) {
568
                if (array_key_exists($propertyMetadata->dependency, $implementsByAlias)) {
569
                    $propertyMetadata->dependency = $implementsByAlias[$propertyMetadata->dependency][0];
570 7
                }
571
            }
572
            foreach ($metadata->methodsMetadata as $method => $methodMetadata) {
573 7
                foreach ($methodMetadata->dependencies as $argument => $dependency) {
574
                    if (array_key_exists($dependency, $implementsByAlias)) {
575
                        $methodMetadata->dependencies[$argument] = $implementsByAlias[$dependency][0];
576 7
                    }
577 7
                }
578
            }
579
        }
580
581
        // Load container class
582
        $containerPath = $this->path().'www/cache/Container.php';
583
        file_put_contents($containerPath, $this->builder->build($this->metadataCollection));
584
        require_once($containerPath);
585
586
        // Inject current core into container
587
        $this->container = new \Container();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Container() of type object<Container> is incompatible with the declared type object<samsonframework\di\ContainerInterface> of property $container.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
588
        $containerReflection = new \ReflectionClass(get_class($this->container));
589
        $serviceProperty = $containerReflection->getProperty(Builder::DI_FUNCTION_SERVICES);
590
        $serviceProperty->setAccessible(true);
591
        $containerServices = $serviceProperty->getValue($this->container);
592
        $containerServices['core'] = $this;
593
        $serviceProperty->setValue($this->container, $containerServices);
594
        $serviceProperty->setAccessible(false);
595
596
        foreach ($modulesToLoad as $name => $parameters) {
597
            $instance = $this->container->get($name);
598
599
            $identifier = $instance->id();
600
601
            // Set composer parameters
602
            $instance->composerParameters = $parameters;
603
604
            // TODO: Change event signature to single approach
605
            // Fire core module load event
606
            Event::fire('core.module_loaded', [$identifier, &$instance]);
607
608
            // Signal core module configure event
609
            Event::signal('core.module.configure', [&$instance, $identifier]);
610
611
            // Call module preparation handler
612
            if (!$instance->prepare()) {
613
                // Handle module failed preparing
614
            }
615
616
            // Trying to find parent class for connecting to it to use View/Controller inheritance
617
            $parentClass = get_parent_class($instance);
618
            if (!in_array($parentClass, [ExternalModule::class, CompressableExternalModule::class, Service::class, CompressableService::class], true)) {
619
                // Переберем загруженные в систему модули
620
                foreach ($this->getContainer()->getServices('module') as $m) {
621
                    // Если в систему был загружен модуль с родительским классом
622
                    if (get_class($m) === $parentClass) {
623
                        $instance->parent = $m;
624
                        //elapsed('Parent connection for '.$moduleClass.'('.$connector->uid.') with '.$parent_class.'('.$m->uid.')');
625
                    }
626
                }
627
            }
628
        }
629
630
631
        $this->active = $this->container->getLocal();
632
633
        return $this;
634
    }
635
636
    /**
637
     * Load module from path to core.
638
     *
639
     * @param string $path       Path for module loading
640
     * @param array  $parameters Collection of loading parameters
641
     *
642
     * @return string module name
643
     * @throws \samsonphp\core\exception\CannotLoadModule
644
     */
645
    public function load($path, $parameters = array())
646
    {
647
        $name = '';
648
        // Check path
649
        if (file_exists($path)) {
650
            /** @var ResourceMap $resourceMap Gather all resources from path */
651
            $resourceMap = ResourceMap::get($path);
652
            if (isset($resourceMap->module[0])) {
653
654
                /** @var string $controllerPath Path to module controller file */
655
                $controllerPath = $resourceMap->module[1];
656
657
                /** @var string $moduleClass Name of module controller class to load */
658
                $moduleClass = $resourceMap->module[0];
659
660
                // Require module controller class into PHP
661
                if (file_exists($controllerPath)) {
662
                    require_once($controllerPath);
663
                }
664
665
                // TODO: this should be done via composer autoload file field
666
                // Iterate all function-style controllers and require them
667
                foreach ($resourceMap->controllers as $controller) {
668
                    require_once($controller);
669
                }
670
671
                $reflection = new \ReflectionClass($moduleClass);
672
                $name = $reflection->getDefaultProperties();
673
                $name = $this->createMetadata($moduleClass, $name['id'] ?? $moduleClass, $path);
674
675
                /*$this->initModule(
676
                    new $moduleClass($path, $resourceMap, $this),
677
                    $parameters
678
                );*/
679
            } elseif (is_array($parameters) && isset($parameters['samsonphp_package_compressable']) && ($parameters['samsonphp_package_compressable'] == 1)) {
680
                $name = $this->createMetadata(VirtualModule::class, $parameters['module_id'], $path);
681
682
                /*$this->initModule(
683
                    new VirtualModule($path, $resourceMap, $this, str_replace('/', '', $parameters['module_id'])),
684
                    $parameters
685
                );*/
686
            }
687
//            elseif (count($resourceMap->classes)) {
688
//                /** Update for future version: Search classes that implement LoadableInterface */
689
//                foreach ($resourceMap->classes as $classPath => $class) {
690
//                    // This class implements LoadableInterface LoadableInterface::class
691
//                    if (in_array('\samsonframework\core\LoadableInterface', $resourceMap->classData[$classPath]['implements'])) {
692
//
693
//                        $name =  str_replace('/', '', $parameters['module_id']);
694
//
695
//                        $this->createMetadata(VirtualModule::class, str_replace('/', '', $parameters['module_id']), $path);
696
//
697
//                        /*$this->initModule(
698
//                            new VirtualModule(
699
//                                $path,
700
//                                $resourceMap,
701
//                                $this,
702
//                                str_replace('/', '', $resourceMap->classData[$classPath]['className'])
703
//                            ),
704
//                            $parameters
705
//                        );*/
706
//                    }
707
//                }
708
//            }
709
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
710
        } else {
711
            throw new CannotLoadModule($path);
712
        }
713
714
        return $name;
715
    }
716
    //[PHPCOMPRESSOR(remove,end)]
717
718
    /** Магический метод для десериализации объекта */
719
    public function __wakeup()
720
    {
721
        $this->active = &$this->module_stack['local'];
722
    }
723
724
    /** Магический метод для сериализации объекта */
725
    public function __sleep()
726
    {
727
        return array('module_stack', 'render_mode');
728
    }
729
730
    protected function createMetadata($class, $name, $path, $scope = 'module')
731
    {
732
        $metadata = new ClassMetadata();
733
        $class = ltrim($class, '\\');
734
        $name = strtolower(ltrim($name, '\\'));
735
        $metadata->className = $class;
736
        $metadata->name = str_replace(['\\', '/'], '_', $name ?? $class);
737
        $metadata->scopes[] = Builder::SCOPE_SERVICES;
738
        $metadata->scopes[] = $scope;
739
        $metadata->propertiesMetadata['system'] = new PropertyMetadata($metadata);
740
        $metadata->propertiesMetadata['system']->dependency = 'core';
741
        $metadata->propertiesMetadata['resourceMap'] = new PropertyMetadata($metadata);
742
        $metadata->propertiesMetadata['resourceMap']->dependency = 'resource_map';
743
744
        // TODO: Now we need to remove and change constructors
745
        $metadata->methodsMetadata['__construct'] = new MethodMetadata($metadata);
746
        $metadata->methodsMetadata['__construct']->dependencies['path'] = $path;
747
        $metadata->methodsMetadata['__construct']->dependencies['resources'] = 'resource_map';
748
        $metadata->methodsMetadata['__construct']->dependencies['system'] = 'core';
749
750
        $this->metadataCollection[$metadata->name] = $metadata;
751
752
        return $metadata->name;
753
    }
754
}
755