Test Setup Failed
Push β€” master ( 7339e7...c2b6f3 )
by Php Easy Api
21:56 queued 18:10
created

Container::make()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 20
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 5
nc 8
nop 3
dl 0
loc 20
rs 10
c 0
b 0
f 0
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
10
class Container implements ContainerContracts,\ArrayAccess
11
{
12
    /**
13
     * @var bool
14
     */
15
    public $singleton = false;
16
17
    /**
18
     * @var
19
     */
20
    public $kernel;
21
22
    /**
23
     * @var array  $instance
24
     */
25
    private static $instance = [];
26
27
    /**
28
     * @var array $instances
29
     */
30
    private $instances = [];
31
32
    /**
33
     * @var array $bindParams
34
     */
35
    private static $bindParams = [];
36
37
    /**
38
     * @var
39
     */
40
    protected $unregister;
41
42
    /**
43
     * @var array
44
     */
45
    protected $values = [];
46
47
    /**
48
     * @param $make
49
     * @param array $bind
50
     * @return array
51
     */
52
    public function applicationProviderBinding($make,$bind=array())
53
    {
54
        //service container is an automatic application provider
55
        //that we can bind to the special class di in the dependency condition.
56
        //This method is automatically added to the classes resolved by the entire make bind method.
57
        return array_merge($bind,['app'=>$make]);
58
    }
59
60
    /**
61
     * @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...
62
     * @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...
63
     * @param null|string $alias
64
     * @return mixed
65
     *
66
     * @throws DependencyException
67
     * @throws NotFoundException
68
     */
69
    public function bind($object=null,$callback=null,$alias=null)
70
    {
71
        if(!is_null($alias)){
72
            $object = $alias;
73
        }
74
75
        //If the bind method does not have parameters object and callback, the value is directly assigned to the kernel object.
76
        //Otherwise, when the bind object and callback are sent, the closure class inherits
77
        //the applicationProvider object and the resolve method is called
78
        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

78
        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

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

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