Test Setup Failed
Push β€” master ( 590e27...97d506 )
by Php Easy Api
21:06 queued 14:11
created

Container::serviceContainerObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 5
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
        //we will automatically inject all container values ​​bindings into resolved class.
55
        if(defined('appInstance') && is_array($bindings = $this->get('bindings'))){
0 ignored issues
show
introduced by
The condition is_array($bindings = $this->get('bindings')) is always false.
Loading history...
Bug introduced by
Are you sure the assignment to $bindings is correct as $this->get('bindings') targeting Resta\Container\Container::get() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

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

85
        return $this->make($object,$callback,/** @scrutinizer ignore-type */ 'container');
Loading history...
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

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

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