<?php
namespace Illuminate\Support\Facades;
use Closure;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Js;
use Illuminate\Support\Str;
use Mockery;
use Mockery\LegacyMockInterface;
use RuntimeException;
abstract class Facade
{
/**
* The application instance being facaded.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected static $app;
/**
* The resolved object instances.
*
* @var array
*/
protected static $resolvedInstance;
/**
* Indicates if the resolved instance should be cached.
*
* @var bool
*/
protected static $cached = true;
/**
* Run a Closure when the facade has been resolved.
*
* @param \Closure $callback
* @return void
*/
public static function resolved(Closure $callback)
{
$accessor = static::getFacadeAccessor();
if (static::$app->resolved($accessor) === true) {
$callback(static::getFacadeRoot());
}
static::$app->afterResolving($accessor, function ($service) use ($callback) {
$callback($service);
});
}
/**
* Convert the facade into a Mockery spy.
*
* @return \Mockery\MockInterface
*/
public static function spy()
{
if (! static::isMock()) {
$class = static::getMockableClass();
return tap($class ? Mockery::spy($class) : Mockery::spy(), function ($spy) {
static::swap($spy);
});
}
}
/**
* Initiate a partial mock on the facade.
*
* @return \Mockery\MockInterface
*/
public static function partialMock()
{
$name = static::getFacadeAccessor();
$mock = static::isMock()
? static::$resolvedInstance[$name]
: static::createFreshMockInstance();
return $mock->makePartial();
}
/**
* Initiate a mock expectation on the facade.
*
* @return \Mockery\Expectation
*/
public static function shouldReceive()
{
$name = static::getFacadeAccessor();
$mock = static::isMock()
? static::$resolvedInstance[$name]
: static::createFreshMockInstance();
return $mock->shouldReceive(...func_get_args());
}
/**
* Initiate a mock expectation on the facade.
*
* @return \Mockery\Expectation
*/
public static function expects()
{
$name = static::getFacadeAccessor();
$mock = static::isMock()
? static::$resolvedInstance[$name]
: static::createFreshMockInstance();
return $mock->expects(...func_get_args());
}
/**
* Create a fresh mock instance for the given class.
*
* @return \Mockery\MockInterface
*/
protected static function createFreshMockInstance()
{
return tap(static::createMock(), function ($mock) {
static::swap($mock);
$mock->shouldAllowMockingProtectedMethods();
});
}
/**
* Create a fresh mock instance for the given class.
*
* @return \Mockery\MockInterface
*/
protected static function createMock()
{
$class = static::getMockableClass();
return $class ? Mockery::mock($class) : Mockery::mock();
}
/**
* Determines whether a mock is set as the instance of the facade.
*
* @return bool
*/
protected static function isMock()
{
$name = static::getFacadeAccessor();
return isset(static::$resolvedInstance[$name]) &&
static::$resolvedInstance[$name] instanceof LegacyMockInterface;
}
/**
* Get the mockable class for the bound instance.
*
* @return string|null
*/
protected static function getMockableClass()
{
if ($root = static::getFacadeRoot()) {
return get_class($root);
}
}
/**
* Hotswap the underlying instance behind the facade.
*
* @param mixed $instance
* @return void
*/
public static function swap($instance)
{
static::$resolvedInstance[static::getFacadeAccessor()] = $instance;
if (isset(static::$app)) {
static::$app->instance(static::getFacadeAccessor(), $instance);
}
}
/**
* Get the root object behind the facade.
*
* @return mixed
*/
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
/**
* Get the registered name of the component.
*
* @return string
*
* @throws \RuntimeException
*/
protected static function getFacadeAccessor()
{
throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
}
/**
* Resolve the facade root instance from the container.
*
* @param string $name
* @return mixed
*/
protected static function resolveFacadeInstance($name)
{
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
if (static::$app) {
if (static::$cached) {
return static::$resolvedInstance[$name] = static::$app[$name];
}
return static::$app[$name];
}
}
/**
* Clear a resolved facade instance.
*
* @param string $name
* @return void
*/
public static function clearResolvedInstance($name)
{
unset(static::$resolvedInstance[$name]);
}
/**
* Clear all of the resolved instances.
*
* @return void
*/
public static function clearResolvedInstances()
{
static::$resolvedInstance = [];
}
/**
* Get the application default aliases.
*
* @return \Illuminate\Support\Collection
*/
public static function defaultAliases()
{
return collect([
'App' => App::class,
'Arr' => Arr::class,
'Artisan' => Artisan::class,
'Auth' => Auth::class,
'Blade' => Blade::class,
'Broadcast' => Broadcast::class,
'Bus' => Bus::class,
'Cache' => Cache::class,
'Config' => Config::class,
'Cookie' => Cookie::class,
'Crypt' => Crypt::class,
'Date' => Date::class,
'DB' => DB::class,
'Eloquent' => Model::class,
'Event' => Event::class,
'File' => File::class,
'Gate' => Gate::class,
'Hash' => Hash::class,
'Http' => Http::class,
'Js' => Js::class,
'Lang' => Lang::class,
'Log' => Log::class,
'Mail' => Mail::class,
'Notification' => Notification::class,
'Password' => Password::class,
'Queue' => Queue::class,
'RateLimiter' => RateLimiter::class,
'Redirect' => Redirect::class,
'Request' => Request::class,
'Response' => Response::class,
'Route' => Route::class,
'Schema' => Schema::class,
'Session' => Session::class,
'Storage' => Storage::class,
'Str' => Str::class,
'URL' => URL::class,
'Validator' => Validator::class,
'View' => View::class,
'Vite' => Vite::class,
]);
}
/**
* Get the application instance behind the facade.
*
* @return \Illuminate\Contracts\Foundation\Application
*/
public static function getFacadeApplication()
{
return static::$app;
}
/**
* Set the application instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public static function setFacadeApplication($app)
{
static::$app = $app;
}
/**
* Handle dynamic, static calls to the object.
*
* @param string $method
* @param array $args
* @return mixed
*
* @throws \RuntimeException
*/
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
}