Test Setup Failed
Push β€” master ( 4c7ace...8edce4 )
by Php Easy Api
20:25 queued 16:59
created

Container::contextualBindCleaner()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 2
dl 0
loc 7
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
        if(defined('appInstance')){
55
            //
56
        }
57
58
        //service container is an automatic application provider
59
        //that we can bind to the special class di in the dependency condition.
60
        //This method is automatically added to the classes resolved by the entire make bind method.
61
        return array_merge($bind,['app'=>$make]);
62
    }
63
64
    /**
65
     * @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...
66
     * @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...
67
     * @param null|string $alias
68
     * @return mixed
69
     *
70
     * @throws DependencyException
71
     * @throws NotFoundException
72
     */
73
    public function bind($object=null,$callback=null,$alias=null)
74
    {
75
        if(!is_null($alias)){
76
            $object = $alias;
77
        }
78
79
        //If the bind method does not have parameters object and callback, the value is directly assigned to the kernel object.
80
        //Otherwise, when the bind object and callback are sent, the closure class inherits
81
        //the applicationProvider object and the resolve method is called
82
        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

82
        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

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

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