IlluminateContainer::validateScope()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 2
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Dms\Ioc;
4
5
use Dms\Core\Exception\InvalidArgumentException;
6
use Dms\Core\Ioc\IIocContainer;
7
use Dms\Core\Util\Debug;
8
use Illuminate\Container\Container;
9
10
/**
11
 * The laravel ioc container.
12
 *
13
 * @author Elliot Levin <[email protected]>
14
 */
15
class IlluminateContainer implements IIocContainer
16
{
17
18
    /**
19
     * @var Container
20
     */
21
    private $container;
22
23
    /**
24
     * @var array
25
     */
26
    private $cacheForHas = [];
27
28
    /**
29
     * @param Container $container
30
     */
31
    public function __construct(Container $container)
32
    {
33
        $this->container = $container;
34
    }
35
36
37
    /**
38
     * Binds the supplied class or interface to the supplied
39
     * concrete class name.
40
     *
41
     * @param string $scope
42
     * @param string $abstract
43
     * @param string $concrete
44
     *
45
     * @return void
46
     */
47 View Code Duplication
    public function bind(string $scope, string $abstract, string $concrete)
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...
48
    {
49
        $this->validateScope(__METHOD__, $scope);
50
51
        if ($scope === self::SCOPE_INSTANCE_PER_RESOLVE) {
52
            $this->container->bind($abstract, $concrete);
53
        } else {
54
            $this->container->singleton($abstract, $concrete);
55
        }
56
    }
57
58
    /**
59
     * Binds the supplied class or interface to the return value
60
     * of the supplied callback.
61
     *
62
     * @param string   $scope
63
     * @param string   $abstract
64
     * @param callable $factory
65
     *
66
     * @return void
67
     */
68 View Code Duplication
    public function bindCallback(string $scope, string $abstract, callable $factory)
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...
69
    {
70
        $this->validateScope(__METHOD__, $scope);
71
72
        if ($scope === self::SCOPE_INSTANCE_PER_RESOLVE) {
73
            $this->container->bind($abstract, $factory);
74
        } else {
75
            $this->container->singleton($abstract, $factory);
76
        }
77
    }
78
79
    /**
80
     * Binds the supplied abstract class or interface to the supplied value.
81
     *
82
     * @param string $abstract
83
     * @param mixed  $concrete
84
     *
85
     * @return void
86
     */
87
    public function bindValue(string $abstract, $concrete)
88
    {
89
        $this->container->instance($abstract, $concrete);
90
    }
91
92
    /**
93
     * Binds the supplied class or interface to the supplied value for the duration
94
     * of the supplied callback.
95
     *
96
     * @param string   $abstract
97
     * @param mixed    $concrete
98
     * @param callable $callback
99
     *
100
     * @return mixed The value returned from the callback
101
     */
102
    public function bindForCallback(string $abstract, $concrete, callable $callback)
103
    {
104
        $hasOriginal      = $this->container->bound($abstract);
105
        $originalInstance = false;
106
107
        if ($hasOriginal) {
108
            $binding = $this->container->getBindings()[$abstract] ?? null;
109
110
            $hasInstance = $binding && $binding['shared'] && $this->container->resolved($abstract);
111
112
            if ($hasInstance) {
113
                $originalInstance = $this->container->make($abstract);
114
            }
115
        }
116
117
        $this->container->instance($abstract, $concrete);
118
119
        try {
120
            $return = $callback();
121
            return $return;
122
        } finally {
123
            unset($this->container[$abstract]);
124
125
            if ($hasOriginal && (isset($binding) && $binding)) {
126
                $this->container->bind($abstract, $binding['concrete'], $binding['shared']);
127
128
                if ($originalInstance) {
129
                    $this->container->instance($abstract, $originalInstance);
130
                }
131
            }
132
        }
133
    }    
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    public function get($id)
139
    {
140
        return $this->container->make($id);
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    public function has($id)
147
    {
148
        if ($this->hasIsCached($id)) {
149
            return $this->hasFromCache($id);
150
        }
151
152
        $has = $this->container->bound($id) || $this->isInstantiable($id);
153
154
        $this->cacheHas($id, $has);
155
156
        return $has;
157
    }
158
159
    /**
160
     * Alias a type to a different name.
161
     *
162
     * @param  string  $abstract
163
     * @param  string  $alias
164
     * @return void
165
     */
166
    public function alias($abstract, $alias)
167
    {
168
        $this->container->alias($abstract, $alias);
169
    }
170
171
    /**
172
     * Create object based on the parameters passed
173
     *
174
     * @param  string  $abstract
175
     * @param  array  $parameters
176
     * @return mixed
177
     */
178
    public function makeWith($abstract, array $parameters = [])
179
    {
180
        return $this->container->make($abstract, $parameters);
181
    }
182
183
    /**
184
     * Get the container itself
185
     *
186
     * @return Container
187
     */
188
    public function getIlluminateContainer()
189
    {
190
        return $this->container;
191
    }
192
193
    private function cacheHas($id, $has)
194
    {
195
        $this->cacheForHas[$id] = $has;
196
    }
197
198
    private function hasFromCache($id)
199
    {
200
        return $this->cacheForHas[$id];
201
    }
202
    
203
    private function hasIsCached($id)
204
    {
205
        return array_key_exists($id, $this->cacheForHas);
206
    }
207
208
    private function isInstantiable($id)
209
    {
210
        if (class_exists($id)) {
211
            return true;
212
        }
213
214
        try {
215
            $reflectionClass = new \ReflectionClass($id);
216
217
            return $reflectionClass->isInstantiable();
218
        } catch (\ReflectionException $e) {
219
            return false;
220
        }
221
    }    
222
223
    private function validateScope(string $method, string $scope)
224
    {
225
        $validScopes = [self::SCOPE_INSTANCE_PER_RESOLVE, self::SCOPE_SINGLETON];
226
227
        if (!in_array($scope, $validScopes, true)) {
228
            throw InvalidArgumentException::format(
229
                'Invalid scope supplied to %s: expecting one of (%s), \'%s\' given',
230
                $method,
231
                Debug::formatValues($validScopes),
232
                $scope
233
            );
234
        }
235
    }
236
237
}
238