Completed
Push — master ( 14f560...15f305 )
by
unknown
08:01
created

CoreLoader::init()   D

Complexity

Conditions 13
Paths 5

Size

Total Lines 112
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 67
c 0
b 0
f 0
nc 5
nop 0
dl 0
loc 112
rs 4.9922

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace samsonphp\core\loader;
4
5
use Doctrine\Common\Annotations\AnnotationReader;
6
use samson\activerecord\dbMySQLConnector;
7
use samson\core\CompressableExternalModule;
8
use samson\core\CompressableService;
9
use samson\core\Core;
10
use samson\core\ExternalModule;
11
use samson\core\VirtualModule;
12
use samsonframework\container\definition\analyzer\annotation\annotation\InjectClass;
13
use samsonframework\container\definition\analyzer\annotation\annotation\InjectParameter;
14
use samsonframework\container\definition\analyzer\annotation\annotation\InjectService;
15
use samsonframework\container\definition\analyzer\annotation\annotation\Service;
16
use samsonframework\container\definition\analyzer\annotation\AnnotationClassAnalyzer;
17
use samsonframework\container\definition\analyzer\annotation\AnnotationMethodAnalyzer;
18
use samsonframework\container\definition\analyzer\annotation\AnnotationPropertyAnalyzer;
19
use samsonframework\container\definition\analyzer\DefinitionAnalyzer;
20
use samsonframework\container\definition\analyzer\reflection\ReflectionClassAnalyzer;
21
use samsonframework\container\definition\analyzer\reflection\ReflectionMethodAnalyzer;
22
use samsonframework\container\definition\analyzer\reflection\ReflectionParameterAnalyzer;
23
use samsonframework\container\definition\analyzer\reflection\ReflectionPropertyAnalyzer;
24
use samsonframework\container\definition\builder\DefinitionBuilder;
25
use samsonframework\container\definition\builder\DefinitionCompiler;
26
use samsonframework\container\definition\builder\DefinitionGenerator;
27
use samsonframework\container\definition\ClassDefinition;
28
use samsonframework\container\definition\exception\MethodDefinitionAlreadyExistsException;
29
use samsonframework\container\definition\parameter\ParameterBuilder;
30
use samsonframework\container\definition\reference\ClassReference;
31
use samsonframework\container\definition\reference\ServiceReference;
32
use samsonframework\container\definition\reference\StringReference;
33
use samsonframework\container\definition\resolver\xml\XmlResolver;
34
use samsonframework\container\definition\scope\ModuleScope;
35
use samsonframework\container\definition\scope\ServiceScope;
36
use samsonframework\core\PreparableInterface;
37
use samsonframework\di\Container;
38
use samsonframework\generator\ClassGenerator;
39
use samsonframework\resource\ResourceMap;
40
use samsonphp\core\loader\module\Module;
41
use samsonphp\core\loader\module\ModuleManagerInterface;
42
use samsonphp\event\Event;
43
use samsonphp\i18n\i18n;
44
45
/**
46
 * Class CoreLoader
47
 *
48
 * @package samsonphp\container\loader
49
 */
50
class CoreLoader
51
{
52
    /** @var ModuleManagerInterface Module manager */
53
    protected $moduleManager;
54
    /** @var ContainerManager Container manager */
55
    public $containerManager;
56
57
    /**
58
     * CoreLoader constructor.
59
     *
60
     * @param ModuleManagerInterface $moduleManager
61
     * @param ContainerManager $containerManager
62
     */
63
    public function __construct(
64
        ModuleManagerInterface $moduleManager,
65
        ContainerManager $containerManager
66
    ) {
67
        $this->moduleManager = $moduleManager;
68
        $this->containerManager = $containerManager;
69
    }
70
71
    /**
72
     * Load modules
73
     *
74
     * @throws \Exception
75
     */
76
    public function init()
77
    {
78
        $containerPath = __DIR__ . '/../../../../../www/cache';
79
        $containerName = 'ContainerCore';
80
        $containerNamespace = 'samsonphp\core\loader';
81
        /** @var Module $module */
82
        $modules = $this->moduleManager->getRegisteredModules();
83
84
        $localModulesPath = '../src';
85
        ResourceMap::get('cache');
86
        $resourceMap = ResourceMap::get($localModulesPath);
87
        $localModules = $resourceMap->modules;
88
89
        if (false || !file_exists($containerPath . '/' . $containerName . '.php')) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
90
91
            $builder = new DefinitionBuilder(new ParameterBuilder());
92
            $xmlResolver = new XmlResolver();
93
            $xmlResolver->resolveFile($builder, __DIR__ . '/../../../../../app/config/config.xml');
94
95
            new Service('');
96
            new InjectService('');
97
            new InjectClass('');
98
            new InjectParameter('');
99
100
            foreach ($modules as $module) {
101
                if ($module->className && !$builder->hasDefinition($module->className)) {
102
                    // Fix samson.php files
103
                    if (!class_exists($module->className)) {
104
                        require_once($module->pathName);
105
                    }
106
                    /** @var ClassDefinition $classDefinition */
107
                    $classDefinition = $builder->addDefinition($module->className);
108
                    if ($id = $this->getModuleId($module->pathName)) {
109
                        $classDefinition->setServiceName($id);
110
                    } else {
111
                        // Generate identifier from module class
112
                        $classDefinition->setServiceName(
113
                            strtolower(ltrim(str_replace(__NS_SEPARATOR__, '_', $module->className), '_'))
114
                        );
115
                    }
116
                    $classDefinition->addScope(new ModuleScope())->setIsSingleton(true);
117
                    $this->defineConstructor($classDefinition, $module->path);
118
                }
119
            }
120
121
            $classDefinition = $builder->addDefinition(VirtualModule::class);
122
            $classDefinition->addScope(new ModuleScope())->setServiceName('local')->setIsSingleton(true);
123
            $this->defineConstructor($classDefinition, getcwd());
124
125
            foreach ($localModules as $moduleFile) {
126
                if (!$builder->hasDefinition($moduleFile[0])) {
127
128
                    /** @var ClassDefinition $classDefinition */
129
                    $classDefinition = $builder->addDefinition($moduleFile[0]);
130
                    $classDefinition->addScope(new ModuleScope());
131
                    $classDefinition->setIsSingleton(true);
132
                    if ($id = $this->getModuleId($moduleFile[1])) {
133
                        $classDefinition->setServiceName($id);
134
                    } else {
135
                        throw new \Exception('Can not get id of local module');
136
                    }
137
138
                    $modulePath = explode('/', str_replace(realpath($localModulesPath), '', $moduleFile[1]));
139
                    $this->defineConstructor($classDefinition, $localModulesPath . '/' . $modulePath[1]);
140
                }
141
            }
142
143
144
            /**
145
             * Add implementors
146
             */
147
            foreach ($this->moduleManager->implements as $interfaceName => $class) {
0 ignored issues
show
Bug introduced by
Accessing implements on the interface samsonphp\core\loader\mo...\ModuleManagerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
148
                $builder->defineImplementors($interfaceName, new ClassReference($class));
149
            }
150
151
            // Init compiler
152
            $reader = new AnnotationReader();
153
            $compiler = new DefinitionCompiler(
154
                new DefinitionGenerator(new ClassGenerator()),
155
                (new DefinitionAnalyzer())
156
                    ->addClassAnalyzer(new AnnotationClassAnalyzer($reader))
157
                    ->addClassAnalyzer(new ReflectionClassAnalyzer())
158
                    ->addMethodAnalyzer(new AnnotationMethodAnalyzer($reader))
159
                    ->addMethodAnalyzer(new ReflectionMethodAnalyzer())
160
                    ->addPropertyAnalyzer(new AnnotationPropertyAnalyzer($reader))
161
                    ->addPropertyAnalyzer(new ReflectionPropertyAnalyzer())
162
                    ->addParameterAnalyzer(new ReflectionParameterAnalyzer())
163
            );
164
165
            $container = $compiler->compile($builder, $containerName, $containerNamespace, $containerPath);
166
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
167
        } else {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
168
169
            $containerClassName = $containerNamespace. '\\' . $containerName;
170
            require_once($containerPath . '/' . $containerName . '.php');
171
            $container = new $containerClassName();
172
        }
173
174
        $GLOBALS['__core'] = $container->get('core');
175
176
        $this->prepareModules($modules, $container);
177
178
        /** @var array $module */
179
        foreach ($localModules as $module) {
180
            $instance = $container->get($module[0]);
181
            $instance->parent = $this->getClassParentModule($container, get_parent_class($instance));
182
        }
183
184
//        $container->get('core')->active($container->get('local'));
185
186
        return $container;
187
    }
188
189
    /**
190
     * Prepare modules
191
     *
192
     * @param array $modules
193
     * @param $container
194
     */
195
    protected function prepareModules(array $modules, $container)
196
    {
197
        foreach ($modules as $module) {
198
            $identifier = $module->name;
199
            if ($module->className) {
200
                // Fix samson.php files
201
                if (!class_exists($module->className)) {
202
                    require_once($module->pathName);
203
                }
204
                $instance = $container->get($module->className);
205
            } else {
206
                continue;
207
            }
208
209
            // Set composer parameters
210
            $instance->composerParameters = $module->composerParameters;
211
212
            // TODO: Change event signature to single approach
213
            // Fire core module load event
214
            Event::fire('core.module_loaded', [$identifier, &$instance]);
215
216
            // Signal core module configure event
217
            Event::signal('core.module.configure', [&$instance, $identifier]);
218
219
            if ($instance instanceof PreparableInterface) {
220
                // Call module preparation handler
221
                if (!$instance->prepare()) {
222
//                    throw new \Exception($identifier.' - Module preparation stage failed');
223
                }
224
            }
225
226
            $instance->parent = $this->getClassParentModule($container, get_parent_class($instance));
227
        }
228
    }
229
230
    /**
231
     * Define constructor
232
     *
233
     * @param ClassDefinition $classDefinition
234
     * @param $path
235
     * @throws MethodDefinitionAlreadyExistsException
236
     */
237
    protected function defineConstructor(ClassDefinition $classDefinition, $path)
238
    {
239
        $classDefinition->defineConstructor()
240
            ->defineParameter('path')
241
                ->defineDependency(new StringReference($path))
242
            ->end()
243
        ->end();
244
    }
245
246
    /**
247
     * Get module id
248
     *
249
     * @param $filePath
250
     * @return string|bool
251
     */
252
    protected function getModuleId($filePath)
253
    {
254
        preg_match(
255
            '/.*(protected|public|private)\s\$id\s=\s(\'|\")(?P<id>.*)(\'|\")\;.*/',
256
            file_get_contents($filePath),
257
            $matches
258
        );
259
260
        if (array_key_exists('id', $matches) && isset($matches['id']{0})) {
261
            return $matches['id'];
262
        } else {
263
            return false;
264
        }
265
    }
266
267
    /**
268
     * Find parent module by OOP class inheritance.
269
     *
270
     * @param string $className Class name for searching parent modules
271
     * @param array  $ignoredClasses Collection of ignored classes
272
     *
273
     * @return null|mixed Parent service instance if present
274
     */
275
    protected function getClassParentModule(
276
        Container $container,
277
        $className,
278
        array $ignoredClasses = [
279
            ExternalModule::class,
280
            CompressableExternalModule::class,
281
            \samson\core\Service::class,
282
            CompressableService::class
283
        ]
284
    ) {
285
        // Skip ignored class names
286
        if (!in_array($className, $ignoredClasses, true)) {
287
            try {
288
                $instance = $container->get(trim($className));
289
                $instance->parent = $this->getClassParentModule($container, get_parent_class($instance));
290
                return $instance;
291
            } catch (\Exception $exception) {
292
                return null;
293
            }
294
//            // Iterate loaded services
295
//            foreach ($container->getServices('module') as $service) {
296
//                if (get_class($service) === $className) {
297
//                    return $service;
298
//                }
299
//            }
300
        }
301
        return null;
302
    }
303
}
304