Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
28.57% covered (danger)
28.57%
24 / 84
42.86% covered (danger)
42.86%
3 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
BlockValidator
28.57% covered (danger)
28.57%
24 / 84
42.86% covered (danger)
42.86%
3 / 7
429.87
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
3
 validate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 reviewItems
30.43% covered (danger)
30.43%
7 / 23
0.00% covered (danger)
0.00%
0 / 1
69.89
 reviewMedia
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
30
 reviewYoutube
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
42
 hasZxxValue
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 addError
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Validation;
6
7use Celemas\Sire\Contract\Validator;
8use Celemas\Sire\Extra;
9use Celemas\Sire\Result;
10use Celemas\Sire\Review;
11use Celemas\Sire\Shape;
12use Override;
13
14final class BlockValidator implements Validator
15{
16    private Shape $shape;
17
18    public function __construct(bool $list = false, bool $keepUnknown = false, ?string $title = null)
19    {
20        unset($title);
21
22        $this->shape = $list ? Shape::list() : new Shape();
23        $this->shape->rules(Validators::registry());
24
25        if ($keepUnknown) {
26            $this->shape->extra(Extra::Allow);
27        }
28
29        $this->shape
30            ->add('type', 'string')
31            ->rules('required', 'in:text,richtext,h1,h2,h3,h4,h5,h6,image,youtube,images,video,iframe');
32        $this->shape->add('rowspan', 'int')->rules('required');
33        $this->shape->add('colspan', 'int')->rules('required');
34        $this->shape->add('width', 'int')->optional()->nullable();
35        $this->shape->add('colstart', 'int')->optional()->nullable();
36        $this->shape->add('meta', Shapes::create()->extra(Extra::Allow))->optional()->nullable();
37        $this->shape->review($this->reviewItems(...));
38    }
39
40    #[Override]
41    public function validate(array $data): Result
42    {
43        return $this->shape->validate($data);
44    }
45
46    private function reviewItems(Review $review): void
47    {
48        foreach ($review->values() as $index => $value) {
49            $listIndex = $review->isList() && is_int($index) ? $index : null;
50            $type = is_array($value) ? $value['type'] ?? null : null;
51
52            if ($type === 'image' || $type === 'images' || $type === 'video') {
53                $this->reviewMedia($review, $listIndex, $value);
54            } elseif ($type === 'youtube') {
55                $this->reviewYoutube($review, $listIndex, $value);
56            } elseif (in_array($type, ['richtext', 'text', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], true)) {
57                if (!$this->hasZxxValue($value)) {
58                    $this->addError(
59                        $review,
60                        $listIndex,
61                        'value',
62                        _('Bitte Textfeld ausfüllen oder Block löschen.'),
63                    );
64                }
65            } elseif ($type === 'iframe') {
66                if (!$this->hasZxxValue($value)) {
67                    $this->addError(
68                        $review,
69                        $listIndex,
70                        'value',
71                        _('Bitte Iframe-Feld ausfüllen oder Block löschen.'),
72                    );
73                }
74            }
75        }
76    }
77
78    private function reviewMedia(Review $review, ?int $listIndex, mixed $value): void
79    {
80        $files = is_array($value) ? $value['value'] ?? [] : [];
81
82        if (is_array($files) && count($files) > 0) {
83            $fileShape = Shapes::list();
84            $fileShape->add('file', 'string')->rules('required');
85            $fileShape->add('meta', Shapes::create()->extra(Extra::Allow))->optional()->nullable();
86
87            if ($fileShape->validate($files)->valid()) {
88                return;
89            }
90
91            $this->addError(
92                $review,
93                $listIndex,
94                'image',
95                _('Attribute `file` nicht gefüllt.'),
96            );
97
98            return;
99        }
100
101        $this->addError(
102            $review,
103            $listIndex,
104            'image',
105            _('Bild eingefügt aber nicht hochgeladen.'),
106        );
107    }
108
109    private function reviewYoutube(Review $review, ?int $listIndex, mixed $value): void
110    {
111        if (!$this->hasZxxValue($value)) {
112            $this->addError(
113                $review,
114                $listIndex,
115                'value',
116                _('Bitte gültige Youtube-ID eingeben.'),
117            );
118        }
119
120        $aspectRatioX = $value['meta']['aspectRatioX']['zxx'] ?? null;
121
122        if (!$aspectRatioX || !is_numeric($aspectRatioX)) {
123            $this->addError(
124                $review,
125                $listIndex,
126                'aspectRatioX',
127                _('Bitte gültige Zahl eingeben.'),
128            );
129        }
130
131        $aspectRatioY = $value['meta']['aspectRatioY']['zxx'] ?? null;
132
133        if (!$aspectRatioY || !is_numeric($aspectRatioY)) {
134            $this->addError(
135                $review,
136                $listIndex,
137                'aspectRatioY',
138                _('Bitte gültige Zahl eingeben.'),
139            );
140        }
141    }
142
143    private function hasZxxValue(mixed $value): bool
144    {
145        $value = is_array($value) ? $value['value']['zxx'] ?? null : null;
146
147        return $value !== null && $value !== '';
148    }
149
150    private function addError(
151        Review $review,
152        ?int $listIndex,
153        string $field,
154        string $message,
155    ): void {
156        $review->addError($listIndex === null ? $field : [$listIndex, $field], $message);
157    }
158}