Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.73% covered (success)
97.73%
43 / 44
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
RichText
97.73% covered (success)
97.73%
43 / 44
80.00% covered (warning)
80.00%
4 / 5
13
0.00% covered (danger)
0.00%
0 / 1
 control
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
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 properties
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 shape
96.67% covered (success)
96.67%
29 / 30
0.00% covered (danger)
0.00%
0 / 1
7
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Field;
6
7use Celema\Sire\Shape;
8use Cosray\Richtext\Envelope;
9use Cosray\Validation\RichtextDoc;
10use Cosray\Validation\Shapes;
11use Cosray\Value\RichText as RichTextValue;
12
13class RichText extends Text implements Capability\ToolsAware
14{
15    use Capability\IsToolsAware;
16
17    public function control(): Control
18    {
19        return Control::richtext();
20    }
21
22    public function value(): RichTextValue
23    {
24        return new RichTextValue($this->owner, $this, $this->valueContext);
25    }
26
27    public function structure(mixed $value = null): array
28    {
29        if (is_array($value) && array_key_exists('value', $value)) {
30            $value = $value['value'];
31        }
32
33        $result = $this->getTranslatableStructure('richtext', $value);
34        $result['format'] = Envelope::FORMAT;
35        $result['version'] = Envelope::VERSION;
36
37        return $result;
38    }
39
40    public function properties(): array
41    {
42        $richtext = $this->owner->config()->richtext;
43
44        return array_merge(parent::properties(), [
45            'richtextClasses' => (object) $richtext->classes,
46            'richtextStyles' => (object) $richtext->styles,
47            'tools' => $this->getTools(),
48        ]);
49    }
50
51    /**
52     * Saves are writer-strict: the panel submits the structured
53     * envelope (format, version, per-locale documents); legacy HTML
54     * strings are rejected. See docs/richtext-format.md.
55     */
56    public function shape(): Shape
57    {
58        $shape = Shapes::create();
59        $this->addType($shape);
60        $shape->add('format', 'string')->rules('required', 'in:' . Envelope::FORMAT);
61        // `in` compares strictly against string args, so pin the int
62        // version with a min/max pair instead.
63        $shape->add('version', 'int')->rules(
64            'required',
65            'min:' . Envelope::VERSION,
66            'max:' . Envelope::VERSION,
67        );
68
69        $richtext = $this->owner->config()->richtext;
70        $doc = new RichtextDoc($richtext->classes, $richtext->styles);
71
72        if ($this->isTranslatable()) {
73            $locales = $this->owner->locales();
74            $defaultLocale = $locales->getDefault()->id;
75            $i18nShape = Shapes::create();
76
77            foreach ($locales as $locale) {
78                $localeValidators = [];
79
80                if ($this->isRequired() && $locale->id === $defaultLocale) {
81                    $localeValidators[] = 'required';
82                }
83
84                $localeField = $i18nShape
85                    ->add($locale->id, $doc)
86                    ->label($this->valueLabel($locale))
87                    ->rules(...$localeValidators);
88
89                if (!in_array('required', $localeValidators, true)) {
90                    $localeField->optional()->nullable();
91                }
92            }
93
94            $value = $shape->add('value', $i18nShape)->rules(...$this->validators);
95        } else {
96            $value = $shape->add('value', $this->zxxShape($doc, $this->validators));
97        }
98
99        if (!$this->isRequired()) {
100            $value->optional()->nullable();
101        }
102
103        $this->addMeta($shape);
104
105        return $shape;
106    }
107}