7
7
use Closure ;
8
8
use Illuminate \Contracts \View \View ;
9
9
use Illuminate \Support \Collection ;
10
+ use Illuminate \Support \Facades \Validator ;
11
+ use Illuminate \Validation \ValidationException ;
10
12
use MoonShine \AssetManager \Js ;
11
13
use MoonShine \Contracts \Core \HasComponentsContract ;
12
14
use MoonShine \Contracts \Core \PageContract ;
@@ -50,6 +52,8 @@ final class Layouts extends Field
50
52
51
53
private ?PageContract $ page = null ;
52
54
55
+ private array $ rules = [];
56
+
53
57
protected function assets (): array
54
58
{
55
59
return [
@@ -63,15 +67,20 @@ public function addLayout(
63
67
iterable $ fields ,
64
68
?int $ limit = null ,
65
69
?iterable $ headingAdditionalFields = null ,
70
+ array $ validation = [],
66
71
): self {
67
72
$ this ->layouts [] = new Layout (
68
73
$ title ,
69
74
$ name ,
70
75
$ fields ,
71
76
$ limit ,
72
- $ headingAdditionalFields
77
+ $ headingAdditionalFields,
73
78
);
74
79
80
+ if ($ validation !== []) {
81
+ $ this ->rules [$ name ] = $ validation ;
82
+ }
83
+
75
84
return $ this ;
76
85
}
77
86
@@ -101,7 +110,7 @@ public function getLayoutButtons(): array
101
110
->map (
102
111
fn (LayoutContract $ layout ) => Link::make ('# ' , $ layout ->title ())
103
112
->icon ('plus ' )
104
- ->customAttributes (['@click.prevent ' => "add(` {$ layout ->name ()}`);closeDropdown() " ])
113
+ ->customAttributes (['@click.prevent ' => "add(` {$ layout ->name ()}`);closeDropdown() " ]),
105
114
)
106
115
->toArray ();
107
116
}
@@ -119,7 +128,7 @@ public function getFilledLayouts(): LayoutCollection
119
128
$ this ->getData ()->getOriginal (),
120
129
$ this ->getColumn (),
121
130
$ values ,
122
- []
131
+ [],
123
132
);
124
133
}
125
134
@@ -133,17 +142,17 @@ public function getFilledLayouts(): LayoutCollection
133
142
134
143
$ layout = clone $ layout ->when (
135
144
$ this ->disableSort ,
136
- fn (Layout $ l ): Layout => $ l ->disableSort ()
145
+ fn (Layout $ l ): Layout => $ l ->disableSort (),
137
146
)
138
147
->when (
139
148
$ this ->isPreviewMode (),
140
- fn (Layout $ l ): Layout => $ l ->forcePreview ()
149
+ fn (Layout $ l ): Layout => $ l ->forcePreview (),
141
150
)
142
151
->setKey ($ data ->getKey ());
143
152
144
153
$ fields = $ this ->fillClonedRecursively (
145
154
$ layout ->fields (),
146
- $ data ->getValues ()
155
+ $ data ->getValues (),
147
156
);
148
157
149
158
$ layout
@@ -152,14 +161,14 @@ public function getFilledLayouts(): LayoutCollection
152
161
->prepend (
153
162
Hidden::make ('_layout ' )
154
163
->customAttributes (['class ' => '_layout-value ' ])
155
- ->setValue ($ data ->getName ())
164
+ ->setValue ($ data ->getName ()),
156
165
)
157
166
->prepareAttributes ()
158
167
->prepareReindexNames ($ this );
159
168
160
169
$ fields = $ this ->fillClonedRecursively (
161
170
$ layout ->getHeadingAdditionalFields (),
162
- $ data ->getValues ()
171
+ $ data ->getValues (),
163
172
);
164
173
165
174
$ layout
@@ -176,13 +185,13 @@ private function fillClonedRecursively(ComponentsContract|Collection $collection
176
185
return $ collection ->map (function (mixed $ item ) use ($ data ) {
177
186
if ($ item instanceof HasComponentsContract) {
178
187
$ item = (clone $ item )->setComponents (
179
- $ this ->fillClonedRecursively ($ item ->getComponents (), $ data )->toArray ()
188
+ $ this ->fillClonedRecursively ($ item ->getComponents (), $ data )->toArray (),
180
189
);
181
190
}
182
191
183
192
if ($ item instanceof HasFieldsContract) {
184
193
$ item = (clone $ item )->fields (
185
- $ this ->fillClonedRecursively ($ item ->getFields (), $ data )->toArray ()
194
+ $ this ->fillClonedRecursively ($ item ->getFields (), $ data )->toArray (),
186
195
);
187
196
}
188
197
@@ -289,6 +298,13 @@ protected function resolvePreview(): View|string
289
298
->render ();
290
299
}
291
300
301
+ public function validation (array $ rules ): self
302
+ {
303
+ $ this ->rules = array_merge_recursive ($ this ->rules , $ rules );
304
+
305
+ return $ this ;
306
+ }
307
+
292
308
protected function resolveOnApply (): ?Closure
293
309
{
294
310
return function ($ item ) {
@@ -308,20 +324,20 @@ protected function resolveOnApply(): ?Closure
308
324
function (Field $ field ) use ($ value , $ index , &$ applyValues ): void {
309
325
$ field ->appendRequestKeyPrefix (
310
326
"{$ this ->getColumn ()}. $ index " ,
311
- $ this ->getRequestKeyPrefix ()
327
+ $ this ->getRequestKeyPrefix (),
312
328
);
313
329
314
330
$ apply = $ field ->apply (
315
331
fn ($ data ): mixed => data_set ($ data , $ field ->getColumn (), $ value [$ field ->getColumn ()] ?? '' ),
316
- $ value
332
+ $ value,
317
333
);
318
334
319
335
data_set (
320
336
$ applyValues ,
321
337
$ field ->getColumn (),
322
- data_get ($ apply , $ field ->getColumn ())
338
+ data_get ($ apply , $ field ->getColumn ()),
323
339
);
324
- }
340
+ },
325
341
);
326
342
327
343
return [
@@ -342,6 +358,39 @@ function (Field $field) use ($value, $index, &$applyValues): void {
342
358
*/
343
359
protected function resolveBeforeApply (mixed $ data ): mixed
344
360
{
361
+ if ($ this ->rules !== []) {
362
+ $ value = $ this ->getRequestValue ();
363
+
364
+ if (!is_array ($ value )) {
365
+ $ value = [];
366
+ }
367
+
368
+ $ value = Collection::make ($ value )->mapToGroups (function ($ v ) {
369
+ return [$ v ['_layout ' ] => $ v ];
370
+ });
371
+
372
+ $ rules = [];
373
+ $ attributes = [];
374
+
375
+ foreach ($ this ->rules as $ layoutName => $ rule ) {
376
+ $ layout = $ this ->getLayouts ()->findByName ($ layoutName );
377
+
378
+ if (\is_null ($ layout )) {
379
+ continue ;
380
+ }
381
+
382
+ foreach ($ rule as $ fieldName => $ args ) {
383
+ $ field = $ layout ->fields ()->onlyFields ()->findByColumn ($ fieldName );
384
+ $ column = $ field ?->getLabel() ?? $ fieldName ;
385
+
386
+ $ rules ["$ layoutName.*. $ fieldName " ] = $ args ;
387
+ $ attributes ["$ layoutName.*. $ fieldName " ] = "{$ layout ->title ()}(:position) {$ column }" ;
388
+ }
389
+ }
390
+
391
+ Validator::validate ($ value ->toArray (), $ rules , attributes: $ attributes );
392
+ }
393
+
345
394
return $ this ->resolveCallback ($ data , function (Field $ field , mixed $ value ): void {
346
395
$ field ->beforeApply ($ value );
347
396
});
@@ -386,7 +435,7 @@ protected function resolveCallback(mixed $data, Closure $callback, bool $fill =
386
435
->each (function (Field $ field ) use ($ data , $ index , $ value , $ callback , $ fill ): void {
387
436
$ field ->appendRequestKeyPrefix (
388
437
"{$ this ->getColumn ()}. $ index " ,
389
- $ this ->getRequestKeyPrefix ()
438
+ $ this ->getRequestKeyPrefix (),
390
439
);
391
440
392
441
$ field ->when ($ fill , fn (Field $ f ): Field => $ f ->resolveFill ($ data ));
0 commit comments