Test Setup Failed
Push β€” master ( 97d506...713012 )
by Php Easy Api
20:40 queued 17:06
created

Container::containerBuild()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 3
dl 0
loc 17
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
     * @return mixed
64
     *
65
     * @throws DependencyException
66
     * @throws NotFoundException
67
     */
68
    public function bind($object=null,$callback=null)
69
    {
70
        //If the bind method does not have parameters object and callback, the value is directly assigned to the kernel object.
71
        //Otherwise, when the bind object and callback are sent, the closure class inherits
72
        //the applicationProvider object and the resolve method is called
73
        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

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

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