99use Illuminate \Contracts \Http \Kernel as KernelContract ;
1010use Illuminate \Contracts \Validation \Factory ;
1111use Illuminate \Routing \Router ;
12- use Illuminate \Support \Collection ;
12+ use Illuminate \Support \Facades \ Blade ;
1313use Illuminate \Support \Str ;
14+ use Illuminate \View \Compilers \BladeCompiler ;
15+ use Laragear \Meta \Attributes \RegisterRule ;
1416use Laragear \Meta \Http \Middleware \MiddlewareDeclaration ;
15- use SplFileInfo ;
17+ use ReflectionClass ;
1618
1719use function array_fill ;
1820use function array_fill_keys ;
1921use function count ;
2022use function is_callable ;
2123use function is_string ;
22- use function method_exists ;
23- use function now ;
2424
2525trait BootHelpers
2626{
27+ /**
28+ * Cached closures for registered validation rules.
29+ *
30+ * @var array<class-string, \Closure>
31+ */
32+ protected static array $ cachedValidationRules = [];
33+
2734 /**
2835 * Extends a manager-like service.
2936 *
@@ -58,7 +65,7 @@ protected function withValidationRule(
5865 string $ rule ,
5966 callable |string $ callback ,
6067 callable |string |null $ message = null ,
61- bool $ implicit = false
68+ bool $ implicit = false ,
6269 ): void {
6370 $ this ->callAfterResolving (
6471 'validator ' ,
@@ -68,7 +75,45 @@ static function (Factory $validator, Application $app) use ($message, $callback,
6875 $ implicit
6976 ? $ validator ->extendImplicit ($ rule , $ callback , $ message )
7077 : $ validator ->extend ($ rule , $ callback , $ message );
71- }
78+ },
79+ );
80+ }
81+
82+ /**
83+ * Registers all Validation Rules found in a directory with a message from a translation prefix.
84+ *
85+ * @param class-string|class-string[] $classes
86+ * @param string $keyPrefix If you register a translation key as "my-package", the validation
87+ * rules will use "my-package::validation.{rule}".
88+ */
89+ protected function withValidationRulesFrom (string |array $ classes , string $ keyPrefix ): void
90+ {
91+ $ this ->callAfterResolving (
92+ 'validator ' ,
93+ static function (Factory $ validator ) use ($ classes , $ keyPrefix ): void {
94+ foreach ((array ) $ classes as $ class ) {
95+ if (! isset (static ::$ cachedValidationRules [$ class ])) {
96+ static ::$ cachedValidationRules [$ class ] = [];
97+
98+ foreach ((new ReflectionClass ($ class ))->getMethods () as $ method ) {
99+ /** @var \Laragear\Meta\Attributes\RegisterRule|null $attribute */
100+ if ($ method ->isPublic () && $ method ->isStatic () && $ attribute = Attr::of ($ method )->first (RegisterRule::class)) {
101+ static ::$ cachedValidationRules [$ class ][$ attribute ->name ] = [
102+ $ method ->getClosure (),
103+ "$ keyPrefix::validation. " .($ attribute ->translationKey ?: Str::snake ($ method ->getName ())),
104+ $ attribute ->implicit ,
105+ ];
106+ }
107+ }
108+ }
109+
110+ foreach (static ::$ cachedValidationRules [$ class ] as $ name => [$ callback , $ message , $ implicit ]) {
111+ $ implicit
112+ ? $ validator ->extendImplicit ($ name , $ callback , $ message )
113+ : $ validator ->extend ($ name , $ callback , $ message );
114+ }
115+ }
116+ },
72117 );
73118 }
74119
@@ -83,7 +128,7 @@ static function (Factory $validator, Application $app) use ($message, $callback,
83128 protected function withMiddleware (string $ class ): MiddlewareDeclaration
84129 {
85130 return new MiddlewareDeclaration (
86- $ this ->app ->make (Router::class), $ this ->app ->make (KernelContract::class), $ class
131+ $ this ->app ->make (Router::class), $ this ->app ->make (KernelContract::class), $ class,
87132 );
88133 }
89134
@@ -142,7 +187,6 @@ protected function withPolicy(string $model, string $policy): void
142187 * Schedule a Job or Command using a callback.
143188 *
144189 * @param callable(\Illuminate\Console\Scheduling\Schedule):mixed $callback
145- * @return void
146190 *
147191 * @see https://www.laravelpackage.com/06-artisan-commands/#scheduling-a-command-in-the-service-provider
148192 */
@@ -165,8 +209,57 @@ protected function withPublishableMigrations(array|string $directories, array|st
165209 $ directories = (array ) $ directories ;
166210
167211 $ this ->publishesMigrations (array_fill_keys (
168- $ directories , array_fill (0 , count ($ directories ), $ this ->app ->databasePath ('migrations ' ))
212+ $ directories , array_fill (0 , count ($ directories ), $ this ->app ->databasePath ('migrations ' )),
169213 ), $ groups );
170214 }
171215 }
216+
217+ /**
218+ * Registers a simple Blade directive.
219+ *
220+ * @param array<string, callable>|string $name
221+ * @param ($name is string ? callable : null) $handler
222+ */
223+ protected function withBladeDirectives (string |array $ name , ?callable $ handler = null ): void
224+ {
225+ $ name = $ handler ? [$ name => $ handler ] : $ name ;
226+
227+ $ this ->callAfterResolving (
228+ BladeCompiler::class,
229+ static function (BladeCompiler $ blade ) use ($ name ): void {
230+ foreach ($ name as $ key => $ handler ) {
231+ $ blade ->directive ($ key , $ handler );
232+ }
233+ },
234+ );
235+ }
236+
237+ /**
238+ * Registers a directory of Blade components under a prefix.
239+ */
240+ protected function withBladeComponents (string $ path , string $ prefix ): void
241+ {
242+ $ this ->callAfterResolving (
243+ BladeCompiler::class,
244+ static function (BladeCompiler $ blade ) use ($ path , $ prefix ): void {
245+ $ blade ->componentNamespace ($ path , $ prefix );
246+ },
247+ );
248+ }
249+
250+ /**
251+ * Returns the cached validation rules.
252+ */
253+ public static function cachedValidationRules (): array
254+ {
255+ return static ::$ cachedValidationRules ;
256+ }
257+
258+ /**
259+ * Flushes cached validation rules retrieved by reflection.
260+ */
261+ public static function flushCachedValidationRules (): void
262+ {
263+ static ::$ cachedValidationRules = [];
264+ }
172265}
0 commit comments