1
0
mirror of https://github.com/flarum/core.git synced 2025-10-13 16:05:05 +02:00
Files
php-flarum/src/Foundation/Application.php
2019-07-06 00:03:25 +02:00

768 lines
19 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\Container\Container;
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
use Illuminate\Events\EventServiceProvider;
use Illuminate\Support\Arr;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
class Application extends Container implements ApplicationContract
{
/**
* The Flarum version.
*
* @var string
*/
const VERSION = '0.1.0-beta.9';
/**
* The base path for the Flarum installation.
*
* @var string
*/
protected $basePath;
/**
* The public path for the Flarum installation.
*
* @var string
*/
protected $publicPath;
/**
* The custom storage path defined by the developer.
*
* @var string
*/
protected $storagePath;
/**
* A custom vendor path to find dependencies in non-standard environments.
*
* @var string
*/
protected $vendorPath;
/**
* 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 = [];
/**
* Create a new Flarum application instance.
*
* @param string|null $basePath
* @param string|null $publicPath
*/
public function __construct($basePath = null, $publicPath = null)
{
$this->registerBaseBindings();
$this->registerBaseServiceProviders();
$this->registerCoreContainerAliases();
if ($basePath) {
$this->setBasePath($basePath);
}
if ($publicPath) {
$this->setPublicPath($publicPath);
}
}
/**
* @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->config('debug', true);
}
/**
* Get the URL to the Flarum installation.
*
* @param string $path
* @return string
*/
public function url($path = null)
{
$config = $this->make('flarum.config');
$url = array_get($config, 'url', array_get($_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(Container::class, $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;
}
/**
* Set the public path for the application.
*
* @param string $publicPath
* @return $this
*/
public function setPublicPath($publicPath)
{
$this->publicPath = rtrim($publicPath, '\/');
$this->bindPathsInContainer();
return $this;
}
/**
* Bind all of the application paths in the container.
*
* @return void
*/
protected function bindPathsInContainer()
{
foreach (['base', 'public', 'storage', 'vendor'] 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->publicPath;
}
/**
* Get the path to the storage directory.
*
* @return string
*/
public function storagePath()
{
return $this->storagePath ?: $this->basePath.DIRECTORY_SEPARATOR.'storage';
}
/**
* Get the path to the vendor directory where dependencies are installed.
*
* @return string
*/
public function vendorPath()
{
return $this->vendorPath ?: $this->basePath.DIRECTORY_SEPARATOR.'vendor';
}
/**
* Set the storage directory.
*
* @param string $path
* @return $this
*/
public function useStoragePath($path)
{
$this->storagePath = $path;
$this->instance('path.storage', $path);
return $this;
}
/**
* Set the vendor directory.
*
* @param string $path
* @return $this
*/
public function useVendorPath($path)
{
$this->vendorPath = $path;
$this->instance('path.vendor', $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 $this->config('offline');
}
/**
* 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' => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
'blade.compiler' => [\Illuminate\View\Compilers\BladeCompiler::class],
'cache' => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
'cache.store' => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class],
'config' => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
'db' => [\Illuminate\Database\DatabaseManager::class],
'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
'events' => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
'files' => [\Illuminate\Filesystem\Filesystem::class],
'filesystem' => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class],
'filesystem.disk' => [\Illuminate\Contracts\Filesystem\Filesystem::class],
'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class],
'hash' => [\Illuminate\Contracts\Hashing\Hasher::class],
'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
'validator' => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
];
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 = [];
}
/**
* Get the path to the cached packages.php file.
*
* @return string
*/
public function getCachedPackagesPath()
{
return storage_path('app/cache/packages.php');
}
/**
* @return string
*/
public function resourcePath()
{
return storage_path('resources');
}
}