Passed
Branch master (562d32)
by Gabriel
01:25
created

ProviderRepository::add()   A

Complexity

Conditions 6
Paths 12

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 12
c 2
b 0
f 0
dl 0
loc 21
ccs 0
cts 12
cp 0
rs 9.2222
cc 6
nc 12
nop 1
crap 42
1
<?php
2
3
namespace Nip\Container\ServiceProviders;
4
5
use Nip\Container\ContainerAwareInterface;
6
use Nip\Container\ContainerAwareTrait;
7
use Nip\Container\ServiceProviders\Providers\AbstractServiceProvider;
8
use Nip\Container\ServiceProviders\Providers\BootableServiceProviderInterface;
9
use Nip\Container\ServiceProviders\Providers\ServiceProviderInterface;
10
11
/**
12
 * Class ServiceProviderAggregate
13
 * @package Nip\Container\ServiceProvider
14
 */
15
class ProviderRepository implements ProviderRepositoryInterface
16
{
17
    use ContainerAwareTrait;
18
19
    /**
20
     * @var array
21
     */
22
    protected $services = [];
23
24
    /**
25
     * @var AbstractServiceProvider[]
26
     */
27
    protected $providers = [];
28
29
    /**
30
     * @var array Array of registered providers class names
31
     */
32
    protected $registeredProviders = [];
33
34
    /**
35
     * The deferred services and their providers.
36
     *
37
     * @var array
38
     */
39
    protected $deferredServices = [];
40
41
    /**
42
     * Indicates if the application has "booted".
43
     *
44
     * @var bool
45
     */
46
    protected $booted = false;
47
48
    /**
49
     * Adds a new Service Provider
50
     * {@inheritdoc}
51
     */
52
    public function add($provider)
53
    {
54
        if (is_string($provider) && class_exists($provider)) {
55
            $provider = $this->resolveProvider($provider);
56
        }
57
58
        if ($provider instanceof ContainerAwareInterface) {
59
            $provider->setContainer($this->getContainer());
60
        }
61
62
        if ($provider instanceof ServiceProviderInterface) {
63
            foreach ($provider->provides() as $service) {
64
                $this->services[$service] = get_class($provider);
65
            }
66
            $this->providers[] = $provider;
67
            return $this;
68
        }
69
70
        throw new \InvalidArgumentException(
71
            'A service provider must be a fully qualified class name or instance ' .
72
            'of (\Nip\Container\ServiceProvider\ServiceProviderInterface)'
73
        );
74
    }
75
76
    /**
77
     * Resolve a service provider instance from the class name.
78
     *
79
     * @param  string $provider
80
     * @return AbstractServiceProvider
81
     */
82
    public function resolveProvider($provider)
83
    {
84
        return new $provider($this);
85
    }
86
87
    public function register()
88
    {
89
        foreach ($this->providers as $provider) {
90
            $this->registerProvider($provider);
91
        }
92
    }
93
94
    /**
95
     * Register a service provider with the application.
96
     *
97
     * @param  AbstractServiceProvider|string $provider
98
     * @return AbstractServiceProvider
99
     */
100
    public function registerProvider($provider)
101
    {
102
        if (($provider = $this->getProvider($provider))) {
103
        } elseif (is_string($provider)) {
0 ignored issues
show
introduced by
The condition is_string($provider) is always false.
Loading history...
104
            $provider = $this->resolveProvider($provider);
105
        }
106
107
        if ($this->registeredProvider($provider)) {
108
            return $provider;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $provider also could return the type Nip\Container\ServicePro...AbstractServiceProvider which is incompatible with the return type mandated by Nip\Container\ServicePro...ace::registerProvider() of void.
Loading history...
109
        }
110
111
        if (method_exists($provider, 'register')) {
112
            $provider->register();
113
        }
114
115
        $this->markAsRegistered($provider);
116
117
        // If the application has already booted, we will call this boot method on
118
        // the provider class so it has an opportunity to do its boot logic and
119
        // will be ready for any usage by this developer's application logic.
120
        if ($this->booted) {
121
            $this->bootProvider($provider);
0 ignored issues
show
Bug introduced by
It seems like $provider can also be of type null; however, parameter $provider of Nip\Container\ServicePro...ository::bootProvider() does only seem to accept Nip\Container\ServicePro...AbstractServiceProvider, 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

121
            $this->bootProvider(/** @scrutinizer ignore-type */ $provider);
Loading history...
122
        }
123
        return $provider;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $provider also could return the type Nip\Container\ServicePro...eProvider&object|object which is incompatible with the return type mandated by Nip\Container\ServicePro...ace::registerProvider() of void.
Loading history...
124
    }
125
126
    /**
127
     * Get the registered service provider instance if it exists.
128
     *
129
     * @param  AbstractServiceProvider|string $provider
130
     * @return AbstractServiceProvider|null
131
     */
132
    public function getProvider($provider)
133
    {
134
        $name = is_string($provider) ? $provider : get_class($provider);
135
        return \Nip_Helper_Arrays::first($this->providers, function ($value) use ($name) {
0 ignored issues
show
Bug introduced by
The type Nip_Helper_Arrays was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
136
            return $value instanceof $name;
137
        });
138
    }
139
140
    /**
141
     * @param AbstractServiceProvider $provider
142
     * @return bool
143
     */
144
    public function registeredProvider($provider)
145
    {
146
        $providerClass = get_class($provider);
147
        if (isset($this->registeredProviders[$providerClass]) && $this->registeredProviders[$providerClass] === true) {
148
            return true;
149
        }
150
        return false;
151
    }
152
153
    /**
154
     * Mark the given provider as registered.
155
     *
156
     * @param  AbstractServiceProvider $provider
157
     * @return void
158
     */
159
    protected function markAsRegistered($provider)
160
    {
161
        $this->registeredProviders[get_class($provider)] = true;
162
    }
163
164
    /**
165
     * Boot the given service provider.
166
     *
167
     * @param  AbstractServiceProvider $provider
168
     * @return mixed
169
     */
170
    protected function bootProvider(AbstractServiceProvider $provider)
171
    {
172
        if ($provider instanceof BootableServiceProviderInterface) {
173
            return $provider->boot();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $provider->boot() targeting Nip\Container\ServicePro...oviderInterface::boot() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
174
        }
175
        return null;
176
    }
177
    
178
    /**
179
     * @return array
180
     */
181
    public function getProviders(): array
182
    {
183
        return $this->providers;
184
    }
185
186
    /**
187
     * Check to see if the services is registered
188
     * {@inheritdoc}
189
     */
190
    public function provides($service)
191
    {
192
        return array_key_exists($service, $this->providers);
193
    }
194
195
    public function boot()
196
    {
197
        foreach ($this->providers as $provider) {
198
            $this->bootProvider($provider);
199
        }
200
201
        $this->setBooted(true);
202
    }
203
204
    /**
205
     * @param bool $booted
206
     */
207
    public function setBooted($booted)
208
    {
209
        $this->booted = $booted;
210
    }
211
212
    /**
213
     * Load and boot all of the remaining deferred providers.
214
     *
215
     * @return void
216
     */
217
    public function loadDeferredProviders()
218
    {
219
        // We will simply spin through each of the deferred providers and register each
220
        // one and boot them if the application has booted. This should make each of
221
        // the remaining services available to this application for immediate use.
222
        foreach ($this->deferredServices as $service => $provider) {
223
            $this->loadDeferredProvider($service);
224
        }
225
        $this->deferredServices = [];
226
    }
227
228
    /**
229
     * Load the provider for a deferred service.
230
     *
231
     * @param  string $service
232
     * @return void
233
     */
234
    public function loadDeferredProvider($service)
235
    {
236
        if (!isset($this->deferredServices[$service])) {
237
            return;
238
        }
239
        $provider = $this->deferredServices[$service];
240
241
        // If the service provider has not already been loaded and registered we can
242
        // register it with the application and remove the service from this list
243
        // of deferred services, since it will already be loaded on subsequent.
244
        if (!isset($this->registeredProviders[$provider])) {
245
            $this->registerDeferredProvider($provider, $service);
246
        }
247
    }
248
249
    /**
250
     * Register a deferred provider and service.
251
     *
252
     * @param  string $provider
253
     * @param  string $service
254
     * @return void
255
     */
256
    public function registerDeferredProvider($provider, $service = null)
257
    {
258
        // Once the provider that provides the deferred service has been registered we
259
        // will remove it from our local list of the deferred services with related
260
        // providers so that this container does not try to resolve it out again.
261
        if ($service) {
262
            unset($this->deferredServices[$service]);
263
        }
264
        $this->registerProvider($instance = new $provider($this));
265
    }
266
}
267