ValidatorStore.php
PHP
Path: src/Validator/ValidatorStore.php
<?php
namespace mini\Validator;
use mini\Util\InstanceStore;
use mini\Mini;
/**
* Registry for validator instances with auto-building from attributes
*
* Stores validators by class name or custom identifiers, optionally scoped by purpose.
* Automatically builds validators from class attributes when accessing unknown classes.
*
* ## Basic Usage
*
* ```php
* $store = Mini::$mini->get(ValidatorStore::class);
*
* // Register core validator (no purpose)
* $store->set(User::class, $coreValidator);
*
* // Register purpose-specific validators
* $store->set(User::class, $createValidator, Purpose::Create);
* $store->set(User::class, $updateValidator, Purpose::Update);
*
* // Custom purpose (string)
* $store->set(User::class, $passwordResetValidator, 'password-reset');
* ```
*
* ## Retrieval
*
* ```php
* $core = $store->get(User::class);
* $create = $store->get(User::class, Purpose::Create);
* $custom = $store->get(User::class, 'password-reset');
* ```
*
* @extends InstanceStore<Validator>
*/
class ValidatorStore extends InstanceStore
{
public function __construct()
{
parent::__construct(Validator::class);
}
/**
* Build cache key from class/identifier and optional purpose
*/
private function buildCacheKey(string $key, Purpose|string|null $purpose): string
{
if ($purpose === null) {
return $key;
}
$purposeString = $purpose instanceof Purpose ? $purpose->value : $purpose;
return $key . ':' . $purposeString;
}
/**
* Set a validator, optionally scoped by purpose
*
* @param string $key Class name or custom identifier
* @param Validator $value Validator instance
* @param Purpose|string|null $purpose Optional purpose scope
*/
public function set(mixed $key, mixed $value, Purpose|string|null $purpose = null): void
{
$cacheKey = $this->buildCacheKey($key, $purpose);
parent::set($cacheKey, $value);
}
/**
* Check if a validator exists, optionally scoped by purpose
*
* @param string $key Class name or custom identifier
* @param Purpose|string|null $purpose Optional purpose scope
*/
public function has(mixed $key, Purpose|string|null $purpose = null): bool
{
$cacheKey = $this->buildCacheKey($key, $purpose);
return parent::has($cacheKey);
}
/**
* Get validator by key, auto-building from class attributes if needed
*
* @param string $key Class name or custom identifier
* @param Purpose|string|null $purpose Optional purpose scope
* @return Validator|null Validator instance, or null if not found and not a class
*/
public function get(mixed $key, Purpose|string|null $purpose = null): mixed
{
$cacheKey = $this->buildCacheKey($key, $purpose);
// Return cached if exists
if (parent::has($cacheKey)) {
return parent::get($cacheKey);
}
// Auto-build from class attributes if class exists
if (class_exists($key) || interface_exists($key)) {
$factory = Mini::$mini->get(AttributeValidatorFactory::class);
$validator = $factory->forClass($key, $purpose);
// Cache it
parent::set($cacheKey, $validator);
return $validator;
}
// Not found and not a class
return null;
}
/**
* Magic getter - auto-builds from attributes if needed (core validator only)
*
* @param string $key
* @return Validator
* @throws \RuntimeException If key not found and not a valid class
*/
public function __get(mixed $key): mixed
{
$validator = $this->get($key);
if ($validator === null) {
throw new \RuntimeException("Validator '$key' not found. Register it in ValidatorStore or ensure the class exists.");
}
return $validator;
}
}