Provider   F
last analyzed

Complexity

Total Complexity 67

Size/Duplication

Total Lines 607
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 7
Bugs 0 Features 0
Metric Value
eloc 124
c 7
b 0
f 0
dl 0
loc 607
ccs 0
cts 181
cp 0
rs 3.04
wmc 67

27 Methods

Rating   Name   Duplication   Size   Complexity  
A postStartup() 0 2 1
A getReflectionClassForObject() 0 3 1
A getIdentifier() 0 3 1
A getInitialContext() 0 3 1
A getReflectionClass() 0 10 2
A getAttribute() 0 2 1
A setReflectionClass() 0 3 1
A injectApplication() 0 3 1
A injectReflectionClasses() 0 3 1
A getApplication() 0 3 1
A injectNamingDirectoryAliases() 0 3 1
A newAnnotationInstance() 0 3 1
A getNamingDirectory() 0 3 1
A injectDependencies() 0 29 5
A exists() 0 3 1
A createInstance() 0 28 4
A has() 0 11 3
A loadDependenciesByMethodInvocation() 0 13 2
A newInstance() 0 16 4
B loadDependencies() 0 44 8
A stop() 0 2 1
A newReflectionClass() 0 3 1
C get() 0 87 13
A loadDependenciesByReflectionMethod() 0 27 4
A set() 0 10 2
A initialize() 0 3 1
A loadDependency() 0 28 4

How to fix   Complexity   

Complex Class

Complex classes like Provider often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Provider, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * \AppserverIo\Appserver\DependencyInjectionContainer\Provider
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2015 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/appserver-io/appserver
18
 * @link      http://www.appserver.io
19
 */
20
21
namespace AppserverIo\Appserver\DependencyInjectionContainer;
22
23
use AppserverIo\Storage\GenericStackable;
24
use AppserverIo\Lang\Reflection\ClassInterface;
25
use AppserverIo\Lang\Reflection\ReflectionClass;
26
use AppserverIo\Lang\Reflection\ReflectionMethod;
27
use AppserverIo\Lang\Reflection\AnnotationInterface;
28
use AppserverIo\Appserver\Core\Environment;
29
use AppserverIo\Appserver\Core\Utilities\EnvironmentKeys;
30
use AppserverIo\Psr\Application\ApplicationInterface;
31
use AppserverIo\Psr\Deployment\DescriptorInterface;
32
use AppserverIo\Psr\Di\ProviderInterface;
33
use AppserverIo\Psr\Di\ObjectManagerInterface;
34
use AppserverIo\Psr\Di\DependencyInjectionException;
35
use AppserverIo\Psr\EnterpriseBeans\Description\ReferenceDescriptorInterface;
36
use AppserverIo\Psr\EnterpriseBeans\Description\BeanReferenceDescriptorInterface;
37
use AppserverIo\Psr\EnterpriseBeans\Description\NameAwareDescriptorInterface;
38
use AppserverIo\Psr\EnterpriseBeans\Description\FactoryAwareDescriptorInterface;
39
use AppserverIo\Psr\EnterpriseBeans\Description\MethodInvocationDescriptorInterface;
40
use AppserverIo\Psr\EnterpriseBeans\Description\MethodInvocationAwareDescriptorInterface;
41
42
/**
43
 * A basic dependency injection provider implementation.
44
 *
45
 * @author    Tim Wagner <[email protected]>
46
 * @copyright 2015 TechDivision GmbH <[email protected]>
47
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
48
 * @link      https://github.com/appserver-io/appserver
49
 * @link      http://www.appserver.io
50
 *
51
 * @property \AppserverIo\Psr\Naming\NamingDirectoryInterface $namingDirectory The applications naming directory interface
52
 * @property \AppserverIo\Psr\Application\ApplicationInterfac $application     The application instance
53
 * @property array                                            $dependencies    Dependencies for the actual injection target
54
 */
55
class Provider extends GenericStackable implements ProviderInterface
56
{
57
58
    /**
59
     * The managers unique identifier.
60
     *
61
     * @return string The unique identifier
62
     * @see \AppserverIo\Psr\Application\ManagerInterface::getIdentifier()
63
     */
64
    public function getIdentifier()
65
    {
66
        return ProviderInterface::IDENTIFIER;
67
    }
68
69
    /**
70
     * Lifecycle callback that'll be invoked after the application has been started.
71
     *
72
     * @param \AppserverIo\Psr\Application\ApplicationInterface $application The application instance
73
     *
74
     * @return void
75
     * @see \AppserverIo\Psr\Application\ManagerInterface::postStartup()
76
     */
77
    public function postStartup(ApplicationInterface $application)
78
    {
79
    }
80
81
    /**
82
     * Has been automatically invoked by the container after the application
83
     * instance has been created.
84
     *
85
     * @param \AppserverIo\Psr\Application\ApplicationInterface $application The application instance
86
     *
87
     * @return void
88
     * @see \AppserverIo\Psr\Application\ManagerInterface::initialize()
89
     */
90
    public function initialize(ApplicationInterface $application)
91
    {
92
        $this->dependencies = array();
93
    }
94
95
    /**
96
     * Returns the value with the passed name from the context.
97
     *
98
     * @param string $key The key of the value to return from the context.
99
     *
100
     * @return mixed The requested attribute
101
     */
102
    public function getAttribute($key)
103
    {
104
        // not yet implemented
105
    }
106
107
    /**
108
     * Injects the storage for the loaded reflection classes.
109
     *
110
     * @param \AppserverIo\Storage\GenericStackable $reflectionClasses The storage for the reflection classes
111
     *
112
     * @return void
113
     */
114
    public function injectReflectionClasses($reflectionClasses)
115
    {
116
        $this->reflectionClasses = $reflectionClasses;
0 ignored issues
show
Bug Best Practice introduced by
The property reflectionClasses does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
117
    }
118
119
    /**
120
     * Injects the naming directory aliases.
121
     *
122
     * @param \AppserverIo\Storage\GenericStackable $namingDirectoryAliases The naming directory aliases
123
     *
124
     * @return void
125
     */
126
    public function injectNamingDirectoryAliases($namingDirectoryAliases)
127
    {
128
        $this->namingDirectoryAliases = $namingDirectoryAliases;
0 ignored issues
show
Bug Best Practice introduced by
The property namingDirectoryAliases does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
129
    }
130
131
    /**
132
     * The application instance.
133
     *
134
     * @param \AppserverIo\Psr\Application\ApplicationInterface $application The application instance
135
     *
136
     * @return void
137
     */
138
    public function injectApplication(ApplicationInterface $application)
139
    {
140
        $this->application = $application;
0 ignored issues
show
Documentation Bug introduced by
It seems like $application of type AppserverIo\Psr\Application\ApplicationInterface is incompatible with the declared type AppserverIo\Psr\Application\ApplicationInterfac of property $application.

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...
141
    }
142
143
    /**
144
     * Returns the naming context instance.
145
     *
146
     * @return \AppserverIo\Psr\Naming\InitialContext The naming context instance
147
     */
148
    public function getInitialContext()
149
    {
150
        throw new \Exception(sprintf('%s not implemented yet', __METHOD__));
151
    }
152
153
    /**
154
     * Returns the application instance.
155
     *
156
     * @return \AppserverIo\Psr\Application\ApplicationInterface The application instance
157
     */
158
    public function getApplication()
159
    {
160
        return $this->application;
161
    }
162
163
    /**
164
     * Returns the applications naming directory.
165
     *
166
     * @return \AppserverIo\Psr\Naming\NamingDirectoryInterface The applications naming directory interface
167
     */
168
    public function getNamingDirectory()
169
    {
170
        return $this->getApplication()->getNamingDirectory();
0 ignored issues
show
Bug introduced by
The method getNamingDirectory() does not exist on AppserverIo\Psr\Application\ApplicationInterface. It seems like you code against a sub-type of AppserverIo\Psr\Application\ApplicationInterface such as AppserverIo\Appserver\Application\Application. ( Ignorable by Annotation )

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

170
        return $this->getApplication()->/** @scrutinizer ignore-call */ getNamingDirectory();
Loading history...
171
    }
172
173
    /**
174
     * Creates a new new instance of the annotation type, defined in the passed reflection annotation.
175
     *
176
     * @param \AppserverIo\Lang\Reflection\AnnotationInterface $annotation The reflection annotation we want to create the instance for
177
     *
178
     * @return \AppserverIo\Lang\Reflection\AnnotationInterface The real annotation instance
179
     */
180
    public function newAnnotationInstance(AnnotationInterface $annotation)
181
    {
182
        return $annotation->newInstance($annotation->getAnnotationName(), $annotation->getValues());
183
    }
184
185
    /**
186
     * Returns a reflection class instance for the passed class name.
187
     *
188
     * @param string $className The class name to return the reflection instance for
189
     *
190
     * @return \AppserverIo\Lang\Reflection\ReflectionClass The reflection instance
191
     */
192
    public function newReflectionClass($className)
193
    {
194
        return new ReflectionClass($className);
195
    }
196
197
    /**
198
     * Returns a new reflection class intance for the passed class name.
199
     *
200
     * @param string $className The class name to return the reflection class instance for
201
     *
202
     * @return \AppserverIo\Lang\Reflection\ReflectionClass The reflection instance
203
     */
204
    public function getReflectionClass($className)
205
    {
206
207
        // check if we've already initialized the reflection class
208
        if (isset($this->reflectionClasses[$className]) === false) {
209
            $this->reflectionClasses[$className] = $this->newReflectionClass($className);
0 ignored issues
show
Bug Best Practice introduced by
The property reflectionClasses does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
210
        }
211
212
        // return the reflection class instance
213
        return $this->reflectionClasses[$className];
214
    }
215
216
    /**
217
     * Returns a reflection class intance for the passed class name.
218
     *
219
     * @param object $instance The instance to return the reflection class instance for
220
     *
221
     * @return \AppserverIo\Lang\Reflection\ReflectionClass The reflection instance
222
     * @see \AppserverIo\Psr\Di\ProviderInterface::newReflectionClass()
223
     * @see \AppserverIo\Psr\Di\ProviderInterface::getReflectionClass()
224
     */
225
    public function getReflectionClassForObject($instance)
226
    {
227
        return $this->getReflectionClass(get_class($instance));
228
    }
229
230
    /**
231
     * Adds the passe reflection class instance to the DI provider.
232
     *
233
     * @param \AppserverIo\Lang\Reflection\ClassInterface $reflectionClass The reflection class instance to add
234
     *
235
     * @return void
236
     */
237
    public function setReflectionClass(ClassInterface $reflectionClass)
238
    {
239
        $this->reflectionClasses[$reflectionClass->getName()] = $reflectionClass;
0 ignored issues
show
Bug Best Practice introduced by
The property reflectionClasses does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
240
    }
241
242
    /**
243
     * Loads the dependencies for the passed object descriptor.
244
     *
245
     * @param \AppserverIo\Psr\EnterpriseBeans\Description\NameAwareDescriptorInterface $objectDescriptor The object descriptor to load the dependencies for
246
     *
247
     * @throws \AppserverIo\Psr\Di\DependencyInjectionException Is thrown, if the dependencies can not be loaded
248
     * @return array The array with the initialized dependencies
249
     */
250
    public function loadDependencies(NameAwareDescriptorInterface $objectDescriptor)
251
    {
252
253
        if ($objectDescriptor instanceof \AppserverIo\Description\FactoryDescriptor) {
254
            throw new \Exception(print_r($objectDescriptor, true));
255
        }
256
257
        // query whether or not the dependencies have been loaded
258
        if (isset($this->dependencies[$name = $objectDescriptor->getName()])) {
259
            return $this->dependencies[$name];
260
        }
261
262
        // initialize the array with the dependencies
263
        $dependencies = array('method' =>  array(), 'property' => array());
264
265
        // check for declared EPB and resource references
266
        /** @var \AppserverIo\Psr\EnterpriseBeans\Description\ReferenceDescriptorInterface $reference */
267
        foreach ($objectDescriptor->getReferences() as $reference) {
0 ignored issues
show
Bug introduced by
The method getReferences() does not exist on AppserverIo\Psr\Enterpri...wareDescriptorInterface. It seems like you code against a sub-type of AppserverIo\Psr\Enterpri...wareDescriptorInterface such as AppserverIo\Description\BeanDescriptor or AppserverIo\Description\EnterpriseBeanDescriptor or AppserverIo\Description\ServletDescriptor. ( Ignorable by Annotation )

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

267
        foreach ($objectDescriptor->/** @scrutinizer ignore-call */ getReferences() as $reference) {
Loading history...
268
            // check if we've a reflection target defined
269
            if ($injectionTarget = $reference->getInjectionTarget()) {
270
                // add the dependency to the array
271
                if ($targetName = $injectionTarget->getTargetProperty()) {
272
                    // append the property dependency
273
                    $dependencies['property'][$targetName] = $this->loadDependency($reference);
274
                } elseif ($targetName = $injectionTarget->getTargetMethod()) {
275
                    // prepare the array with the method dependencies
276
                    if (!isset($dependencies['method'][$targetName])) {
277
                        $dependencies['method'][$targetName] = array();
278
                    }
279
280
                    // append the method/constructor dependency
281
                    $dependencies['method'][$targetName][] = $this->loadDependency($reference);
282
283
                } else {
284
                    // throw an exception
285
                    throw new DependencyInjectionException(
286
                        sprintf('Can\'t find property or method %s in class "%s"', $targetName, $name)
287
                    );
288
                }
289
            }
290
        }
291
292
        // return the array with the loaded dependencies
293
        return $this->dependencies[$name] = $dependencies;
294
    }
295
296
    /**
297
     * Load's and return's the dependency instance for the passed reference.
298
     *
299
     * @param \AppserverIo\Psr\EnterpriseBeans\Description\ReferenceDescriptorInterface $referenceDescriptor The reference descriptor
300
     *
301
     * @return object The reference instance
302
     * @throws \Exception Is thrown, if no DI type definition for the passed reference is available
303
     */
304
    public function loadDependency(ReferenceDescriptorInterface $referenceDescriptor)
305
    {
306
307
        // load the session ID from the execution environment
308
        $sessionId = Environment::singleton()->getAttribute(EnvironmentKeys::SESSION_ID);
309
310
        // prepare the lookup name
311
        $lookupName = sprintf('php:global/%s/%s', $this->getApplication()->getUniqueName(), $referenceDescriptor->getRefName());
0 ignored issues
show
Bug introduced by
The method getRefName() does not exist on AppserverIo\Psr\Enterpri...enceDescriptorInterface. It seems like you code against a sub-type of said class. However, the method does not exist in AppserverIo\Psr\Enterpri...enceDescriptorInterface or AppserverIo\Psr\Enterpri...enceDescriptorInterface or AppserverIo\Psr\Enterpri...enceDescriptorInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

311
        $lookupName = sprintf('php:global/%s/%s', $this->getApplication()->getUniqueName(), $referenceDescriptor->/** @scrutinizer ignore-call */ getRefName());
Loading history...
Bug introduced by
The method getUniqueName() does not exist on AppserverIo\Psr\Application\ApplicationInterface. It seems like you code against a sub-type of AppserverIo\Psr\Application\ApplicationInterface such as AppserverIo\Appserver\Application\Application. ( Ignorable by Annotation )

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

311
        $lookupName = sprintf('php:global/%s/%s', $this->getApplication()->/** @scrutinizer ignore-call */ getUniqueName(), $referenceDescriptor->getRefName());
Loading history...
312
313
        // at least we need a type for instanciation, if we've a bean reference
314
        if ($referenceDescriptor instanceof BeanReferenceDescriptorInterface && $type = $referenceDescriptor->getType()) {
315
            // load the object manager instance
316
            /** @var \AppserverIo\Psr\Di\ObjectManagerInterface $objectManager */
317
            $objectManager = $this->getNamingDirectory()->search(
318
                sprintf('php:global/%s/%s', $this->getApplication()->getUniqueName(), ObjectManagerInterface::IDENTIFIER)
319
            );
320
321
            // try to directly instanciate the class by its defined type
322
            return $this->get($objectManager->getPreference($type), $sessionId);
0 ignored issues
show
Unused Code introduced by
The call to AppserverIo\Appserver\De...ntainer\Provider::get() has too many arguments starting with $sessionId. ( Ignorable by Annotation )

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

322
            return $this->/** @scrutinizer ignore-call */ get($objectManager->getPreference($type), $sessionId);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
323
        }
324
325
        // query if the instance is available, if yes load the instance by lookup the initial context
326
        if ($this->getNamingDirectory()->isBound($lookupName)) {
327
            return $this->getNamingDirectory()->search($lookupName, array($sessionId));
328
        }
329
330
        // throw an exception if the dependency can't be instanciated
331
        throw new \Exception(sprintf('Can\'t lookup bean "%s" nor find a DI type definition', $lookupName));
332
    }
333
334
    /**
335
     * Loads the dependencies for the passed reflection method.
336
     *
337
     * @param \AppserverIo\Lang\Reflection\ReflectionMethod $reflectionMethod The reflection method to load the dependencies for
338
     *
339
     * @return array The array with the initialized dependencies
340
     * @throws \Exception Is thrown, if no DI type definition for the passed reference is available
341
     */
342
    public function loadDependenciesByReflectionMethod(ReflectionMethod $reflectionMethod)
343
    {
344
345
        // initialize the array for the dependencies
346
        $dependencies = array();
347
348
        // load the object manager instance
349
        /** @var \AppserverIo\Psr\Di\ObjectManagerInterface $objectManager */
350
        $objectManager = $this->getNamingDirectory()->search(
351
            sprintf('php:global/%s/%s', $this->getApplication()->getUniqueName(), ObjectManagerInterface::IDENTIFIER)
352
        );
353
354
        // iterate over the constructor parameters
355
        /** @var \AppserverIo\Lang\Reflection\ParameterInterface $reflectionParameter */
356
        foreach ($reflectionMethod->getParameters() as $reflectionParameter) {
357
            // try to lookup the beans for the parameters
358
            if ($this->has($id = $objectManager->getPreference($reflectionParameter->getType()))) {
359
                $dependencies[] = $this->get($id);
360
            } elseif ($reflectionParameter->toPhpReflectionParameter()->allowsNull()) {
361
                continue;
362
            } else {
363
                throw new \Exception(sprintf('Can\'t lookup bean "%s" nor find a DI type definition', $id));
364
            }
365
        }
366
367
        // return the initialized dependencies
368
        return $dependencies;
369
    }
370
371
    /**
372
     * Loads the dependencies for the passed method invocation descriptor.
373
     *
374
     * @param \AppserverIo\Psr\EnterpriseBeans\Description\MethodInvocationDescriptorInterface $descriptor The descriptor to load the dependencies for
375
     *
376
     * @return array The array with the initialized dependencies
377
     */
378
    public function loadDependenciesByMethodInvocation(MethodInvocationDescriptorInterface $descriptor)
379
    {
380
381
        // initialize the array with the dependencies
382
        $dependencies = array();
383
384
        // load the dependencies from the DI provider
385
        foreach ($descriptor->getArguments() as $argument) {
386
            $dependencies[] = $this->get((string) $argument);
387
        }
388
389
        // return the dependencies
390
        return $dependencies;
391
    }
392
393
    /**
394
     * Creates a new instance with the dependencies defined by the passed descriptor.
395
     *
396
     * @param \AppserverIo\Psr\EnterpriseBeans\Description\NameAwareDescriptorInterface $objectDescriptor The object descriptor with the dependencies
397
     *
398
     * @return object The instance
399
     */
400
    public function createInstance(NameAwareDescriptorInterface $objectDescriptor)
401
    {
402
403
        // try to load the reflection class
404
        $reflectionClass = $this->getReflectionClass($objectDescriptor->getClassName());
0 ignored issues
show
Bug introduced by
The method getClassName() does not exist on AppserverIo\Psr\Enterpri...wareDescriptorInterface. It seems like you code against a sub-type of AppserverIo\Psr\Enterpri...wareDescriptorInterface such as AppserverIo\Psr\Enterpri...UnitDescriptorInterface or AppserverIo\Description\FactoryDescriptor or AppserverIo\Description\BeanDescriptor or AppserverIo\Description\EnterpriseBeanDescriptor or AppserverIo\Description\ServletDescriptor or AppserverIo\Description\PersistenceUnitDescriptor or AppserverIo\Ldap\Description\EntityDescriptor. ( Ignorable by Annotation )

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

404
        $reflectionClass = $this->getReflectionClass($objectDescriptor->/** @scrutinizer ignore-call */ getClassName());
Loading history...
405
406
        // load the dependencies for the passed descriptor
407
        $dependencies = $this->loadDependencies($objectDescriptor);
408
409
        // check if we've a constructor
410
        if ($reflectionClass->hasMethod($methodName = '__construct') &&
411
            $reflectionClass->getMethod($methodName)->getParameters()
412
        ) {
413
            // query whether or not constructor parameters are available
414
            if (isset($dependencies['method'][$methodName])) {
415
                // create a new instance and pass the constructor args
416
                return $reflectionClass->newInstanceArgs($dependencies['method'][$methodName]);
417
            }
418
        }
419
420
        // create a new instance
421
        $instance = $reflectionClass->newInstance();
422
423
        // inject the dependencies using properties/methods
424
        $this->injectDependencies($objectDescriptor, $instance);
425
426
        // return the initialized instance
427
        return $instance;
428
    }
429
430
    /**
431
     * Injects the dependencies of the passed instance defined in the object descriptor.
432
     *
433
     *
434
     * @param \AppserverIo\Psr\Deployment\DescriptorInterface $objectDescriptor The object descriptor with the dependencies
435
     * @param object                                          $instance         The instance to inject the dependencies for
436
     *
437
     * @return void
438
     */
439
    public function injectDependencies(DescriptorInterface $objectDescriptor, $instance)
440
    {
441
442
        // try to load the reflection class
443
        $reflectionClass = $this->getReflectionClass($objectDescriptor->getClassName());
0 ignored issues
show
Bug introduced by
The method getClassName() does not exist on AppserverIo\Psr\Deployment\DescriptorInterface. It seems like you code against a sub-type of AppserverIo\Psr\Deployment\DescriptorInterface such as AppserverIo\Ldap\Descrip...tityDescriptorInterface or AppserverIo\Ldap\Descrip...toryDescriptorInterface or AppserverIo\Description\PreferenceDescriptor or AppserverIo\Description\FactoryDescriptor or AppserverIo\Description\BeanDescriptor or AppserverIo\Description\EnterpriseBeanDescriptor or AppserverIo\Description\ServletDescriptor or AppserverIo\Description\PersistenceUnitDescriptor or AppserverIo\Ldap\Description\EntityDescriptor. ( Ignorable by Annotation )

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

443
        $reflectionClass = $this->getReflectionClass($objectDescriptor->/** @scrutinizer ignore-call */ getClassName());
Loading history...
444
445
        // load the dependencies for the passed descriptor
446
        $dependencies = $this->loadDependencies($objectDescriptor);
0 ignored issues
show
Bug introduced by
$objectDescriptor of type AppserverIo\Psr\Deployment\DescriptorInterface is incompatible with the type AppserverIo\Psr\Enterpri...wareDescriptorInterface expected by parameter $objectDescriptor of AppserverIo\Appserver\De...der::loadDependencies(). ( Ignorable by Annotation )

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

446
        $dependencies = $this->loadDependencies(/** @scrutinizer ignore-type */ $objectDescriptor);
Loading history...
447
448
        // iterate over all methods and inject the dependencies
449
        foreach ($dependencies['method'] as $methodName => $toInject) {
450
            // query whether or not the method exists
451
            if ($reflectionClass->hasMethod($methodName)) {
452
                // inject the target by invoking the method
453
                call_user_func_array(array($instance, $methodName), $toInject);
454
            }
455
        }
456
457
        // inject dependencies by property
458
        foreach ($dependencies['property'] as $propertyName => $toInject) {
459
            // query whether or not the property exists
460
            if ($reflectionClass->hasProperty($propertyName)) {
461
                // load the reflection property
462
                $reflectionProperty = $reflectionClass->getProperty($propertyName);
463
464
                // load the PHP ReflectionProperty instance to inject the bean instance
465
                $phpReflectionProperty = $reflectionProperty->toPhpReflectionProperty();
466
                $phpReflectionProperty->setAccessible(true);
467
                $phpReflectionProperty->setValue($instance, $toInject);
468
            }
469
        }
470
    }
471
472
    /**
473
     * Returns a new instance of the passed class name.
474
     *
475
     * @param string $className The fully qualified class name to return the instance for
476
     * @param array  $args      Arguments to pass to the constructor of the instance
477
     *
478
     * @return object The instance itself
479
     */
480
    public function newInstance($className, array $args = array())
481
    {
482
483
        // load the reflection data for the passed class name
484
        $reflectionClass = $this->getReflectionClass($className);
485
486
        // query whether or not the class has a constructor
487
        if ($reflectionClass->hasMethod($methodName = '__construct') &&
488
            $reflectionClass->getMethod($methodName)->getParameters() &&
489
            sizeof($args) > 0
490
        ) {
491
            return $reflectionClass->newInstanceArgs($args);
492
        }
493
494
        // return the instance without calling the constructor
495
        return $reflectionClass->newInstance();
496
    }
497
498
    /**
499
     * Finds an entry of the container by its identifier and returns it.
500
     *
501
     * @param string $id Identifier of the entry to look for
502
     *
503
     * @throws \Psr\Container\NotFoundExceptionInterface  No entry was found for **this** identifier.
504
     * @throws \Psr\Container\ContainerExceptionInterface Error while retrieving the entry.
505
     *
506
     * @return mixed Entry.
507
     */
508
    public function get($id)
509
    {
510
511
        // query whether or not the instance can be created
512
        if ($this->has($id)) {
513
            // query the request context whether or not an instance has already been loaded
514
            if (Environment::singleton()->hasAttribute($id)) {
515
                return Environment::singleton()->getAttribute($id);
516
            }
517
518
            try {
519
                // load the object manager instance
520
                /** @var \AppserverIo\Psr\Di\ObjectManagerInterface $objectManager */
521
                $objectManager = $this->getNamingDirectory()->search(
522
                    sprintf('php:global/%s/%s', $this->getApplication()->getUniqueName(), ObjectManagerInterface::IDENTIFIER)
523
                );
524
525
                // query whether or not the passed ID has a descriptor
526
                if ($objectManager->hasObjectDescriptor($id)) {
527
                    // load the object descriptor instance
528
                    $objectDescriptor = $objectManager->getObjectDescriptor($id);
529
530
                    // query if the simple bean has to be initialized by a factory
531
                    if ($objectDescriptor instanceof FactoryAwareDescriptorInterface && $factory = $objectDescriptor->getFactory()) {
532
                        // query whether or not the factory is a simple class or a bean
533
                        if ($className = $factory->getClassName()) {
534
                            $factoryInstance = $this->get($className);
535
                        } else {
536
                            $factoryInstance = $this->get($factory->getName());
537
                        }
538
539
                        // create the instance by invoking the factory method
540
                        $instance = call_user_func(array($factoryInstance, $factory->getMethod()));
541
542
                    } else {
543
                        // create the instance and inject the dependencies
544
                        $instance = $this->createInstance($objectDescriptor);
0 ignored issues
show
Bug introduced by
$objectDescriptor of type AppserverIo\Psr\Deployme...escriptorInterface|null is incompatible with the type AppserverIo\Psr\Enterpri...wareDescriptorInterface expected by parameter $objectDescriptor of AppserverIo\Appserver\De...vider::createInstance(). ( Ignorable by Annotation )

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

544
                        $instance = $this->createInstance(/** @scrutinizer ignore-type */ $objectDescriptor);
Loading history...
545
                    }
546
547
                    // query whether or not method invocations has been configured
548
                    if ($objectDescriptor instanceof MethodInvocationAwareDescriptorInterface) {
549
                        // iterate over all configured method invocations
550
                        foreach ($objectDescriptor->getMethodInvocations() as $methodInvocation) {
551
                            // invoke the method with the configured arguments
552
                            call_user_func_array(
553
                                array($instance, $methodInvocation->getMethodName()),
554
                                $this->loadDependenciesByMethodInvocation($methodInvocation)
555
                            );
556
                        }
557
                    }
558
559
                    // add the initialized instance to the request context if has to be shared
560
                    if ($objectDescriptor->isShared()) {
0 ignored issues
show
Bug introduced by
The method isShared() does not exist on AppserverIo\Psr\Deployment\DescriptorInterface. It seems like you code against a sub-type of AppserverIo\Psr\Deployment\DescriptorInterface such as AppserverIo\Ldap\Descrip...ieldDescriptorInterface or AppserverIo\Ldap\Descrip...ueryDescriptorInterface or AppserverIo\Ldap\Description\EntityDescriptor or AppserverIo\Ldap\Description\RepositoryDescriptor or AppserverIo\Description\...ractNameAwareDescriptor. ( Ignorable by Annotation )

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

560
                    if ($objectDescriptor->/** @scrutinizer ignore-call */ isShared()) {
Loading history...
561
                        $this->set($id, $instance);
0 ignored issues
show
Bug introduced by
It seems like $instance can also be of type object; however, parameter $value of AppserverIo\Appserver\De...ntainer\Provider::set() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

561
                        $this->set($id, /** @scrutinizer ignore-type */ $instance);
Loading history...
562
                    }
563
564
                    // immediately return the instance
565
                    return $instance;
566
                }
567
568
                // initialize the array for the dependencies
569
                $dependencies = array();
570
571
                // assume, that the passed ID is a FQCN
572
                $reflectionClass = $this->getReflectionClass($id);
573
574
                // query whether or not the class has a constructor that expects parameters
575
                if ($reflectionClass->hasMethod($methodName = '__construct') &&
576
                    $reflectionClass->getMethod($methodName)->getParameters()
577
                ) {
578
                    // if yes, load them by the the reflection method
579
                    $dependencies = $this->loadDependenciesByReflectionMethod($reflectionClass->getMethod($methodName));
580
                }
581
582
                // create and ddd the initialized instance to the request context
583
                $this->set($id, $instance = $this->newInstance($id, $dependencies));
584
585
                // finally return the instance
586
                return $instance;
587
588
            } catch (\Exception $e) {
589
                throw new NotFoundException(sprintf('DI error when try to inject dependencies for identifier "%s"', $id), null, $e);
590
            }
591
        }
592
593
        // throw an exception if no entry was found for **this** identifier
594
        throw new NotFoundException(sprintf('DI definition for identifier "%s" is not available', $id));
595
    }
596
597
    /**
598
     * Returns TRUE if the container can return an entry for the given identifier.
599
     * Returns FALSE otherwise.
600
     *
601
     * `has($id)` returning TRUE does not mean that `get($id)` will not throw an exception.
602
     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
603
     *
604
     * @param string $id Identifier of the entry to look for.
605
     *
606
     * @return boolean TRUE if an entry for the given identifier exists, else FALSE
607
     */
608
    public function has($id)
609
    {
610
611
        // load the object manager instance
612
        /** @var \AppserverIo\Psr\Di\ObjectManagerInterface $objectManager */
613
        $objectManager = $this->getNamingDirectory()->search(
614
            sprintf('php:global/%s/%s', $this->getApplication()->getUniqueName(), ObjectManagerInterface::IDENTIFIER)
615
        );
616
617
        // query whether or not a object descriptor or the class definition exists
618
        return class_exists($id) || $objectManager->hasObjectDescriptor($id) || Environment::singleton()->hasAttribute($id);
619
    }
620
621
    /**
622
     * Register's the passed value with the passed ID.
623
     *
624
     * @param string $id    The ID of the value to add
625
     * @param string $value The value to add
626
     *
627
     * @return void
628
     * @throws \AppserverIo\Appserver\DependencyInjectionContainer\ContainerException Is thrown, if a value with the passed key has already been added
629
     */
630
    public function set($id, $value)
631
    {
632
633
        // query whether or not a value with the passed ID already exists
634
        if (Environment::singleton()->hasAttribute($id)) {
635
            throw new ContainerException(sprintf('A value for identifier "%s" has already been added to the DI container', $id));
636
        }
637
638
        // add the value to the environment
639
        Environment::singleton()->setAttribute($id, $value);
640
    }
641
642
    /**
643
     * Query's whether or not an instance of the passed already exists.
644
     *
645
     * @param string $id Identifier of the entry to look for
646
     *
647
     * @return boolean TRUE if an instance exists, else FALSE
648
     */
649
    public function exists($id)
650
    {
651
        return Environment::singleton()->hasAttribute($id);
652
    }
653
654
    /**
655
     * Stops the manager instance.
656
     *
657
     * @return void
658
     * @see \AppserverIo\Psr\Application\ManagerInterface::stop()
659
     */
660
    public function stop()
661
    {
662
        // Still not implemented yet
663
    }
664
}
665