Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.89% covered (warning)
88.89%
48 / 54
33.33% covered (danger)
33.33%
2 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Blocks
88.89% covered (warning)
88.89%
48 / 54
33.33% covered (danger)
33.33%
2 / 6
16.35
0.00% covered (danger)
0.00%
0 / 1
 __toString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 supportedTranslateModes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 value
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 structure
92.86% covered (success)
92.86%
13 / 14
0.00% covered (danger)
0.00%
0 / 1
3.00
 shape
90.32% covered (success)
90.32%
28 / 31
0.00% covered (danger)
0.00%
0 / 1
7.04
 emptyValueMap
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
3.04
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Field;
6
7use Celemas\Sire\Extra;
8use Celemas\Sire\Shape;
9use Cosray\Schema\TranslateMode;
10use Cosray\Validation\BlockValidator;
11use Cosray\Validation\Prepare;
12use Cosray\Validation\Shapes;
13use Cosray\Value\Blocks as BlocksValue;
14
15class Blocks extends Field implements Capability\Translatable, Capability\Blocks\Resizable
16{
17    use Capability\IsTranslatable;
18    use Capability\Blocks\IsResizable;
19
20    public function __toString(): string
21    {
22        return 'Blocks Field';
23    }
24
25    /** @return list<TranslateMode> */
26    protected function supportedTranslateModes(): array
27    {
28        return [TranslateMode::Asymmetric];
29    }
30
31    public function value(): BlocksValue
32    {
33        return new BlocksValue($this->owner, $this, $this->valueContext);
34    }
35
36    public function structure(mixed $value = null): array
37    {
38        $value ??= $this->default;
39
40        if (is_array($value)) {
41            $valueMap = $this->isAsymmetricallyTranslated()
42                ? $value
43                : [self::NEUTRAL_LOCALE => $value];
44        } else {
45            $valueMap = $this->emptyValueMap();
46        }
47
48        return [
49            'type' => $this::class,
50            'value' => $valueMap,
51            'meta' => [
52                'columns' => [self::NEUTRAL_LOCALE => $this->columns],
53                'minCellWidth' => [self::NEUTRAL_LOCALE => $this->minCellWidth],
54            ],
55        ];
56    }
57
58    public function shape(): Shape
59    {
60        $shape = Shapes::create();
61        $this->addType($shape);
62
63        $itemShape = new BlockValidator(list: true, title: $this->label, keepUnknown: true);
64
65        if ($this->isAsymmetricallyTranslated()) {
66            $locales = $this->owner->locales();
67            $defaultLocale = $locales->getDefault()->id;
68            $i18nShape = Shapes::create();
69
70            foreach ($locales as $locale) {
71                $innerValidators = [];
72
73                if ($this->isRequired() && $locale->id === $defaultLocale) {
74                    $innerValidators[] = 'required';
75                }
76
77                $localeField = $i18nShape
78                    ->add($locale->id, $itemShape)
79                    ->rules(...$innerValidators)
80                    ->prepare(Prepare::nullAsEmpty(...));
81
82                if (!in_array('required', $innerValidators, true)) {
83                    $localeField->optional()->nullable();
84                }
85            }
86
87            $value = $shape
88                ->add('value', $i18nShape)
89                ->rules(...$this->validators)
90                ->prepare(Prepare::nullAsEmpty(...));
91        } else {
92            $value = $shape
93                ->add('value', $this->zxxShape($itemShape, $this->validators))
94                ->prepare(Prepare::nullAsEmpty(...));
95        }
96
97        if (!$this->isRequired()) {
98            $value->optional()->nullable();
99        }
100
101        $meta = Shapes::create()->extra(Extra::Allow);
102        $meta->add('columns', $this->zxxShape('int'))->optional()->nullable();
103        $meta->add('minCellWidth', $this->zxxShape('int'))->optional()->nullable();
104        $shape->add('meta', $meta)->optional()->nullable();
105
106        return $shape;
107    }
108
109    private function emptyValueMap(): array
110    {
111        if (!$this->isAsymmetricallyTranslated()) {
112            return [self::NEUTRAL_LOCALE => []];
113        }
114
115        $result = [];
116
117        foreach ($this->owner->locales() as $locale) {
118            $result[$locale->id] = [];
119        }
120
121        return $result;
122    }
123}