src/Validator/functions.php source

1 <?php
2
3 namespace mini;
4
5 use mini\Validator\Validator;
6 use mini\Validator\ValidatorStore;
7 use mini\Validator\AttributeValidatorFactory;
8 use mini\Validator\Purpose;
9
10 // Register Validator services
11 Mini::$mini->addService(Validator::class, Lifetime::Transient, fn() => new Validator());
12 Mini::$mini->addService(ValidatorStore::class, Lifetime::Singleton, fn() => new ValidatorStore());
13 Mini::$mini->addService(AttributeValidatorFactory::class, Lifetime::Singleton, fn() => new AttributeValidatorFactory());
14
15 /**
16 * Get or create a Validator instance
17 *
18 * With no arguments: Returns a new Validator for building validation rules.
19 * With class name: Returns the core validator (auto-built from class attributes).
20 * With class name + purpose: Returns the purpose-specific validator.
21 *
22 * ## Examples
23 *
24 * ```php
25 * // New validator for building rules
26 * $v = validator()->type('string')->minLength(5);
27 *
28 * // Core validator (auto-built from class attributes)
29 * $v = validator(User::class);
30 *
31 * // Purpose-specific validators
32 * $v = validator(User::class, Purpose::Create);
33 * $v = validator(User::class, Purpose::Update);
34 *
35 * // Custom purpose (string)
36 * $v = validator(User::class, 'password-reset');
37 * ```
38 *
39 * ## Validation Flow
40 *
41 * Purpose validation is done in the application layer:
42 * ```php
43 * // In controller/service
44 * if ($error = validator(User::class, Purpose::Create)->isInvalid($user)) {
45 * throw new ValidationException($error);
46 * }
47 * ```
48 *
49 * Core validation is done in the repository layer:
50 * ```php
51 * // In repository
52 * if ($error = validator(User::class)->isInvalid($user)) {
53 * throw new ValidationException($error);
54 * }
55 * ```
56 *
57 * @param class-string|string|null $classOrName Class name or custom identifier
58 * @param Purpose|string|null $purpose Optional purpose scope (Create, Update, or custom string)
59 * @return Validator Validator instance
60 * @throws \InvalidArgumentException If identifier not found and not a valid class
61 */
62 function validator(?string $classOrName = null, Purpose|string|null $purpose = null): Validator {
63 // No argument: return new validator
64 if ($classOrName === null) {
65 return Mini::$mini->get(Validator::class);
66 }
67
68 $store = Mini::$mini->get(ValidatorStore::class);
69
70 // Get from store (auto-builds from attributes if class/interface and no purpose)
71 $validator = $store->get($classOrName, $purpose);
72
73 if ($validator === null) {
74 // Standard purposes (Purpose enum) are opt-in: return empty validator
75 if ($purpose instanceof Purpose) {
76 return Mini::$mini->get(Validator::class);
77 }
78
79 // Custom string purposes and core validators: throw if not found
80 $msg = $purpose !== null
81 ? "Validator '$classOrName' with purpose '$purpose' not found. Register it in ValidatorStore."
82 : "Validator '$classOrName' not found. Register it in ValidatorStore or ensure the class exists.";
83 throw new \InvalidArgumentException($msg);
84 }
85
86 // Return clone to allow modifications without affecting cached version
87 return clone $validator;
88 }
89