Test Setup Failed
Push β€” master ( 0b0dbf...e8ca0d )
by Php Easy Api
03:37
created

Container   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 600
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 109
dl 0
loc 600
rs 4.5599
c 0
b 0
f 0
wmc 58

29 Methods

Rating   Name   Duplication   Size   Complexity  
A containerBuild() 0 17 2
A contextualBindCleaner() 0 7 3
A bind() 0 10 2
A applicationProviderBinding() 0 6 1
A consoleKernelObjectChecker() 0 12 4
A consoleShared() 0 5 1
A consoleKernelObject() 0 8 1
A build() 0 13 2
A get() 0 20 3
A instance() 0 6 1
A register() 0 22 2
A __get() 0 3 1
A resolved() 0 7 2
A singleton() 0 12 2
A __set() 0 3 1
A serviceContainerObject() 0 5 1
A offsetExists() 0 2 1
A make() 0 20 4
A kernel() 0 6 1
A share() 0 14 2
A setAppInstance() 0 19 3
B has() 0 44 8
A offsetUnset() 0 2 1
A registerProcess() 0 13 2
A offsetGet() 0 5 1
A kernelAssigner() 0 4 1
A terminate() 0 14 2
A resolve() 0 25 2
A offsetSet() 0 1 1

How to fix   Complexity   

Complex Class

Complex classes like Container 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 Container, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Resta\Container;
4
5
use DI\NotFoundException;
6
use DI\DependencyException;
7
use Resta\Console\ConsoleBindings;
8
use Resta\Contracts\ContainerContracts;
9
use Resta\Contracts\ApplicationContracts;
10
use Resta\Exception\FileNotFoundException;
11
12
class Container implements ContainerContracts,\ArrayAccess
13
{
14
    /**
15
     * @var bool
16
     */
17
    public $singleton = false;
18
19
    /**
20
     * @var
21
     */
22
    public $kernel;
23
24
    /**
25
     * @var array  $instance
26
     */
27
    private static $instance = [];
28
29
    /**
30
     * @var array $instances
31
     */
32
    private $instances = [];
33
34
    /**
35
     * @var array $bindParams
36
     */
37
    private static $bindParams = [];
38
39
    /**
40
     * @var
41
     */
42
    protected $unregister;
43
44
    /**
45
     * @var array
46
     */
47
    protected $values = [];
48
49
    /**
50
     * @param $make
51
     * @param array $bind
52
     * @return array
53
     */
54
    public function applicationProviderBinding($make,$bind=array())
55
    {
56
        //service container is an automatic application provider
57
        //that we can bind to the special class di in the dependency condition.
58
        //This method is automatically added to the classes resolved by the entire make bind method.
59
        return array_merge($bind,['app'=>$make]);
60
    }
61
62
    /**
63
     * @param null $object
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $object is correct as it would always require null to be passed?
Loading history...
64
     * @param null $callback
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $callback is correct as it would always require null to be passed?
Loading history...
65
     * @param null|string $alias
66
     * @return mixed
67
     *
68
     * @throws DependencyException
69
     * @throws NotFoundException
70
     */
71
    public function bind($object=null,$callback=null,$alias=null)
72
    {
73
        if(!is_null($alias)){
74
            $object = $alias;
75
        }
76
77
        //If the bind method does not have parameters object and callback, the value is directly assigned to the kernel object.
78
        //Otherwise, when the bind object and callback are sent, the closure class inherits
79
        //the applicationProvider object and the resolve method is called
80
        return $this->make($object,$callback,'container');
0 ignored issues
show
Bug introduced by
It seems like $object can also be of type string; however, parameter $object of Resta\Container\Container::make() does only seem to accept null, 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

80
        return $this->make(/** @scrutinizer ignore-type */ $object,$callback,'container');
Loading history...
Bug introduced by
'container' of type string is incompatible with the type boolean expected by parameter $container of Resta\Container\Container::make(). ( Ignorable by Annotation )

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

80
        return $this->make($object,$callback,/** @scrutinizer ignore-type */ 'container');
Loading history...
81
    }
82
83
    /**
84
     * @param $object
85
     * @param $callback
86
     * @param bool $sync
87
     * @return mixed
88
     *
89
     * @throws DependencyException
90
     * @throws NotFoundException
91
     */
92
    private function build($object,$callback,$sync=false)
93
    {
94
        //If the console object returns true,
95
        //we do not cancel binding operations
96
        //We are getting what applies to console with consoleKernelObject.
97
        if($sync===false) return $this->consoleKernelObjectChecker($object,$callback);
98
99
        //the value corresponding to the bind value for the global object is assigned and
100
        //the resolve method is called for the dependency injection.
101
        $this->kernelAssigner()->setKernelObject($object,$callback);
102
103
        //return kernel object
104
        return $this->kernel();
105
    }
106
107
    /**
108
     * @param $object
109
     * @param bool $container
110
     * @param $callback
111
     * @return mixed
112
     *
113
     * @throws DependencyException
114
     * @throws NotFoundException
115
     */
116
    private function consoleKernelObject($object,$callback,$container=false)
117
    {
118
        //we use the console bindings class to specify the classes to be preloaded in the console application.
119
        //Thus, classes that can not be bound with http are called without closure in global loaders directory.
120
        $this->resolve(ConsoleBindings::class)->console($object,$callback,$container);
121
122
        //The console application must always return the kernel method.
123
        return $this->kernel();
124
    }
125
126
    /**
127
     * @param $object
128
     * @param $callback
129
     * @param bool $container
130
     * @return mixed
131
     *
132
     * @throws DependencyException
133
     * @throws NotFoundException
134
     */
135
    private function consoleKernelObjectChecker($object,$callback,$container=false)
136
    {
137
        //we check whether the callback value is a callable function.
138
        $isCallableForCallback = is_callable($callback);
139
140
        //If the console object returns true,
141
        //we do not cancel binding operations
142
        //We are getting what applies to console with consoleKernelObject.
143
        if($this->console() AND $isCallableForCallback) return $this->consoleKernelObject($object,$callback,$container);
0 ignored issues
show
Bug introduced by
The method console() does not exist on Resta\Container\Container. Did you maybe mean consoleKernelObject()? ( Ignorable by Annotation )

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

143
        if($this->/** @scrutinizer ignore-call */ console() AND $isCallableForCallback) return $this->consoleKernelObject($object,$callback,$container);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
144
145
        //If the application is not a console operation, we re-bind to existing methods synchronously.
146
        return ($container) ? $this->containerBuild($object,$callback,true) : $this->build($object,$callback,true);
147
    }
148
149
    /**
150
     * @param $object
151
     * @param $callback
152
     *
153
     * @throws DependencyException
154
     * @throws NotFoundException
155
     */
156
    private function consoleShared($object,$callback)
157
    {
158
        //The console share is evaluated as a true variable to be assigned as the 3rd parameter in the classes to be bound.
159
        //The work to be done here is to bind the classes to be included in the console share privately.
160
        $this->kernelAssigner()->consoleShared($object,$callback);
161
    }
162
163
    /**
164
     * @param $object
165
     * @param $callback
166
     * @param bool $sync
167
     * @return mixed
168
     *
169
     * @throws DependencyException
170
     * @throws NotFoundException
171
     */
172
    public function containerBuild($object,$callback,$sync=false)
173
    {
174
        //If the console object returns true,
175
        //we do not cancel binding operations
176
        //We are getting what applies to console with consoleKernelObject.
177
        if($sync===false) return $this->consoleKernelObjectChecker($object,$callback,true);
178
179
        //Since the objects that come to the build method are objects from the container method,
180
        //we need to automatically create a kernel object named serviceContainer in this method.
181
        $this->serviceContainerObject();
182
183
        //the value corresponding to the bind value for the global object is assigned and
184
        //the resolve method is called for the dependency method.
185
        $this->kernelAssigner()->setKernelObject($object,$callback,'serviceContainer');
186
187
        //return kernel object
188
        return $this->kernel();
189
    }
190
191
    /**
192
     * @param $class
193
     * @param $bind
194
     */
195
    private function contextualBindCleaner($class,$bind)
196
    {
197
        //the context bind objects are checked again and the bind sequence submitted by
198
        //the user is checked and forced to re-instantiate the object.
199
        if(isset(self::$instance[$class]) && self::$bindParams[$class]!==$bind){
200
            unset(self::$instance[$class]);
201
            unset(self::$bindParams[$class]);
202
        }
203
    }
204
205
    /**
206
     * get abstract data in container
207
     *
208
     * @param $abstract
209
     * @return mixed|ApplicationContracts|null
210
     *
211
     * @throws FileNotFoundException
212
     */
213
    public function get($abstract)
214
    {
215
        //get instance container
216
        $container = app();
217
218
        $containerClosureResolver = [];
219
220
        // the has method can have a dotted string value so
221
        // we need to be able to control the string or array within the container.
222
        foreach (explode(".",$abstract) as $item){
223
            if(isset($container[$item])){
224
                $container = $container[$item];
225
            }
226
            else{
227
                $containerClosureResolver[] = $item;
228
                $container = ContainerClosureResolver::get(implode('.',$containerClosureResolver));
229
            }
230
        }
231
232
        return $container;
233
    }
234
235
    /**
236
     * checks if the container entity is available
237
     *
238
     * @param $abstract
239
     * @return bool|mixed
240
     *
241
     * @throws FileNotFoundException
242
     */
243
    public function has($abstract)
244
    {
245
        $bools = [];
246
247
        //get instance container
248
        $container = $this;
249
250
        $containerClosureResolver = [];
251
252
        // the has method can have a dotted string value so
253
        // we need to be able to control the string or array within the container.
254
        foreach (explode(".",$abstract) as $item){
255
256
            // this blog will work
257
            // if the data in the container loop points to an array.
258
            if(!is_array($container)){
259
260
                // we are querying the value of
261
                // the items corresponding to the dotted value in the container.
262
                // the control result is transferred to the bools array.
263
                $container = $container[$item];
264
265
                if(is_null($container)){
266
                    $containerClosureResolver[] = $item;
267
                    $container = ContainerClosureResolver::get(implode('.',$containerClosureResolver));
268
269
                    if(is_callable($container)){
270
                        $bools = [];
271
                        $container = true;
272
                    }
273
                }
274
275
                $bools[] = is_null($container) ? false : true;
276
            }
277
            else{
278
                // if the container array corresponds to a string,
279
                // the bools array is filled with the isset control directly.
280
                $bools[] = isset($container[$item]) ? true : false;
281
            }
282
        }
283
284
        // the method returns false if the bools sequence is false,
285
        // otherwise it will return true.
286
        return in_array(false,$bools) ? false : true;
287
    }
288
289
    /**
290
     * Register an existing instance as shared in the container.
291
     *
292
     * @param  string  $abstract
293
     * @param  mixed   $instance
294
     * @return mixed
295
     */
296
    public function instance($abstract, $instance)
297
    {
298
        // we'll check to determine if this type has been bound before, and if it has
299
        // we will fire the rebound callbacks registered with the container and it
300
        // can be updated with consuming classes that have gotten resolved here.
301
        $this->instances[$abstract] = $instance;
302
    }
303
304
    /**
305
     * @return mixed
306
     */
307
    public function kernel()
308
    {
309
        //The kernel object system is the container backbone.
310
        //Binding binding and container loads are done with
311
        //the help of this object and distributed to the system.
312
        return $this->kernel;
313
    }
314
315
    /**
316
     * @return mixed
317
     *
318
     * @throws DependencyException
319
     * @throws NotFoundException
320
     */
321
    public function kernelAssigner()
322
    {
323
        //We will use the kernelAssigner class to resolve the singleton object state.
324
        return $this->resolve(ContainerKernelAssigner::class);
325
    }
326
327
    /**
328
     * @param null $object
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $object is correct as it would always require null to be passed?
Loading history...
329
     * @param null $callback
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $callback is correct as it would always require null to be passed?
Loading history...
330
     * @param bool $container
331
     * @return mixed
332
     *
333
     * @throws DependencyException
334
     * @throws NotFoundException
335
     */
336
    public function make($object=null,$callback=null,$container=false)
337
    {
338
        //we check whether the boolean value of the singleton variable used
339
        //for booting does not reset every time the object variable to be assigned to the kernel variable is true
340
        $this->singleton();
341
342
        //The console share is evaluated as a true variable to be assigned as the 3rd parameter in the classes to be bound.
343
        //The work to be done here is to bind the classes to be included in the console share privately.
344
        if($container){
345
            $this->consoleShared($object,$callback);
346
        }
347
348
        //If the third parameter passed to the bind method carries a container value,
349
        //then you will not be able to fire the build method instead of the make method.
350
        $makeBuild = ($container==="container") ? 'containerBuild' : 'build';
0 ignored issues
show
introduced by
The condition $container === 'container' is always false.
Loading history...
351
352
        //If the bind method does not have parameters object and callback, the value is directly assigned to the kernel object.
353
        //Otherwise, when the bind object and callback are sent, the closure class inherits
354
        //the applicationProvider object and the resolve method is called
355
        return ($object===null) ? $this->kernel() : $this->{$makeBuild}($object,$callback);
0 ignored issues
show
introduced by
The condition $object === null is always true.
Loading history...
356
    }
357
358
    /**
359
     * @param $offset
360
     * @return bool
361
     */
362
    public function offsetExists($offset) {
363
        return isset($this->container[$offset]);
0 ignored issues
show
Bug Best Practice introduced by
The property container does not exist on Resta\Container\Container. Since you implemented __get, consider adding a @property annotation.
Loading history...
364
    }
365
366
    /**
367
     * @param mixed $offset
368
     * @return mixed
369
     *
370
     * @throws DependencyException
371
     * @throws NotFoundException
372
     */
373
    public function offsetGet($offset) {
374
375
        return $this->resolve($this->instances['containerInstanceResolve'],[
376
            'instances' => $this->instances
377
        ])->{$offset}();
378
    }
379
380
    /**
381
     * @param $offset
382
     * @param $value
383
     */
384
    public function offsetSet($offset, $value) {}
385
386
    /**
387
     * @param $offset
388
     */
389
    public function offsetUnset($offset) {
390
        unset($this->container[$offset]);
0 ignored issues
show
Bug Best Practice introduced by
The property container does not exist on Resta\Container\Container. Since you implemented __get, consider adding a @property annotation.
Loading history...
391
    }
392
393
    /**
394
     * @param $key
395
     * @param $object
396
     * @param null $concrete
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $concrete is correct as it would always require null to be passed?
Loading history...
397
     * @return bool|mixed
398
     */
399
    public function register($key,$object,$concrete=null)
400
    {
401
        // we assign the values ​​required
402
        // for register to the global value variable.
403
        $this->values['key']        = $key;
404
        $this->values['object']     = $object;
405
        $this->values['concrete']   = $concrete;
406
407
        // If there is an instance of the application class,
408
        // the register method is saved both in this example and in the global.
409
        if(defined('appInstance')){
410
411
            // where we will assign both the global instance
412
            // and the registered application object.
413
            $this->setAppInstance($this->singleton());
414
            $this->setAppInstance(core());
415
416
            return false;
417
        }
418
419
        // we are just doing global instance here.
420
        $this->setAppInstance($this->singleton());
421
    }
422
423
    /**
424
     * @param $instance
425
     * @param bool $withConcrete
426
     * @return bool
427
     */
428
    private function registerProcess($instance,$withConcrete=false)
429
    {
430
        // values recorded without concrete.
431
        // or values deleted
432
        if(false===$withConcrete){
433
434
            //values registered without concrete
435
            $instance->{$this->values['key']}=$this->values['object'];
436
            return false;
437
        }
438
439
        //values registered with concrete
440
        $instance->{$this->values['key']}[$this->values['object']]=$this->values['concrete'];
441
    }
442
443
    /**
444
     * @param $class
445
     * @param array $bind
446
     * @return mixed
447
     *
448
     * @throws DependencyException
449
     * @throws NotFoundException
450
     */
451
    public function resolve($class,$bind=array())
452
    {
453
        //the context bind objects are checked again and the bind sequence submitted by
454
        //the user is checked and forced to re-instantiate the object.
455
        $this->contextualBindCleaner($class,$bind);
456
457
        //We do an instance check to get the static instance values of
458
        //the classes to be resolved with the make bind method.
459
        if(!isset(self::$instance[$class])){
460
461
            //bind params object
462
            self::$bindParams[$class] = $bind;
463
464
            //By singleton checking, we solve the dependency injection of the given class.
465
            //Thus, each class can be called together with its dependency.
466
            self::$instance[$class] = DIContainerManager::make($class,$this->applicationProviderBinding($this,self::$bindParams[$class]));
467
            $this->singleton()->resolved[$class] = self::$instance[$class];
468
469
            //return resolve class
470
            return self::$instance[$class];
471
        }
472
473
        //if the class to be resolved has already been loaded,
474
        //we get the instance value that was saved to get the recurring instance.
475
        return self::$instance[$class];
476
    }
477
478
    /**
479
     * get resolved class
480
     *
481
     * @param $class
482
     * @return mixed
483
     */
484
    public function resolved($class){
485
486
        if(isset($this['resolved'][$class])){
487
            return $this['resolved'][$class];
488
        }
489
490
        exception()->runtime('The class named '.$class.' was not solved before.');
491
    }
492
493
    /**
494
     * @param null $object
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $object is correct as it would always require null to be passed?
Loading history...
495
     * @param null $callback
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $callback is correct as it would always require null to be passed?
Loading history...
496
     * @return mixed
497
     *
498
     * @throws DependencyException
499
     * @throws NotFoundException
500
     */
501
    public function share($object=null,$callback=null)
502
    {
503
        //we check whether the boolean value of the singleton variable used
504
        //for booting does not reset every time the object variable to be assigned to the kernel variable is true
505
        $this->singleton();
506
507
        //The console share is evaluated as a true variable to be assigned as the 3rd parameter in the classes to be bound.
508
        //The work to be done here is to bind the classes to be included in the console share privately.
509
        $this->consoleShared($object,$callback);
510
511
        //If the bind method does not have parameters object and callback, the value is directly assigned to the kernel object.
512
        //Otherwise, when the bind object and callback are sent, the closure class inherits
513
        //the applicationProvider object and the resolve method is called
514
        return ($object===null) ? $this->kernel() : $this->build($object,$callback);
0 ignored issues
show
introduced by
The condition $object === null is always true.
Loading history...
515
516
    }
517
518
    /**
519
     * @throws DependencyException
520
     * @throws NotFoundException
521
     */
522
    private function serviceContainerObject()
523
    {
524
        //Since the objects that come to the build method are objects from the container method,
525
        //we need to automatically create a kernel object named serviceContainer in this method.
526
        $this->kernelAssigner()->container();
527
    }
528
529
    /**
530
     * @method singleton
531
     */
532
    public function singleton()
533
    {
534
        if($this->singleton===false){
535
536
            //after first initializing, the singleton variable is set to true,
537
            //and subsequent incoming classes can inherit the loaded object.
538
            $this->singleton = true;
539
            $this->kernel = \application::kernelBindObject();
0 ignored issues
show
Bug introduced by
The type application 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...
540
        }
541
542
        //kernel object taken over
543
        return $this->kernel();
544
    }
545
546
    /**
547
     * @param $instance
548
     * @return bool
549
     */
550
    private function setAppInstance($instance)
551
    {
552
        // for application instance
553
        // if the values ​​to be saved are to be saved without the concrete,
554
        // if it is an array.
555
        if($this->values['concrete']===null) {
556
557
            // Without concrete,
558
            // the saved value will be saved
559
            // if the it does not exist in application instance.
560
            if(!isset($instance->{$this->values['key']})) {
561
                $this->registerProcess($instance);
562
            }
563
            return false;
564
        }
565
566
        // We send concrete values to be recorded with concrete as true.
567
        // these values will be recorded as a array.
568
        $this->registerProcess($instance,true);
569
    }
570
571
    /**
572
     * @param string $key
573
     * @param null|string $object
574
     * @return mixed
575
     */
576
    public function terminate($key,$object=null)
577
    {
578
        // object null is
579
        // sent to just terminate a key.
580
        if($object===null){
581
            unset(core()->{$key});
582
            unset($this->singleton()->{$key});
583
            return false;
584
        }
585
586
        // It is used to delete
587
        // both key and sequence members.
588
        unset($this->singleton()->{$key}[$object]);
589
        unset(core()->{$key}[$object]);
590
    }
591
592
    /**
593
     * Dynamically access container services.
594
     *
595
     * @param  string  $key
596
     * @return mixed
597
     */
598
    public function __get($key)
599
    {
600
        return $this[$key];
601
    }
602
    /**
603
     * Dynamically set container services.
604
     *
605
     * @param  string  $key
606
     * @param  mixed   $value
607
     * @return void
608
     */
609
    public function __set($key, $value)
610
    {
611
        $this[$key] = $value;
612
    }
613
}