Completed
Push — master ( a91b3a...da0f12 )
by Tom
11s
created

ServiceServiceProvider::createFactoryFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
dl 9
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
namespace TomPHP\ContainerConfigurator\League;
4
5
use League\Container\Definition\ClassDefinition;
6
use League\Container\ServiceProvider\AbstractServiceProvider;
7
use TomPHP\ContainerConfigurator\Configurator;
8
use TomPHP\ContainerConfigurator\Exception\NotClassDefinitionException;
9
use TomPHP\ContainerConfigurator\ServiceConfig;
10
use TomPHP\ContainerConfigurator\ServiceDefinition;
11
12
final class ServiceServiceProvider extends AbstractServiceProvider
13
{
14
    /**
15
     * @var array
16
     */
17
    private $config;
18
19
    /**
20
     * @api
21
     *
22
     * @param ServiceConfig $config
23
     */
24
    public function __construct(ServiceConfig $config)
25
    {
26
        $this->config   = $config;
0 ignored issues
show
Documentation Bug introduced by
It seems like $config of type object<TomPHP\ContainerC...igurator\ServiceConfig> is incompatible with the declared type array of property $config.

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...
27
        $this->provides = $config->getKeys();
28
    }
29
30
    public function register()
31
    {
32
        foreach ($this->config as $config) {
33
            $this->registerService($config);
34
        }
35
    }
36
37
    /**
38
     * @param ServiceDefinition $definition
39
     *
40
     * @throws NotClassDefinitionException
41
     *
42
     * @return void
43
     */
44
    private function registerService(ServiceDefinition $definition)
45
    {
46
        if ($definition->isFactory()) {
47
            $this->getContainer()->add(
48
                $definition->getName(),
49
                $this->createFactoryFactory($definition),
50
                $definition->isSingleton()
51
            );
52
53
            return;
54
        }
55
56
        if ($definition->isAlias()) {
57
            $this->getContainer()->add(
58
                $definition->getName(),
59
                $this->createAliasFactory($definition)
60
            );
61
62
            return;
63
        }
64
65
        $service = $this->getContainer()->add(
66
            $definition->getName(),
67
            $definition->getClass(),
68
            $definition->isSingleton()
69
        );
70
71
        if (!$service instanceof ClassDefinition) {
72
            throw NotClassDefinitionException::fromServiceName($definition->getName());
73
        }
74
75
        $service->withArguments($this->injectContainer($definition->getArguments()));
76
        $this->addMethodCalls($service, $definition);
77
    }
78
79
    /**
80
     * @param ClassDefinition   $service
81
     * @param ServiceDefinition $definition
82
     */
83
    private function addMethodCalls(ClassDefinition $service, ServiceDefinition $definition)
84
    {
85
        foreach ($definition->getMethods() as $method => $args) {
86
            $service->withMethodCall($method, $this->injectContainer($args));
87
        }
88
    }
89
90
    /**
91
     * @param ServiceDefinition $definition
92
     *
93
     * @return \Closure
94
     */
95
    private function createAliasFactory(ServiceDefinition $definition)
96
    {
97
        return function () use ($definition) {
98
            return $this->getContainer()->get($definition->getClass());
99
        };
100
    }
101
102
    /**
103
     * @param ServiceDefinition $definition
104
     *
105
     * @return \Closure
106
     */
107 View Code Duplication
    private function createFactoryFactory(ServiceDefinition $definition)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
108
    {
109
        return function () use ($definition) {
110
            $className = $definition->getClass();
111
            $factory   = new $className();
112
113
            return $factory(...$this->resolveArguments($definition->getArguments()));
114
        };
115
    }
116
117
    /**
118
     * @param array $arguments
119
     *
120
     * @return array
121
     */
122
    private function injectContainer(array $arguments)
123
    {
124
        return array_map(
125
            function ($argument) {
126
                return ($argument === Configurator::container())
127
                    ? $this->container
128
                    : $argument;
129
            },
130
            $arguments
131
        );
132
    }
133
134
    /**
135
     * @param array $arguments
136
     *
137
     * @return array
138
     */
139
    private function resolveArguments(array $arguments)
140
    {
141
        return array_map(
142
            function ($argument) {
143
                if ($argument === Configurator::container()) {
144
                    return $this->container;
145
                }
146
147
                if ($this->container->has($argument)) {
148
                    return $this->container->get($argument);
149
                }
150
151
                return $argument;
152
            },
153
            $arguments
154
        );
155
    }
156
}
157