mirror of
https://github.com/flarum/core.git
synced 2025-10-13 16:05:05 +02:00
699 lines
17 KiB
PHP
699 lines
17 KiB
PHP
<?php
|
|
/*
|
|
* This file is part of Flarum.
|
|
*
|
|
* (c) Toby Zerner <toby.zerner@gmail.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Flarum\Foundation;
|
|
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\ServiceProvider;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Container\Container;
|
|
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
|
|
use Illuminate\Events\EventServiceProvider;
|
|
|
|
class Application extends Container implements ApplicationContract
|
|
{
|
|
/**
|
|
* The Flarum version.
|
|
*
|
|
* @var string
|
|
*/
|
|
const VERSION = '0.1.0-beta.2';
|
|
|
|
/**
|
|
* The base path for the Flarum installation.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $basePath;
|
|
|
|
/**
|
|
* 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 = [];
|
|
|
|
/**
|
|
* 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 = [];
|
|
|
|
/**
|
|
* The custom storage path defined by the developer.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $storagePath;
|
|
|
|
/**
|
|
* Create a new Flarum application instance.
|
|
*
|
|
* @param string|null $basePath
|
|
*/
|
|
public function __construct($basePath = null)
|
|
{
|
|
$this->registerBaseBindings();
|
|
|
|
$this->registerBaseServiceProviders();
|
|
|
|
$this->registerCoreContainerAliases();
|
|
|
|
if ($basePath) {
|
|
$this->setBasePath($basePath);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determine if Flarum has been installed.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isInstalled()
|
|
{
|
|
return $this->bound('flarum.config');
|
|
}
|
|
|
|
/**
|
|
* @param string $key
|
|
* @param mixed $default
|
|
* @return mixed
|
|
*/
|
|
public function config($key, $default = null)
|
|
{
|
|
return array_get($this->make('flarum.config'), $key, $default);
|
|
}
|
|
|
|
/**
|
|
* Check if Flarum is in debug mode.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function inDebugMode()
|
|
{
|
|
return ! $this->isInstalled() || $this->config('debug');
|
|
}
|
|
|
|
/**
|
|
* Get the URL to the Flarum installation.
|
|
*
|
|
* @param string $path
|
|
* @return string
|
|
*/
|
|
public function url($path = null)
|
|
{
|
|
$config = $this->isInstalled() ? $this->make('flarum.config') : [];
|
|
$url = array_get($config, 'url', $_SERVER['REQUEST_URI']);
|
|
|
|
if (is_array($url)) {
|
|
if (isset($url[$path])) {
|
|
return $url[$path];
|
|
}
|
|
|
|
$url = $url['base'];
|
|
}
|
|
|
|
if ($path) {
|
|
$url .= '/' . array_get($config, "paths.$path", $path);
|
|
}
|
|
|
|
return $url;
|
|
}
|
|
|
|
/**
|
|
* Get the version number of the application.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function version()
|
|
{
|
|
return static::VERSION;
|
|
}
|
|
|
|
/**
|
|
* Register the basic bindings into the container.
|
|
*/
|
|
protected function registerBaseBindings()
|
|
{
|
|
static::setInstance($this);
|
|
|
|
$this->instance('app', $this);
|
|
|
|
$this->instance('Illuminate\Container\Container', $this);
|
|
}
|
|
|
|
/**
|
|
* Register all of the base service providers.
|
|
*/
|
|
protected function registerBaseServiceProviders()
|
|
{
|
|
$this->register(new EventServiceProvider($this));
|
|
}
|
|
|
|
/**
|
|
* 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()
|
|
{
|
|
foreach (['base', 'public', 'storage'] as $path) {
|
|
$this->instance('path.'.$path, $this->{$path.'Path'}());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the base path of the Laravel installation.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function basePath()
|
|
{
|
|
return $this->basePath;
|
|
}
|
|
|
|
/**
|
|
* Get the path to the public / web directory.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function publicPath()
|
|
{
|
|
return $this->basePath;
|
|
}
|
|
|
|
/**
|
|
* 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 or check the current application environment.
|
|
*
|
|
* @param mixed
|
|
* @return string
|
|
*/
|
|
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 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()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Register a service provider with the application.
|
|
*
|
|
* @param ServiceProvider|string $provider
|
|
* @param array $options
|
|
* @param bool $force
|
|
* @return 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 ServiceProvider|string $provider
|
|
* @return 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 ServiceProvider
|
|
*/
|
|
public function resolveProviderClass($provider)
|
|
{
|
|
return new $provider($this);
|
|
}
|
|
|
|
/**
|
|
* Mark the given provider as registered.
|
|
*
|
|
* @param 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.
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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 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);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the path to the cached "compiled.php" file.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getCachedCompilePath()
|
|
{
|
|
return $this->basePath().'/bootstrap/cache/compiled.php';
|
|
}
|
|
|
|
/**
|
|
* Get the path to the cached services.json file.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getCachedServicesPath()
|
|
{
|
|
return $this->basePath().'/bootstrap/cache/services.json';
|
|
}
|
|
|
|
/**
|
|
* Determine if the application is currently down for maintenance.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isDownForMaintenance()
|
|
{
|
|
return file_exists($this->storagePath().'/framework/down');
|
|
}
|
|
|
|
/**
|
|
* 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]);
|
|
}
|
|
|
|
/**
|
|
* Register the core class aliases in the container.
|
|
*/
|
|
public function registerCoreContainerAliases()
|
|
{
|
|
$aliases = [
|
|
'app' => ['Flarum\Foundation\Application', 'Illuminate\Contracts\Container\Container', 'Illuminate\Contracts\Foundation\Application'],
|
|
'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'],
|
|
'db' => 'Illuminate\Database\DatabaseManager',
|
|
'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',
|
|
'mailer' => ['Illuminate\Mail\Mailer', 'Illuminate\Contracts\Mail\Mailer', 'Illuminate\Contracts\Mail\MailQueue'],
|
|
'validator' => ['Illuminate\Validation\Factory', 'Illuminate\Contracts\Validation\Factory'],
|
|
'view' => ['Illuminate\View\Factory', 'Illuminate\Contracts\View\Factory'],
|
|
];
|
|
|
|
foreach ($aliases as $key => $aliases) {
|
|
foreach ((array) $aliases as $alias) {
|
|
$this->alias($key, $alias);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flush the container of all bindings and resolved instances.
|
|
*/
|
|
public function flush()
|
|
{
|
|
parent::flush();
|
|
|
|
$this->loadedProviders = [];
|
|
}
|
|
}
|