File: /home/xedaptot/be.naniguide.com/app/Verification/DriverRegistry.php
<?php
namespace App\Verification;
use App\Model\EmailVerificationServer;
use App\Verification\Capabilities\HasDocsLink;
use App\Verification\Capabilities\HasIcon;
use App\Verification\Drivers\VerificationDriver;
/**
* Static registry mapping verification vendor type → driver class.
*
* Source of truth: docs/verification/COMPREHENSIVE-DESIGN.md §6.
*
* Lifecycle:
* - Core drivers register in VerificationDriverServiceProvider::boot()
* - Plugin drivers register directly in plugin's ServiceProvider::boot()
* via DriverRegistry::register(...) — NOT via Hook.
* - Plugin uninstall fires Hook 'verification_driver_uninstall' → controller
* calls DriverRegistry::unregisterTypes() + force-deletes server rows.
*/
final class DriverRegistry
{
/** @var array<string, class-string<VerificationDriver>> */
private static array $map = [];
/**
* Register a driver class against its type ID.
*
* @param class-string<VerificationDriver> $driverClass
*/
public static function register(string $type, string $driverClass): void
{
if (!is_subclass_of($driverClass, VerificationDriver::class)) {
throw new \LogicException(
"Driver class {$driverClass} must implement " . VerificationDriver::class
);
}
if ($driverClass::type() !== $type) {
throw new \LogicException(
"Driver {$driverClass}::type() returned '{$driverClass::type()}', expected '{$type}'"
);
}
self::$map[$type] = $driverClass;
}
/**
* Resolve a fresh driver instance for the given EmailVerificationServer row.
*/
public static function resolve(EmailVerificationServer $server): VerificationDriver
{
$type = $server->type;
if (!isset(self::$map[$type])) {
throw new \LogicException("Unregistered verification driver type: {$type}");
}
return new (self::$map[$type])($server);
}
public static function has(?string $type): bool
{
return $type !== null && isset(self::$map[$type]);
}
/** @return array<string, class-string<VerificationDriver>> */
public static function all(): array
{
return self::$map;
}
/**
* Build admin/customer dropdown options from the static metadata of every
* registered driver. No driver instantiation — pure static lookup.
*
* @return list<array{value:string,text:string,url:string,icon:?string,docs:?string}>
*/
public static function typeOptions(): array
{
$opts = [];
foreach (self::$map as $type => $class) {
$opts[] = [
'value' => $type,
'text' => $class::displayName(),
'url' => $class::vendorUrl(),
'icon' => is_a($class, HasIcon::class, true) ? $class::iconUrl() : null,
'docs' => is_a($class, HasDocsLink::class, true) ? $class::docsUrl() : null,
];
}
return $opts;
}
/**
* Drop a set of types from the registry. Used by plugin lifecycle controller
* when admin disables a plugin (after force-deleting EmailVerificationServer rows).
*
* @param list<string> $types
*/
public static function unregisterTypes(array $types): void
{
foreach ($types as $type) {
unset(self::$map[$type]);
}
}
}