Files
Php-Template/src/Services/Facade.php
Ron Rise 56b78f0102
All checks were successful
🧪✨ Tests Workflow / 📝 ✨ Code Lint (push) Successful in 1m53s
🧪✨ Tests Workflow / 🛡️ 🔒 Library Audit (push) Successful in 2m4s
🧪✨ Tests Workflow / 🛡️ 🔒 License Check (push) Successful in 2m7s
🧪✨ Tests Workflow / 🐙 🔍 Code Sniffer (push) Successful in 1m57s
🧪✨ Tests Workflow / 🧪 ✨ Database Migrations (push) Successful in 2m44s
🧪✨ Tests Workflow / 🧪 ✅ Unit Tests (push) Successful in 52s
🏗️✨ Build Workflow / 🖥️ 🔨 Build (push) Successful in 3m13s
refactor: update facade structure and add service providers for logging and Redis (#4)
Reviewed-on: #4
Co-authored-by: Ron Rise <ron@siteworxpro.com>
Co-committed-by: Ron Rise <ron@siteworxpro.com>
2025-10-15 15:39:25 +00:00

309 lines
7.4 KiB
PHP

<?php
declare(strict_types=1);
namespace Siteworxpro\App\Services;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Testing\Fakes\Fake;
use Mockery;
use Mockery\Expectation;
use Mockery\ExpectationInterface;
use Mockery\LegacyMockInterface;
use Mockery\MockInterface;
class Facade
{
/**
* The application instance being facaded.
*
* @var Container | null
*/
protected static ?Container $container = null;
/**
* The resolved object instances.
*
* @var array
*/
protected static array $resolvedInstance;
/**
* Indicates if the resolved instance should be cached.
*
* @var bool
*/
protected static bool $cached = true;
/**
* Run a Closure when the facade has been resolved.
*
* @param \Closure $callback
* @return void
*/
public static function resolved(\Closure $callback): void
{
$accessor = static::getFacadeAccessor();
if (static::$container->resolved($accessor) === true) {
$callback(static::getFacadeRoot(), static::$container);
}
static::$container->afterResolving($accessor, function ($service, $app) use ($callback) {
$callback($service, $app);
});
}
/**
* Convert the facade into a Mockery spy.
*
* @return MockInterface
*/
public static function spy(): MockInterface
{
if (! static::isMock()) {
$class = static::getMockableClass();
return tap($class ? Mockery::spy($class) : Mockery::spy(), function ($spy) {
static::swap($spy);
});
}
throw new \RuntimeException('Cannot spy on an existing mock instance.');
}
/**
* Initiate a partial mock on the facade.
*
* @return MockInterface
*/
public static function partialMock(): MockInterface
{
$name = static::getFacadeAccessor();
$mock = static::isMock()
? static::$resolvedInstance[$name]
: static::createFreshMockInstance();
return $mock->makePartial();
}
/**
* Initiate a mock expectation on the facade.
*
* @return Expectation|ExpectationInterface
*/
public static function shouldReceive(): Mockery\Expectation | Mockery\ExpectationInterface
{
$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 Expectation|ExpectationInterface
*/
public static function expects(): Mockery\Expectation | Mockery\ExpectationInterface
{
$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 MockInterface|LegacyMockInterface
*/
protected static function createFreshMockInstance(): MockInterface | LegacyMockInterface
{
return tap(static::createMock(), function ($mock) {
static::swap($mock);
$mock->shouldAllowMockingProtectedMethods();
});
}
/**
* Create a fresh mock instance for the given class.
*
* @return MockInterface
*/
protected static function createMock(): MockInterface
{
$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(): bool
{
$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(): ?string
{
if ($root = static::getFacadeRoot()) {
return get_class($root);
}
return null;
}
/**
* Hotswap the underlying instance behind the facade.
*
* @param mixed $instance
* @return void
*/
public static function swap(mixed $instance): void
{
static::$resolvedInstance[static::getFacadeAccessor()] = $instance;
if (isset(static::$container)) {
static::$container->instance(static::getFacadeAccessor(), $instance);
}
}
/**
* Determines whether a "fake" has been set as the facade instance.
*
* @return bool
*/
public static function isFake(): bool
{
$name = static::getFacadeAccessor();
return isset(static::$resolvedInstance[$name]) &&
static::$resolvedInstance[$name] instanceof Fake;
}
/**
* Get the root object behind the facade.
*
* @return mixed
*/
public static function getFacadeRoot(): mixed
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
/**
* Get the registered name of the component.
*
* @return string
*
* @throws \RuntimeException
*/
protected static function getFacadeAccessor(): string
{
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(string $name): mixed
{
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
if (static::$container) {
if (static::$cached) {
return static::$resolvedInstance[$name] = static::$container[$name];
}
return static::$container[$name];
}
return null;
}
/**
* Clear a resolved facade instance.
*
* @param string $name
* @return void
*/
public static function clearResolvedInstance(string $name): void
{
unset(static::$resolvedInstance[$name]);
}
/**
* Clear all of the resolved instances.
*
* @return void
*/
public static function clearResolvedInstances(): void
{
static::$resolvedInstance = [];
}
/**
* Get the application instance behind the facade.
*/
public static function getFacadeContainer(): ?Container
{
return static::$container;
}
/**
* Set the application instance.
*
* @param Container $container
* @return void
*/
public static function setFacadeContainer(Container $container): void
{
static::$container = $container;
}
/**
* Handle dynamic, static calls to the object.
*
* @param string $method
* @param array $args
* @return mixed
*
* @throws \RuntimeException
*/
public static function __callStatic(string $method, array $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new \RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
}