Passed
Push — master ( e5ed6d...a29323 )
by Rafael
09:38
created

AutoWire   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 31
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 7
dl 0
loc 31
rs 10
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
C createInstance() 0 22 7
1
<?php
2
/*******************************************************************************
3
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\Component\AutoWire;
12
13
use Doctrine\Common\Inflector\Inflector;
14
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
15
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
16
17
/**
18
 * Based on the principle of symfony autowiring (https://symfony.com/doc/current/service_container/autowiring.html)
19
 * this autoWire is used to create a instance and inject dependencies using constructor of given class.
20
 *
21
 * - Remove the need of register service for simple classes, like resolvers
22
 * - Does not impact the performance in dev or prod
23
 *
24
 * Caveats:
25
 * - Only works in a constructor
26
 * - Only works if the constructor typehint match exactly with desired service or the param name match with the service or parameter name
27
 *
28
 * How it works?
29
 *
30
 * Services:
31
 *
32
 * - Firstly try to find a service based on constructor type hint
33
 * - If not exist any service registered with this type, then try to find using the service name based on argument name
34
 *    Service Name Conventions:
35
 *      $service => '@service'
36
 *      $serviceName => '@service_name'
37
 *      $serviceName_WithDot => '@service_name.with_dot'
38
 *
39
 * NOTE: in any case, services require ALWAYS the type in the constructor.
40
 *
41
 * Parameters:
42
 * - If the type hint of the argument is not defined or is any scalar type
43
 * a parameter will be injected using the same naming convention of services
44
 */
45
class AutoWire implements ContainerAwareInterface
46
{
47
    use ContainerAwareTrait;
48
49
    /**
50
     * @param string $class
51
     *
52
     * @return mixed
53
     */
54
    public function createInstance(string $class)
55
    {
56
        $refClass = new \ReflectionClass($class);
57
        $args = [];
58
        if ($refClass->getConstructor()) {
59
            foreach ($refClass->getConstructor()->getParameters() as $parameter) {
60
                $name = Inflector::tableize(str_replace('_', '.', $parameter->getName()));
61
                $dependency = null;
62
                if ($parameter->getClass()) {
63
                    if ($this->container->has($parameter->getClass()->getName())) {
64
                        $dependency = $this->container->get($parameter->getClass()->getName());
65
                    } elseif ($this->container->has($name)) {
66
                        $dependency = $this->container->get($name);
67
                    }
68
                } elseif ($this->container->hasParameter($name)) {
69
                    $dependency = $this->container->getParameter($name);
70
                }
71
                $args[] = $dependency;
72
            }
73
        }
74
75
        return $refClass->newInstanceArgs($args);
76
    }
77
}
78