<?php namespace Illuminate\Foundation; use Closure; use RuntimeException; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Http\Request; use Illuminate\Container\Container; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\ServiceProvider; use Illuminate\Events\EventServiceProvider; use Illuminate\Routing\RoutingServiceProvider; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpFoundation\Request as SymfonyRequest; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Illuminate\Contracts\Foundation\Application as ApplicationContract; class Application extends Container implements ApplicationContract, HttpKernelInterface { /** * The Laravel framework version. * * @var string */ const VERSION = '5.2.45'; /** * The base path for the Laravel installation. * * @var string */ protected $basePath; /** * Indicates if the application has been bootstrapped before. * * @var bool */ protected $hasBeenBootstrapped = false; /** * Indicates if the application has "booted". * * @var bool */ protected $booted = false; /** * The array of booting callbacks. * * @var array */ protected $bootingCallbacks = []; /** * The array of booted callbacks. * * @var array */ protected $bootedCallbacks = []; /** * The array of terminating callbacks. * * @var array */ protected $terminatingCallbacks = []; /** * All of the registered service providers. * * @var array */ protected $serviceProviders = []; /** * The names of the loaded service providers. * * @var array */ protected $loadedProviders = []; /** * The deferred services and their providers. * * @var array */ protected $deferredServices = []; /** * A custom callback used to configure Monolog. * * @var callable|null */ protected $monologConfigurator; /** * The custom database path defined by the developer. * * @var string */ protected $databasePath; /** * The custom storage path defined by the developer. * * @var string */ protected $storagePath; /** * The custom environment path defined by the developer. * * @var string */ protected $environmentPath; /** * The environment file to load during bootstrapping. * * @var string */ protected $environmentFile = '.env'; /** * The application namespace. * * @var string */ protected $namespace = null; /** * Create a new Illuminate application instance. * * @param string|null $basePath * @return void */ public function __construct($basePath = null) { $this->registerBaseBindings(); $this->registerBaseServiceProviders(); $this->registerCoreContainerAliases(); if ($basePath) { $this->setBasePath($basePath); } } /** * Get the version number of the application. * * @return string */ public function version() { return static::VERSION; } /** * Register the basic bindings into the container. * * @return void */ protected function registerBaseBindings() { static::setInstance($this); $this->instance('app', $this); $this->instance('Illuminate\Container\Container', $this); } /** * Register all of the base service providers. * * @return void */ protected function registerBaseServiceProviders() { $this->register(new EventServiceProvider($this)); $this->register(new RoutingServiceProvider($this)); } /** * Run the given array of bootstrap classes. * * @param array $bootstrappers * @return void */ public function bootstrapWith(array $bootstrappers) { $this->hasBeenBootstrapped = true; foreach ($bootstrappers as $bootstrapper) { $this['events']->fire('bootstrapping: '.$bootstrapper, [$this]); $this->make($bootstrapper)->bootstrap($this); $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]); } } /** * Register a callback to run after loading the environment. * * @param \Closure $callback * @return void */ public function afterLoadingEnvironment(Closure $callback) { return $this->afterBootstrapping( 'Illuminate\Foundation\Bootstrap\DetectEnvironment', $callback ); } /** * Register a callback to run before a bootstrapper. * * @param string $bootstrapper * @param Closure $callback * @return void */ public function beforeBootstrapping($bootstrapper, Closure $callback) { $this['events']->listen('bootstrapping: '.$bootstrapper, $callback); } /** * Register a callback to run after a bootstrapper. * * @param string $bootstrapper * @param Closure $callback * @return void */ public function afterBootstrapping($bootstrapper, Closure $callback) { $this['events']->listen('bootstrapped: '.$bootstrapper, $callback); } /** * Determine if the application has been bootstrapped before. * * @return bool */ public function hasBeenBootstrapped() { return $this->hasBeenBootstrapped; } /** * Set the base path for the application. * * @param string $basePath * @return $this */ public function setBasePath($basePath) { $this->basePath = rtrim($basePath, '\/'); $this->bindPathsInContainer(); return $this; } /** * Bind all of the application paths in the container. * * @return void */ protected function bindPathsInContainer() { $this->instance('path', $this->path()); $this->instance('path.base', $this->basePath()); $this->instance('path.lang', $this->langPath()); $this->instance('path.config', $this->configPath()); $this->instance('path.public', $this->publicPath()); $this->instance('path.storage', $this->storagePath()); $this->instance('path.database', $this->databasePath()); $this->instance('path.bootstrap', $this->bootstrapPath()); } /** * Get the path to the application "app" directory. * * @return string */ public function path() { return $this->basePath.DIRECTORY_SEPARATOR.'app'; } /** * Get the base path of the Laravel installation. * * @return string */ public function basePath() { return $this->basePath; } /** * Get the path to the bootstrap directory. * * @return string */ public function bootstrapPath() { return $this->basePath.DIRECTORY_SEPARATOR.'bootstrap'; } /** * Get the path to the application configuration files. * * @return string */ public function configPath() { return $this->basePath.DIRECTORY_SEPARATOR.'config'; } /** * Get the path to the database directory. * * @return string */ public function databasePath() { return $this->databasePath ?: $this->basePath.DIRECTORY_SEPARATOR.'database'; } /** * Set the database directory. * * @param string $path * @return $this */ public function useDatabasePath($path) { $this->databasePath = $path; $this->instance('path.database', $path); return $this; } /** * Get the path to the language files. * * @return string */ public function langPath() { return $this->basePath.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'lang'; } /** * Get the path to the public / web directory. * * @return string */ public function publicPath() { return $this->basePath.DIRECTORY_SEPARATOR.'public'; } /** * Get the path to the storage directory. * * @return string */ public function storagePath() { return $this->storagePath ?: $this->basePath.DIRECTORY_SEPARATOR.'storage'; } /** * Set the storage directory. * * @param string $path * @return $this */ public function useStoragePath($path) { $this->storagePath = $path; $this->instance('path.storage', $path); return $this; } /** * Get the path to the environment file directory. * * @return string */ public function environmentPath() { return $this->environmentPath ?: $this->basePath; } /** * Set the directory for the environment file. * * @param string $path * @return $this */ public function useEnvironmentPath($path) { $this->environmentPath = $path; return $this; } /** * Set the environment file to be loaded during bootstrapping. * * @param string $file * @return $this */ public function loadEnvironmentFrom($file) { $this->environmentFile = $file; return $this; } /** * Get the environment file the application is using. * * @return string */ public function environmentFile() { return $this->environmentFile ?: '.env'; } /** * Get the fully qualified path to the environment file. * * @return string */ public function environmentFilePath() { return $this->environmentPath().'/'.$this->environmentFile(); } /** * Get or check the current application environment. * * @param mixed * @return string|bool */ public function environment() { if (func_num_args() > 0) { $patterns = is_array(func_get_arg(0)) ? func_get_arg(0) : func_get_args(); foreach ($patterns as $pattern) { if (Str::is($pattern, $this['env'])) { return true; } } return false; } return $this['env']; } /** * Determine if application is in local environment. * * @return bool */ public function isLocal() { return $this['env'] == 'local'; } /** * Detect the application's current environment. * * @param \Closure $callback * @return string */ public function detectEnvironment(Closure $callback) { $args = isset($_SERVER['argv']) ? $_SERVER['argv'] : null; return $this['env'] = (new EnvironmentDetector())->detect($callback, $args); } /** * Determine if we are running in the console. * * @return bool */ public function runningInConsole() { return php_sapi_name() == 'cli'; } /** * Determine if we are running unit tests. * * @return bool */ public function runningUnitTests() { return $this['env'] == 'testing'; } /** * Register all of the configured providers. * * @return void */ public function registerConfiguredProviders() { $manifestPath = $this->getCachedServicesPath(); (new ProviderRepository($this, new Filesystem, $manifestPath)) ->load($this->config['app.providers']); } /** * Register a service provider with the application. * * @param \Illuminate\Support\ServiceProvider|string $provider * @param array $options * @param bool $force * @return \Illuminate\Support\ServiceProvider */ public function register($provider, $options = [], $force = false) { if (($registered = $this->getProvider($provider)) && ! $force) { return $registered; } // If the given "provider" is a string, we will resolve it, passing in the // application instance automatically for the developer. This is simply // a more convenient way of specifying your service provider classes. if (is_string($provider)) { $provider = $this->resolveProviderClass($provider); } $provider->register(); // Once we have registered the service we will iterate through the options // and set each of them on the application so they will be available on // the actual loading of the service objects and for developer usage. foreach ($options as $key => $value) { $this[$key] = $value; } $this->markAsRegistered($provider); // If the application has already booted, we will call this boot method on // the provider class so it has an opportunity to do its boot logic and // will be ready for any usage by the developer's application logics. if ($this->booted) { $this->bootProvider($provider); } return $provider; } /** * Get the registered service provider instance if it exists. * * @param \Illuminate\Support\ServiceProvider|string $provider * @return \Illuminate\Support\ServiceProvider|null */ public function getProvider($provider) { $name = is_string($provider) ? $provider : get_class($provider); return Arr::first($this->serviceProviders, function ($key, $value) use ($name) { return $value instanceof $name; }); } /** * Resolve a service provider instance from the class name. * * @param string $provider * @return \Illuminate\Support\ServiceProvider */ public function resolveProviderClass($provider) { return new $provider($this); } /** * Mark the given provider as registered. * * @param \Illuminate\Support\ServiceProvider $provider * @return void */ protected function markAsRegistered($provider) { $this['events']->fire($class = get_class($provider), [$provider]); $this->serviceProviders[] = $provider; $this->loadedProviders[$class] = true; } /** * Load and boot all of the remaining deferred providers. * * @return void */ public function loadDeferredProviders() { // We will simply spin through each of the deferred providers and register each // one and boot them if the application has booted. This should make each of // the remaining services available to this application for immediate use. foreach ($this->deferredServices as $service => $provider) { $this->loadDeferredProvider($service); } $this->deferredServices = []; } /** * Load the provider for a deferred service. * * @param string $service * @return void */ public function loadDeferredProvider($service) { if (! isset($this->deferredServices[$service])) { return; } $provider = $this->deferredServices[$service]; // If the service provider has not already been loaded and registered we can // register it with the application and remove the service from this list // of deferred services, since it will already be loaded on subsequent. if (! isset($this->loadedProviders[$provider])) { $this->registerDeferredProvider($provider, $service); } } /** * Register a deferred provider and service. * * @param string $provider * @param string $service * @return void */ public function registerDeferredProvider($provider, $service = null) { // Once the provider that provides the deferred service has been registered we // will remove it from our local list of the deferred services with related // providers so that this container does not try to resolve it out again. if ($service) { unset($this->deferredServices[$service]); } $this->register($instance = new $provider($this)); if (! $this->booted) { $this->booting(function () use ($instance) { $this->bootProvider($instance); }); } } /** * Resolve the given type from the container. * * (Overriding Container::make) * * @param string $abstract * @param array $parameters * @return mixed */ public function make($abstract, array $parameters = []) { $abstract = $this->getAlias($abstract); if (isset($this->deferredServices[$abstract])) { $this->loadDeferredProvider($abstract); } return parent::make($abstract, $parameters); } /** * Determine if the given abstract type has been bound. * * (Overriding Container::bound) * * @param string $abstract * @return bool */ public function bound($abstract) { return isset($this->deferredServices[$abstract]) || parent::bound($abstract); } /** * Determine if the application has booted. * * @return bool */ public function isBooted() { return $this->booted; } /** * Boot the application's service providers. * * @return void */ public function boot() { if ($this->booted) { return; } // Once the application has booted we will also fire some "booted" callbacks // for any listeners that need to do work after this initial booting gets // finished. This is useful when ordering the boot-up processes we run. $this->fireAppCallbacks($this->bootingCallbacks); array_walk($this->serviceProviders, function ($p) { $this->bootProvider($p); }); $this->booted = true; $this->fireAppCallbacks($this->bootedCallbacks); } /** * Boot the given service provider. * * @param \Illuminate\Support\ServiceProvider $provider * @return mixed */ protected function bootProvider(ServiceProvider $provider) { if (method_exists($provider, 'boot')) { return $this->call([$provider, 'boot']); } } /** * Register a new boot listener. * * @param mixed $callback * @return void */ public function booting($callback) { $this->bootingCallbacks[] = $callback; } /** * Register a new "booted" listener. * * @param mixed $callback * @return void */ public function booted($callback) { $this->bootedCallbacks[] = $callback; if ($this->isBooted()) { $this->fireAppCallbacks([$callback]); } } /** * Call the booting callbacks for the application. * * @param array $callbacks * @return void */ protected function fireAppCallbacks(array $callbacks) { foreach ($callbacks as $callback) { call_user_func($callback, $this); } } /** * {@inheritdoc} */ public function handle(SymfonyRequest $request, $type = self::MASTER_REQUEST, $catch = true) { return $this['Illuminate\Contracts\Http\Kernel']->handle(Request::createFromBase($request)); } /** * Determine if middleware has been disabled for the application. * * @return bool */ public function shouldSkipMiddleware() { return $this->bound('middleware.disable') && $this->make('middleware.disable') === true; } /** * Determine if the application configuration is cached. * * @return bool */ public function configurationIsCached() { return file_exists($this->getCachedConfigPath()); } /** * Get the path to the configuration cache file. * * @return string */ public function getCachedConfigPath() { return $this->bootstrapPath().'/cache/config.php'; } /** * Determine if the application routes are cached. * * @return bool */ public function routesAreCached() { return $this['files']->exists($this->getCachedRoutesPath()); } /** * Get the path to the routes cache file. * * @return string */ public function getCachedRoutesPath() { return $this->bootstrapPath().'/cache/routes.php'; } /** * Get the path to the cached "compiled.php" file. * * @return string */ public function getCachedCompilePath() { return $this->bootstrapPath().'/cache/compiled.php'; } /** * Get the path to the cached services.php file. * * @return string */ public function getCachedServicesPath() { return $this->bootstrapPath().'/cache/services.php'; } /** * Determine if the application is currently down for maintenance. * * @return bool */ public function isDownForMaintenance() { return file_exists($this->storagePath().'/framework/down'); } /** * Throw an HttpException with the given data. * * @param int $code * @param string $message * @param array $headers * @return void * * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ public function abort($code, $message = '', array $headers = []) { if ($code == 404) { throw new NotFoundHttpException($message); } throw new HttpException($code, $message, null, $headers); } /** * Register a terminating callback with the application. * * @param \Closure $callback * @return $this */ public function terminating(Closure $callback) { $this->terminatingCallbacks[] = $callback; return $this; } /** * Terminate the application. * * @return void */ public function terminate() { foreach ($this->terminatingCallbacks as $terminating) { $this->call($terminating); } } /** * Get the service providers that have been loaded. * * @return array */ public function getLoadedProviders() { return $this->loadedProviders; } /** * Get the application's deferred services. * * @return array */ public function getDeferredServices() { return $this->deferredServices; } /** * Set the application's deferred services. * * @param array $services * @return void */ public function setDeferredServices(array $services) { $this->deferredServices = $services; } /** * Add an array of services to the application's deferred services. * * @param array $services * @return void */ public function addDeferredServices(array $services) { $this->deferredServices = array_merge($this->deferredServices, $services); } /** * Determine if the given service is a deferred service. * * @param string $service * @return bool */ public function isDeferredService($service) { return isset($this->deferredServices[$service]); } /** * Define a callback to be used to configure Monolog. * * @param callable $callback * @return $this */ public function configureMonologUsing(callable $callback) { $this->monologConfigurator = $callback; return $this; } /** * Determine if the application has a custom Monolog configurator. * * @return bool */ public function hasMonologConfigurator() { return ! is_null($this->monologConfigurator); } /** * Get the custom Monolog configurator for the application. * * @return callable */ public function getMonologConfigurator() { return $this->monologConfigurator; } /** * Get the current application locale. * * @return string */ public function getLocale() { return $this['config']->get('app.locale'); } /** * Set the current application locale. * * @param string $locale * @return void */ public function setLocale($locale) { $this['config']->set('app.locale', $locale); $this['translator']->setLocale($locale); $this['events']->fire('locale.changed', [$locale]); } /** * Determine if application locale is the given locale. * * @param string $locale * @return bool */ public function isLocale($locale) { return $this->getLocale() == $locale; } /** * Register the core class aliases in the container. * * @return void */ public function registerCoreContainerAliases() { $aliases = [ 'app' => ['Illuminate\Foundation\Application', 'Illuminate\Contracts\Container\Container', 'Illuminate\Contracts\Foundation\Application'], 'auth' => ['Illuminate\Auth\AuthManager', 'Illuminate\Contracts\Auth\Factory'], 'auth.driver' => ['Illuminate\Contracts\Auth\Guard'], 'blade.compiler' => ['Illuminate\View\Compilers\BladeCompiler'], 'cache' => ['Illuminate\Cache\CacheManager', 'Illuminate\Contracts\Cache\Factory'], 'cache.store' => ['Illuminate\Cache\Repository', 'Illuminate\Contracts\Cache\Repository'], 'config' => ['Illuminate\Config\Repository', 'Illuminate\Contracts\Config\Repository'], 'cookie' => ['Illuminate\Cookie\CookieJar', 'Illuminate\Contracts\Cookie\Factory', 'Illuminate\Contracts\Cookie\QueueingFactory'], 'encrypter' => ['Illuminate\Encryption\Encrypter', 'Illuminate\Contracts\Encryption\Encrypter'], 'db' => ['Illuminate\Database\DatabaseManager'], 'db.connection' => ['Illuminate\Database\Connection', 'Illuminate\Database\ConnectionInterface'], 'events' => ['Illuminate\Events\Dispatcher', 'Illuminate\Contracts\Events\Dispatcher'], 'files' => ['Illuminate\Filesystem\Filesystem'], 'filesystem' => ['Illuminate\Filesystem\FilesystemManager', 'Illuminate\Contracts\Filesystem\Factory'], 'filesystem.disk' => ['Illuminate\Contracts\Filesystem\Filesystem'], 'filesystem.cloud' => ['Illuminate\Contracts\Filesystem\Cloud'], 'hash' => ['Illuminate\Contracts\Hashing\Hasher'], 'translator' => ['Illuminate\Translation\Translator', 'Symfony\Component\Translation\TranslatorInterface'], 'log' => ['Illuminate\Log\Writer', 'Illuminate\Contracts\Logging\Log', 'Psr\Log\LoggerInterface'], 'mailer' => ['Illuminate\Mail\Mailer', 'Illuminate\Contracts\Mail\Mailer', 'Illuminate\Contracts\Mail\MailQueue'], 'auth.password' => ['Illuminate\Auth\Passwords\PasswordBrokerManager', 'Illuminate\Contracts\Auth\PasswordBrokerFactory'], 'auth.password.broker' => ['Illuminate\Auth\Passwords\PasswordBroker', 'Illuminate\Contracts\Auth\PasswordBroker'], 'queue' => ['Illuminate\Queue\QueueManager', 'Illuminate\Contracts\Queue\Factory', 'Illuminate\Contracts\Queue\Monitor'], 'queue.connection' => ['Illuminate\Contracts\Queue\Queue'], 'queue.failer' => ['Illuminate\Queue\Failed\FailedJobProviderInterface'], 'redirect' => ['Illuminate\Routing\Redirector'], 'redis' => ['Illuminate\Redis\Database', 'Illuminate\Contracts\Redis\Database'], 'request' => ['Illuminate\Http\Request', 'Symfony\Component\HttpFoundation\Request'], 'router' => ['Illuminate\Routing\Router', 'Illuminate\Contracts\Routing\Registrar'], 'session' => ['Illuminate\Session\SessionManager'], 'session.store' => ['Illuminate\Session\Store', 'Symfony\Component\HttpFoundation\Session\SessionInterface'], 'url' => ['Illuminate\Routing\UrlGenerator', 'Illuminate\Contracts\Routing\UrlGenerator'], 'validator' => ['Illuminate\Validation\Factory', 'Illuminate\Contracts\Validation\Factory'], 'view' => ['Illuminate\View\Factory', 'Illuminate\Contracts\View\Factory'], ]; foreach ($aliases as $key => $aliases) { foreach ($aliases as $alias) { $this->alias($key, $alias); } } } /** * Flush the container of all bindings and resolved instances. * * @return void */ public function flush() { parent::flush(); $this->loadedProviders = []; } /** * Get the application namespace. * * @return string * * @throws \RuntimeException */ public function getNamespace() { if (! is_null($this->namespace)) { return $this->namespace; } $composer = json_decode(file_get_contents(base_path('composer.json')), true); foreach ((array) data_get($composer, 'autoload.psr-4') as $namespace => $path) { foreach ((array) $path as $pathChoice) { if (realpath(app_path()) == realpath(base_path().'/'.$pathChoice)) { return $this->namespace = $namespace; } } } throw new RuntimeException('Unable to detect application namespace.'); } }