Skip to content

Commit 75b2501

Browse files
authored
Merge pull request #37 from lara-zeus/fix/validation-and-casts
Add MatrixStateCast and enhance Matrix validation
2 parents 4f364c4 + 5a725cc commit 75b2501

File tree

3 files changed

+134
-9
lines changed

3 files changed

+134
-9
lines changed

resources/views/components/matrix-choice.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
<input
4040
{{ $attributes }}
4141
@if($isDisabled || ($isOptionDisabled($columnKey,'') && $isOptionDisabled($rowKey,''))) disabled @endif
42-
wire:key="{{ $id }}.{{ $rowKey }}"
42+
wire:key="{{ $id }}.{{ $rowKey }}.{{ $columnKey }}"
4343
wire:loading.attr="disabled"
4444
{{ $applyStateBindingModifiers('wire:model') }}="{{ $supStatPath }}"
4545
value="{{ $columnKey }}"

src/Components/Matrix.php

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
use Closure;
66
use Filament\Forms\Components\CheckboxList;
7+
use Illuminate\Validation\Rules\Enum;
8+
use Illuminate\Validation\Rules\In;
9+
use LaraZeus\MatrixChoice\MatrixStateCast;
710

811
class Matrix extends CheckboxList
912
{
13+
/** @phpstan-ignore-next-line */
1014
protected string $view = 'zeus-matrix-choice::components.matrix-choice';
1115

1216
protected array | Closure $columnData = [];
@@ -21,20 +25,34 @@ protected function setUp(): void
2125
{
2226
parent::setUp();
2327

24-
$this->rules([
25-
function () {
26-
return function (string $attribute, mixed $value, Closure $fail) {
28+
$this
29+
->stateCast(app(MatrixStateCast::class))
30+
->rules([
31+
fn () => function (string $attribute, mixed $value, Closure $fail) {
32+
$pillColor = $this->getPilColor();
2733
if ($this->rowSelectRequired && (blank($value) || count($this->getRowData()) !== count($value))) {
2834
$fail(__('required a selection for each row'));
2935
}
30-
foreach ($value as $val) {
31-
if ($this->rowSelectRequired && is_array($val) && blank(array_filter($val))) {
36+
37+
foreach ($value as $rowData => $columnData) {
38+
if ($this->rowSelectRequired && is_array($columnData) && blank(array_filter($columnData))) {
3239
$fail(__('required a selection for each row'));
3340
}
41+
42+
if (! in_array($rowData, array_keys($this->getRowData()))) {
43+
$fail(__('the selected :attribute is invalid'));
44+
}
45+
46+
if ($pillColor === 'checkbox' && count(array_diff_key($columnData, $this->getColumnData()))) {
47+
$fail(__('the selected :attribute is invalid'));
48+
}
49+
50+
if ($pillColor === 'radio' && ! in_array($columnData, array_keys($this->getColumnData()))) {
51+
$fail(__('the selected :attribute is invalid'));
52+
}
3453
}
35-
};
36-
},
37-
]);
54+
},
55+
]);
3856
}
3957

4058
public function columnData(array $data): static
@@ -86,4 +104,9 @@ public function rowSelectRequired(bool $rowSelectRequired = true): static
86104

87105
return $this;
88106
}
107+
108+
public function getInValidationRule(): In | Enum | null
109+
{
110+
return null;
111+
}
89112
}

src/MatrixStateCast.php

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
namespace LaraZeus\MatrixChoice;
4+
5+
use BackedEnum;
6+
use Filament\Schemas\Components\StateCasts\OptionsArrayStateCast;
7+
use Illuminate\Support\Arr;
8+
9+
class MatrixStateCast extends OptionsArrayStateCast
10+
{
11+
public function get(mixed $state): array
12+
{
13+
if (blank($state)) {
14+
return [];
15+
}
16+
17+
if (! is_array($state)) {
18+
$state = json_decode($state, associative: true);
19+
}
20+
$keys = array_keys(Arr::wrap($state));
21+
22+
return array_reduce(
23+
Arr::wrap($state),
24+
function (array $carry, $stateItem) use (&$keys): array {
25+
if (blank($stateItem)) {
26+
return $carry;
27+
}
28+
$key = array_shift($keys);
29+
30+
if ($stateItem instanceof BackedEnum) {
31+
$stateItem = $stateItem->value;
32+
}
33+
34+
if (
35+
is_int($stateItem)
36+
|| (
37+
is_string($stateItem)
38+
&& ctype_digit($stateItem)
39+
&& (($stateItem === '0') || (! str($stateItem)->startsWith('0')))
40+
)
41+
) {
42+
$max = (string) PHP_INT_MAX;
43+
44+
if (
45+
(strlen($stateItem) > strlen($max)) ||
46+
((strlen($stateItem) === strlen($max)) && (strcmp($stateItem, $max) > 0))
47+
) {
48+
$carry[] = strval($stateItem);
49+
} else {
50+
$carry[] = intval($stateItem);
51+
}
52+
} else {
53+
if (is_array($stateItem)) {
54+
$carry[$key] = $stateItem;
55+
} else {
56+
$carry[] = strval($stateItem);
57+
}
58+
}
59+
60+
return $carry;
61+
},
62+
initial: [],
63+
);
64+
}
65+
66+
public function set(mixed $state): array
67+
{
68+
if (blank($state)) {
69+
return [];
70+
}
71+
72+
if (! is_array($state)) {
73+
$state = json_decode($state, associative: true);
74+
}
75+
76+
$keys = array_keys(Arr::wrap($state));
77+
78+
return array_reduce(
79+
Arr::wrap($state),
80+
function (array $carry, $stateItem) use (&$keys): array {
81+
if (blank($stateItem)) {
82+
return $carry;
83+
}
84+
85+
$key = array_shift($keys);
86+
87+
if ($stateItem instanceof BackedEnum) {
88+
$stateItem = $stateItem->value;
89+
}
90+
91+
if (is_array($stateItem)) {
92+
$carry[$key] = $stateItem;
93+
} else {
94+
$carry[] = strval($stateItem);
95+
}
96+
97+
return $carry;
98+
},
99+
initial: [],
100+
);
101+
}
102+
}

0 commit comments

Comments
 (0)