Application::isProduction()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php 
2
3
/**
4
 * Lenevor Framework
5
 *
6
 * LICENSE
7
 *
8
 * This source file is subject to the new BSD license that is bundled
9
 * with this package in the file license.md.
10
 * It is also available through the world-wide-web at this URL:
11
 * https://lenevor.com/license
12
 * If you did not receive a copy of the license and are unable to
13
 * obtain it through the world-wide-web, please send an email
14
 * to [email protected] so we can send you a copy immediately.
15
 *
16
 * @package     Lenevor
17
 * @subpackage  Base
18
 * @link        https://lenevor.com
19
 * @copyright   Copyright (c) 2019 - 2021 Alexander Campo <[email protected]>
20
 * @license     https://opensource.org/licenses/BSD-3-Clause New BSD license or see https://lenevor.com/license or see /license.md
21
 */
22
23
namespace Syscodes\Core;
24
25
use Closure;
26
use Syscodes\Support\Str;
27
use Syscodes\Collections\Arr;
28
use Syscodes\Container\Container;
29
use Syscodes\Support\Environment;
30
use Syscodes\Filesystem\Filesystem;
31
use Syscodes\Support\ServiceProvider;
32
use Syscodes\Log\LoggerServiceProvider;
33
use Syscodes\Events\EventServiceProvider;
34
use Syscodes\Routing\RoutingServiceProvider;
35
use Syscodes\Core\Http\Exceptions\HttpException;
36
use Syscodes\Core\Http\Exceptions\NotFoundHttpException;
37
use Syscodes\Contracts\Core\Application as ApplicationContract;
38
39
/**
40
 * Allows the loading of service providers and functions to activate 
41
 * routes, environments and calls of main classes.
42
 * 
43
 * @author Alexander Campo <[email protected]>
44
 */
45
class Application extends Container implements ApplicationContract
46
{
47
    /**
48
     * The current globally available application.
49
     * 
50
     * @var string $instance
51
     */
52
    protected static $instance;
53
54
    /**
55
     * Php version.
56
     */
57
    protected static $phpVersion = '7.3.12';
58
    
59
    /**
60
     * The custom application path defined by the developer.
61
     *
62
     * @var string $appPath
63
     */
64
    protected $appPath;
65
66
    /**
67
     * The base path for the Lenevor installation.
68
     *
69
     * @var string $basePath
70
     */
71
    protected $basePath;
72
73
    /**
74
     * Indicates if the application has 'booted'.
75
     * 
76
     * @var bool $booted
77
     */
78
    protected $booted = false;
79
80
    /**
81
     * The array of booted callbacks.
82
     * 
83
     * @var callable[] $bootedCallbacks
84
     */
85
    protected $bootedCallbacks = [];
86
87
    /**
88
     * The array of booting callbacks.
89
     * 
90
     * @var callable[] $bootingCallbacks
91
     */
92
    protected $bootingCallbacks = [];
93
94
    /**
95
     * The deferred services and their providers.
96
     * 
97
     * @var array $deferredServices
98
     */
99
    protected $deferredServices = [];
100
101
    /**
102
     * Get the current application environment.
103
     * 
104
     * @var string
105
     */
106
    protected $env;
107
108
    /**
109
     * The custom environment path defined by the developer.
110
     *
111
     * @var string $environmentPath
112
     */
113
    protected $environmentPath;
114
115
    /**
116
     * The environment file to load during bootstrapping.
117
     *
118
     * @var string $environmentFile
119
     */
120
    protected $environmentFile = '.env';
121
122
    /** 
123
     * Indicates if the application has been bootstrapped before.
124
     * 
125
     * @var bool $hasBeenBootstrapped
126
     */
127
    protected $hasBeenBootstrapped = false;
128
129
    /**
130
     * Indicates if the application is running in the console.
131
     * 
132
     * @var bool|null $isRunningInConsole
133
     */
134
    protected $isRunningInConsole;
135
136
    /**
137
     * The names of the loaded service providers.
138
     * 
139
     * @var array $loadServiceProviders
140
     */
141
    protected $loadServiceProviders = [];
142
143
    /**
144
     * All of the registered services providers.
145
     * 
146
     * @var \Syscodes\Support\ServiceProvider[] $serviceProviders
147
     */
148
    protected $serviceProviders = [];
149
150
    /**
151
     * Constructor. Create a new Application instance.
152
     * 
153
     * @param  string|null  $path 
154
     * 
155
     * @return void
156
     */
157
    public function __construct($path = null)
158
    {
159
        if ($path)
160
        {
161
            $this->setBasePath($path);
162
        }
163
164
        $this->registerBaseBindings();
165
        $this->registerBaseServiceProviders();
166
        $this->registerCoreContainerAliases();
167
        $this->requerimentVersion(static::$phpVersion);
168
        $this->getExtensionLoaded(['mbstring']);
169
    }
170
171
    /**
172
     * Throw an HttpException with the given data.
173
     *
174
     * @param  int  $code
175
     * @param  string  $message
176
     * @param  array  $headers
177
     * 
178
     * @return void
179
     *
180
     * @throws \Syscodes\Core\Http\Exceptions\NotFoundHttpException
181
     * @throws \Syscodes\Core\Http\Exceptions\HttpException
182
     */
183
    public function abort($code, $message = '', array $headers = [])
184
    {
185
        // Convert the first letter in capital
186
        $message = ucfirst($message);
187
188
        if ($code == 404) {
189
            throw new NotFoundHttpException($message);
190
        }
191
192
        throw new HttpException($code, $message, null, $headers);
193
    } 
194
195
    /**
196
     * Set the base path for the application.
197
     *
198
     * @param  string  $path
199
     * 
200
     * @return $this
201
     */
202
    public function setBasePath(string $path)
203
    {
204
        $this->basePath = rtrim($path, '\/');
205
206
        $this->bindContainerPaths();
207
208
        return $this;
209
    }
210
    
211
    /**
212
     * Register all of the base service providers.
213
     * 
214
     * @return void
215
     */
216
    protected function registerBaseServiceProviders()
217
    {
218
        $this->register(new EventServiceProvider($this));
219
        $this->register(new LoggerServiceProvider($this));
220
        $this->register(new RoutingServiceProvider($this));
221
    }
222
223
    /**
224
     * Bind all of the application paths in the container.
225
     * 
226
     * @return void
227
     */
228
    protected function bindContainerPaths()
229
    {
230
        $this->instance('path', $this->path());
231
        $this->instance('path.base', $this->basePath());
232
        $this->instance('path.lang', $this->langPath());
233
        $this->instance('path.config', $this->configPath());
234
        $this->instance('path.public', $this->publicPath());
235
        $this->instance('path.storage', $this->storagePath());
236
        $this->instance('path.database', $this->databasePath());
237
        $this->instance('path.resources', $this->resourcePath());
238
        $this->instance('path.bootstrap', $this->bootstrapPath());
239
    }
240
241
    /**
242
     * Get the path to the application "app" directory.
243
     *
244
     * @param  string  $path
245
     * 
246
     * @return string
247
     */
248
    public function path($path = '')
249
    {
250
        $appPath = $this->basePath.DIRECTORY_SEPARATOR.'app';
251
        
252
        return $appPath.($path ? DIRECTORY_SEPARATOR.$path : $path);
253
    }
254
255
    /**
256
     * Get the base path of the Lenevor installation.
257
     *
258
     * @param  string  $path  Optionally, a path to append to the base path
259
     * 
260
     * @return string
261
     */
262
    public function basePath($path = '')
263
    {
264
        return $this->basePath.($path ? DIRECTORY_SEPARATOR.$path : $path);
265
    }
266
    
267
    /**
268
     * Get the path to the bootstrap directory.
269
     *
270
     * @param  string  $path  Optionally, a path to append to the bootstrap path
271
     * 
272
     * @return string
273
     */
274
    public function bootstrapPath($path = '')
275
    {
276
        return $this->basePath.DIRECTORY_SEPARATOR.'bootstrap'.($path ? DIRECTORY_SEPARATOR.$path : $path);
277
    }
278
279
    /**
280
     * Get the path to the application configuration files.
281
     *
282
     * @param  string  $path  Optionally, a path to append to the config path
283
     * 
284
     * @return string
285
     */
286
    public function configPath($path = '')
287
    {
288
        return $this->basePath.DIRECTORY_SEPARATOR.'config'.($path ? DIRECTORY_SEPARATOR.$path : $path);
289
    }
290
291
    /**
292
     * Get the path to the database directory.
293
     *
294
     * @param  string  $path  Optionally, a path to append to the database path
295
     * 
296
     * @return string
297
     */
298
    public function databasePath($path = '')
299
    {
300
        return $this->basePath.DIRECTORY_SEPARATOR.'database'.($path ? DIRECTORY_SEPARATOR.$path : $path);
301
    }
302
303
    /**
304
     * Get the path to the lang directory.
305
     * 
306
     * @return string
307
     */
308
    public function langPath()
309
    {
310
        return $this->resourcePath().DIRECTORY_SEPARATOR.'lang';
311
    }
312
313
    /**
314
     * Get the path to the public / web directory.
315
     * 
316
     * @return string
317
     */
318
    public function publicPath()
319
    {
320
        return $this->basePath.DIRECTORY_SEPARATOR.'public';
321
    }
322
323
    /**
324
     * Get the path to the resources directory.
325
     *
326
     * @param  string  $path $path  Optionally, a path to append to the resources path
327
     * 
328
     * @return string
329
     */
330
    public function resourcePath($path = '')
331
    {
332
        return $this->basePath.DIRECTORY_SEPARATOR.'resources'.($path ? DIRECTORY_SEPARATOR.$path : $path);
333
    }
334
335
    /**
336
     * Get the path to the storage directory.
337
     * 
338
     * @return string
339
     */
340
    public function storagePath()
341
    {
342
        return $this->basePath.DIRECTORY_SEPARATOR.'storage';
343
    }
344
345
    /**
346
     * Run the given array of bootstap classes.
347
     * 
348
     * @param  string[]  $bootstrappers
349
     * 
350
     * @return void
351
     */
352
    public function bootstrapWith(array $bootstrappers)
353
    {
354
        $this->hasBeenBootstrapped = true;
355
356
        foreach ($bootstrappers as $bootstrapper) {
357
            $this->make($bootstrapper)->bootstrap($this);
358
        }
359
    }
360
361
    /**
362
     * Determine if middleware has been disabled for the application.
363
     * 
364
     * @return bool
365
     */
366
    public function skipGoingMiddleware()
367
    {
368
        return $this->bound('middleware.disable') &&
369
               $this->make('middleware.disable') === true;
370
    }
371
372
    /**
373
     * Set the directory for the environment file.
374
     * 
375
     * @param  string  $path
376
     * 
377
     * @return $this
378
     */
379
    public function setEnvironmentPath($path)
380
    {
381
        $this->environmentPath = $path;
382
383
        return $this;
384
    }
385
386
    /**
387
     * Get the path to the environment file directory.
388
     * 
389
     * @return string
390
     */
391
    public function environmentPath()
392
    {
393
        return $this->environmentPath ?: $this->basePath;
394
    }
395
396
    /**
397
     * Set the environment file to be loaded during bootstrapping.
398
     * 
399
     * @param  string  $file
400
     * 
401
     * @return $this
402
     */
403
    public function setEnvironmentFile($file)
404
    {
405
        $this->environmentFile = $file;
406
407
        return $this;
408
    }
409
410
    /**
411
     * Get the environment file the application is using.
412
     * 
413
     * @return string
414
     */
415
    public function environmentFile()
416
    {
417
        return $this->environmentFile ?: '.env';
418
    }
419
    
420
    /**
421
     * Get the fully qualified path to the environment file.
422
     * 
423
     * @return string
424
     */
425
    public function environmentFilePath()
426
    {
427
        return $this->environmentPath().DIRECTORY_SEPARATOR.$this->environmentFile();
428
    }
429
430
    /**
431
     * Get or check the current application environment.
432
     * 
433
     * @param  string|array  ...$environments
434
     * 
435
     * @return string|bool
436
     */
437
    public function environment(...$environments)
438
    {
439
        if (count($environments) > 0) {
440
            $patterns = is_array($environments[0]) ? $environments[0] : $environments;
441
442
            return Str::is($patterns, $this->env);
0 ignored issues
show
Bug introduced by
$patterns of type array|array<integer,array|string> is incompatible with the type string expected by parameter $pattern of Syscodes\Support\Str::is(). ( Ignorable by Annotation )

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

442
            return Str::is(/** @scrutinizer ignore-type */ $patterns, $this->env);
Loading history...
443
        }
444
445
        return $this->env;
446
    }
447
448
    /**
449
     * Detect the application's current environment.
450
     * 
451
     * @param  \Closure  $callback
452
     *
453
     * @return string
454
     */
455
    public function detectEnvironment(Closure $callback)
456
    {
457
        return $this->env = (new EnvironmentDetector)->detect($callback);
458
    }
459
    
460
    /**
461
     * Determine if application is in local environment.
462
     * 
463
     * @return bool
464
     */
465
    public function isLocal()
466
    {
467
        return $this->env === 'local';
468
    }
469
    
470
    /**
471
     * Determine if application is in production environment.
472
     * 
473
     * @return bool
474
     */
475
    public function isProduction()
476
    {
477
        return $this->env === 'production';
478
    }
479
    
480
    /**
481
     * Determine if the application is unit tests.
482
     * 
483
     * @return bool
484
     */
485
    public function isUnitTests()
486
    {
487
        return $this->env === 'testing';
488
    }
489
490
    /**
491
     * Determine if the application is running in the console.
492
     * 
493
     * @return bool|null
494
     */
495
    public function runningInConsole()
496
    {
497
        if (null === $this->isRunningInConsole) {
498
            $this->isRunningInConsole = Environment::get('APP_RUNNING_CONSOLE') ?? isCli();
0 ignored issues
show
Documentation Bug introduced by
It seems like Syscodes\Support\Environ...NG_CONSOLE') ?? isCli() can also be of type string. However, the property $isRunningInConsole is declared as type boolean|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
499
        }
500
501
        return $this->isRunningInConsole;
502
    }
503
    
504
    /**
505
     * You can load different configurations depending on your
506
     * current environment. Setting the environment also influences
507
     * things like logging and error reporting.
508
     * 
509
     * This can be set to anything, but default usage is:
510
     *     local (development)
511
     *     testing
512
     *     production
513
     * 
514
     * @return string
515
     */
516
    public function bootEnvironment()
517
    {
518
        if (file_exists(SYS_PATH.'src'.DIRECTORY_SEPARATOR.'environment'.DIRECTORY_SEPARATOR.$this->environment().'.php')) {
519
            require_once SYS_PATH.'src'.DIRECTORY_SEPARATOR.'environment'.DIRECTORY_SEPARATOR.$this->environment().'.php';
520
        } else {
521
            header('HTTP/1.1 503 Service Unavailable.', true, 503);
522
            print('<style>
523
                    body {
524
                        align-items: center;
525
                        background: #FBFCFC;
526
                        display: flex;
527
                        font-family: verdana, sans-seif;
528
                        font-size: .9em;
529
                        font-weight: 600;
530
                        justify-content: center;
531
                    }
532
                    
533
                    p {
534
                        background: #F0F3F4;
535
                        border-radius: 5px;
536
                        box-shadow: 0 1px 4px #333333;
537
                        color: #34495E;
538
                        padding: 10px;
539
                        text-align: center;
540
                        text-shadow: 0 1px 0 #424949;
541
                        width: 25%;
542
                    }
543
                </style>
544
                <p>The application environment is not set correctly.</p>');
545
            die(); // EXIT_ERROR
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
546
        }
547
    }
548
549
    /**
550
     * Determine if the application has been bootstrapped before.
551
     * 
552
     * @return bool
553
     */
554
    public function hasBeenBootstrapped()
555
    {
556
        return $this->hasBeenBootstrapped;
557
    }
558
559
    /**
560
     * You can empty out this file, if you are certain that you match all requirements.
561
     * You can remove this if you are confident that your PHP version is sufficient.
562
     * 
563
     * @return string
564
     */
565
    protected function requerimentVersion($version)
566
    {
567
        if (version_compare(PHP_VERSION, $version) < 0) {
568
            if (PHP_SAPI == 'cli') {
569
                $string  = "\033[1;36m";
570
                $string .= "$version\033[0m";
571
                trigger_error("Your PHP version must be equal or higher than {$string} to use Lenevor Framework.".PHP_EOL, E_USER_ERROR);
572
            }
573
    
574
            die("Your PHP version must be equal or higher than <b>{$version}</b> to use Lenevor Framework.");
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
575
        }
576
    }
577
578
    /**
579
     * You can remove this if you are confident you have mbstring installed.
580
     * 
581
     * @return string
582
     */
583
    protected function getExtensionLoaded(array $extensionLoaded)
584
    {
585
        foreach ($extensionLoaded as $value) {
586
            if ( ! extension_loaded($value)) {
587
                if (PHP_SAPI == 'cli') {
588
                    $string  = "\033[1;36m";
589
                    $string .= "$value\033[0m";
590
                    trigger_error("You must enable the {$string} extension to use Lenevor Framework.".PHP_EOL, E_USER_ERROR);
591
                }
592
593
                die("You must enable the <b>{$value}</b> extension to use Lenevor Framework.");
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
594
            }
595
        }
596
    }
597
598
    /**
599
     * Resolve the given type from the container.
600
     *
601
     * (Overriding Container::make)
602
     * 
603
     * @param  string  $id
604
     * @param  array   $parameters
605
     * 
606
     * @return mixed
607
     */
608
    public function make($id, array $parameters = [])
609
    {
610
        $this->loadDeferredProviderInstance($id = $this->getAlias($id));
611
       
612
        return parent::make($id, $parameters);
613
    }
614
615
    /**
616
     * Resolve the given type from the container.
617
     *
618
     * (Overriding Container::resolve)
619
     * 
620
     * @param  string  $id
621
     * @param  array   $parameters
622
     * 
623
     * @return mixed
624
     */
625
    protected function resolve($id, array $parameters = [])
626
    {
627
        $this->loadDeferredProviderInstance($id = $this->getAlias($id));
628
       
629
        return parent::resolve($id, $parameters);
630
    }
631
    
632
    /**
633
     * Load the deferred provider if the given type is a deferred service.
634
     * 
635
     * @param  string  $id
636
     * 
637
     * @return void
638
     */
639
    protected function loadDeferredProviderInstance($id)
640
    {
641
        if ($this->isDeferredService($id) && ! isset($this->instances[$id])) {
642
            $this->loadDeferredProvider($id);
643
        }
644
    }
645
646
    /**
647
     * Register all of the configured providers.
648
     * 
649
     * @return void
650
     */
651
    public function registerConfiguredProviders()
652
    {
653
        (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
654
                ->load($this['config']['services.providers']);
655
    }
656
    
657
    /**
658
     * Register a service provider.
659
     * 
660
     * @param  \Syscodes\Support\ServiceProvider|string  $provider
661
     * @param  bool  $force
662
     * 
663
     * @return \Syscodes\Support\ServiceProvider
664
     */
665
    public function register($provider, $force = false)
666
    {
667
        if (($registered = $this->getProviderHasBeenLoaded($provider)) && ! $force) {
668
            return $registered;
669
        }
670
671
        if (is_string($provider)) {
672
            $provider = $this->resolveProviderClass($provider);
673
        }
674
        
675
        $provider->register();
676
677
        $this->markAsRegistered($provider);
678
        
679
        if ($this->isBooted()) {
680
            $this->bootProviderClass($provider);
681
        }
682
683
        return $provider;
684
    }
685
686
    /**
687
     * Get the registered service provider instance if it exists.
688
     * 
689
     * @param  \Syscodes\Support\ServiceProvider|string  $provider
690
     * 
691
     * @return \Syscodes\Support\ServiceProvider
692
     */
693
    protected function getProviderHasBeenLoaded($provider)
694
    {
695
        $name = is_string($provider) ? $provider : getClass($provider, true);
0 ignored issues
show
Bug introduced by
$provider of type Syscodes\Support\ServiceProvider is incompatible with the type string expected by parameter $classname of getClass(). ( Ignorable by Annotation )

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

695
        $name = is_string($provider) ? $provider : getClass(/** @scrutinizer ignore-type */ $provider, true);
Loading history...
696
697
        if (array_key_exists($name, $this->loadServiceProviders)) {
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type array; however, parameter $key of array_key_exists() does only seem to accept integer|string, 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

697
        if (array_key_exists(/** @scrutinizer ignore-type */ $name, $this->loadServiceProviders)) {
Loading history...
698
            return Arr::first($this->serviceProviders, function($key, $value) use ($name) {
699
                return getClass($value, true) == $name;
700
            });
701
        }
702
    }
703
704
    /**
705
     * Resolve a service provider instance from the class name.
706
     * 
707
     * @param  string  $provider
708
     * 
709
     * @return \Syscodes\Support\ServiceProvider
710
     */
711
    public function resolveProviderClass($provider)
712
    {
713
        return new $provider($this);
714
    }
715
716
    /**
717
     * Mark the given provider as registered.
718
     * 
719
     * @param  \Syscodes\Support\ServiceProvider  $provider
720
     * 
721
     * @return void
722
     */
723
    protected function markAsRegistered($provider)
724
    {
725
        $this['events']->dispatch($class = getClass($provider, true), array($provider));
0 ignored issues
show
Bug introduced by
$provider of type Syscodes\Support\ServiceProvider is incompatible with the type string expected by parameter $classname of getClass(). ( Ignorable by Annotation )

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

725
        $this['events']->dispatch($class = getClass(/** @scrutinizer ignore-type */ $provider, true), array($provider));
Loading history...
726
727
        $this->serviceProviders[] = $provider;
728
        
729
        $this->loadServiceProviders[$class] = true;
730
    }
731
732
    /**
733
     * Load and boot all of the remaining deferred providers.
734
     * 
735
     * @return void
736
     */
737
    public function loadDeferredProviders()
738
    {
739
        foreach ($this->deferredServices as $service => $provider) { 
740
            $this->loadDeferredProvider($service);
741
        }
742
743
        $this->deferredServices = [];
744
    }
745
746
    /**
747
     * Load the provider for a deferred service.
748
     * 
749
     * @param  string  $service
750
     * 
751
     * @return void
752
     */
753
    public function loadDeferredProvider($service)
754
    {
755
        if ( ! $this->isDeferredService($service)) {
756
            return;
757
        }
758
        
759
        $provider = $this->deferredServices[$service];
760
761
        if ( ! isset($this->loadServiceProviders[$provider])) {
762
            $this->registerDeferredProvider($provider, $service);
763
        }
764
    }
765
766
    /**
767
     * Register a deferred provider and service.
768
     * 
769
     * @param  string  $provider
770
     * @param  string  $service
771
     * 
772
     * @return void
773
     */
774
    public function registerDeferredProvider($provider, $service = null)
775
    {
776
        if ( ! is_null($service)) {
777
            unset($this->deferredServices[$service]);
778
        }
779
780
        $this->register($instance = new $provider($this));
781
782
        if ( ! $this->isBooted()) {
783
            $this->booting(function () use ($instance) {
784
                $this->bootProviderClass($instance);
785
            });
786
        }
787
    }
788
    
789
    /**
790
     * Determine if the given id type has been bound.
791
     * 
792
     * @param  string  $id
793
     * 
794
     * @return bool
795
     */
796
    public function bound($id)
797
    {
798
        return $this->isDeferredService($id) || parent::bound($id);
799
    }
800
801
    /**
802
     * Determine if the application has booted.
803
     * 
804
     * @return bool
805
     */
806
    public function isBooted()
807
    {
808
        return $this->booted;
809
    }
810
811
    /**
812
     * Boot the application´s service providers.
813
     * 
814
     * @return void
815
     */
816
    public function boot()
817
    {
818
        if ($this->isbooted()) {
819
            return;
820
        }
821
822
        $this->bootAppCallbacks($this->bootingCallbacks);
823
824
        array_walk($this->serviceProviders, function ($provider) {
825
            $this->bootProviderClass($provider);
826
        });
827
828
        $this->booted = true;
829
830
        $this->bootAppCallbacks($this->bootedCallbacks);
831
    }
832
833
    /**
834
     * Call the booting callbacks for the application.
835
     * 
836
     * @param  callable[]  $callbacks
837
     * 
838
     * @return void
839
     */
840
    protected function bootAppCallbacks(array $callbacks)
841
    {
842
        foreach ($callbacks as $callback) {
843
            $callback($this);
844
        }
845
    }
846
847
    /**
848
     * Boot the given service provider.
849
     * 
850
     * @param  \Syscodes\Support\ServiceProvider  $provider
851
     * 
852
     * @return mixed
853
     */
854
    protected function bootProviderClass(ServiceProvider $provider)
855
    {
856
        if (method_exists($provider, 'boot'))
857
        {
858
            $provider->boot();
859
        }
860
    }
861
862
    /**
863
     * Register a new boot listener.
864
     * 
865
     * @param  callable  $callback
866
     * 
867
     * @return void
868
     */
869
    public function booting($callback)
870
    {
871
        $this->bootingCallbacks[] = $callback;
872
    }
873
874
    /**
875
     * Register a new 'booted' listener.
876
     * 
877
     * @param  callable  $callback
878
     * 
879
     * @return void
880
     */
881
    public function booted($callback)
882
    {
883
        $this->bootedCallbacks[] = $callback;
884
885
        if ($this->isBooted()) {
886
            $this->bootAppCallbacks([$callback]);
887
        }
888
    }
889
890
    /**
891
     * Get the path to the cached services.php file.
892
     * 
893
     * @return string
894
     */
895
    public function getCachedServicesPath()
896
    {
897
        return $this->normalizeCachePath('APP_SERVICES_CACHE', 'cache/services.php');
898
    }
899
900
    /**
901
     * Normalize a relative or absolute path to a cache file.
902
     * 
903
     * @param  string  $key
904
     * @param  string  $default
905
     * 
906
     * @return string
907
     */
908
    protected function normalizeCachePath($key, $default)
909
    {
910
        if (is_null($env = Environment::get($key))) {
911
            return $this->bootstrapPath($default);
912
        }
913
914
        return isset($env) 
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $env : $this->basePath($env) also could return the type boolean which is incompatible with the documented return type string.
Loading history...
915
                ? $env
916
                : $this->basePath($env);
917
    }
918
919
    /**
920
     * Get the service providers.
921
     * 
922
     * @return array
923
     */
924
    public function getLoadedProviders()
925
    {
926
        return $this->loadServiceProviders;
927
    }
928
929
    /**
930
     * Determine if the given service provider is loaded.
931
     * 
932
     * @param  string  $provider
933
     * 
934
     * @return bool
935
     */
936
    public function providerIsLoaded(string $provider)
937
    {
938
        return isset($this->loadServiceProviders[$provider]);
939
    }
940
941
    /**
942
     * Get the application's deferred services.
943
     * 
944
     * @return array
945
     */
946
    public function getDeferredServices()
947
    {
948
        return $this->deferredServices;
949
    }
950
951
    /**
952
     * Set the application's deferred services.
953
     * 
954
     * @param  array  $services
955
     * 
956
     * @return void
957
     */
958
    public function setDeferredServices(array $services)
959
    {
960
        $this->deferredServices = $services;
961
    }
962
963
    /**
964
     * Determine if the given service is a deferred service.
965
     * 
966
     * @param  string  $service
967
     * 
968
     * @return bool
969
     */
970
    public function isDeferredService($service)
971
    {
972
        return isset($this->deferredServices[$service]);
973
    }
974
975
    /**
976
     * Add an array of services to the application's deferred services.
977
     * 
978
     * @param  array  $services
979
     * 
980
     * @return void
981
     */
982
    public function addDeferredServices(array $services)
983
    {
984
        $this->deferredServices = array_merge($this->deferredServices, $services);
985
    }
986
987
    /**
988
     * Get the current application locale.
989
     * 
990
     * @return string
991
     */
992
    public function getLocale()
993
    {
994
        return $this['config']->get('app.locale');
995
    }
996
997
    /**
998
     * Get the current application fallback locale.
999
     * 
1000
     * @return string
1001
     */
1002
    public function getFallbackLocale()
1003
    {
1004
        return $this['config']->get('app.fallbackLocale');
1005
    }
1006
1007
    /**
1008
     * Determine if application locale is the given locale.
1009
     * 
1010
     * @param  string  $locale
1011
     * 
1012
     * @return bool
1013
     */
1014
    public function isLocale($locale)
1015
    {
1016
        return $this->getLocale() == $locale;
1017
    }
1018
1019
    /**
1020
     * Register the basic bindings into the container.
1021
     *
1022
     * @return void
1023
     */
1024
    public function registerBaseBindings() 
1025
    {
1026
        static::setInstance($this);
1027
        
1028
        $this->instance('app', $this);
1029
        
1030
        $this->instance('config', $this[\Syscodes\Config\Configure::class]);
1031
    }
1032
1033
    /**
1034
     * Register the core class aliases in the container.
1035
     * 
1036
     * @return void
1037
     */
1038
    public function registerCoreContainerAliases()
1039
    {
1040
        foreach ([
1041
            'app'              => [self::class, \Syscodes\Contracts\Container\Container::class, \Syscodes\Contracts\Core\Application::class, \Psr\Container\ContainerInterface::class],
1042
            'cache'            => [\Syscodes\Cache\CacheManager::class, \Syscodes\Contracts\Cache\Manager::class],
1043
            'cache.store'      => [\Syscodes\Cache\CacheRepository::class, \Syscodes\Contracts\Cache\Repository::class],
1044
            'config'           => [\Syscodes\Config\Configure::class, \Syscodes\Contracts\Config\Configure::class],
1045
            'db'               => [\Syscodes\Database\DatabaseManager::class, \Syscodes\Database\ConnectionResolverInterface::class],
1046
            'db.connection'    => [\Syscodes\Database\Connection::class, \Syscodes\Database\ConnectionInterface::class],
1047
            'encrypter'        => [\Syscodes\Encryption\Encrypter::class, \Syscodes\Contracts\Encryption\Encrypter::class],
1048
            'events'           => [\Syscodes\Events\Dispatcher::class, \Syscodes\Contracts\Events\Dispatcher::class],
1049
            'files'            => [\Syscodes\Filesystem\Filesystem::class],
1050
            'log'              => [\Syscodes\Log\LogManager::class, \Psr\Log\LoggerInterface::class],
1051
            'plaze.transpiler' => [\Syscodes\View\Transpilers\PlazeTranspiler::class],
1052
            'redirect'         => [\Syscodes\Routing\Redirector::class],
1053
            'redis'            => [\Syscodes\Redis\RedisManager::class],
1054
            'request'          => [\Syscodes\Http\Request::class],
1055
            'router'           => [\Syscodes\Routing\Router::class],
1056
            'session'          => [\Syscodes\Session\SessionManager::class],
1057
            'session.store'    => [\Syscodes\Session\Store::class, \Syscodes\Contracts\Session\Session::class],
1058
            'translator'       => [\Syscodes\Translation\Translator::class],
1059
            'url'              => [\Syscodes\Routing\UrlGenerator::class],
1060
            'view'             => [\Syscodes\View\Factory::class, \Syscodes\Contracts\View\Factory::class]
1061
        ] as $key => $aliases) {
1062
            foreach ((array) $aliases as $alias) {
1063
                $this->alias($key, $alias);
1064
            }
1065
        }
1066
    }
1067
}