1<?php
2
3
4namespace ComboStrap\Meta\Api;
5
6
7use ComboStrap\DataType;
8use ComboStrap\ExceptionBadArgument;
9use ComboStrap\ExceptionCompile;
10use ComboStrap\ExceptionNotFound;
11use ComboStrap\LogUtility;
12
13/**
14 * @package ComboStrap
15 * A list of value metadata
16 *   * Multiple select if the possible values are set
17 *   * Text with a {@link  MetadataMultiple::getStringSeparator() separator}
18 * Ie:
19 *   * keyword1, keyword2
20 *   * usage1, usage2, ...
21 *
22 * By default, the data type is text, if number, the implementation should overwrite the {@link MetadataMultiple::getDataType()}
23 */
24abstract class MetadataMultiple extends Metadata
25{
26
27    /**
28     * @var array|null
29     */
30    protected ?array $array = null;
31
32
33    /**
34     * @param null|array $value
35     * @return Metadata
36     * @throws ExceptionCompile
37     */
38    public function setValue($value): Metadata
39    {
40        if ($value === null) {
41            $this->array = $value;
42            return $this;
43        }
44        if (!is_array($value)) {
45            throw new ExceptionCompile("The value is not an array. Value: " . var_export($value, true));
46        }
47        $this->array = $value;
48        return $this;
49    }
50
51    static     public function getDataType(): string
52    {
53        return DataType::TEXT_TYPE_VALUE;
54    }
55
56    public function getValue(): array
57    {
58        $this->buildCheck();
59        if ($this->array === null) {
60            throw new ExceptionNotFound("No multiple values was found");
61        }
62        return $this->array;
63    }
64
65    public function getDefaultValue()
66    {
67        throw new ExceptionNotFound("No default multiples value");
68    }
69
70    /**
71     * @throws ExceptionNotFound
72     */
73    public function getValueOrDefaults(): array
74    {
75        try {
76            return $this->getValue();
77        } catch (ExceptionNotFound $e) {
78            return $this->getDefaultValue();
79        }
80    }
81
82
83    public function valueIsNotNull(): bool
84    {
85        return $this->array !== null;
86    }
87
88    public function toStoreValue()
89    {
90        $this->buildCheck();
91        if ($this->array === null) {
92            return null;
93        }
94        return implode($this->getStringSeparator(), $this->array);
95    }
96
97    public function toStoreDefaultValue()
98    {
99        try {
100            $defaultValue = $this->getDefaultValue();
101        } catch (ExceptionNotFound $e) {
102            return null;
103        }
104        return implode($this->getStringSeparator(), $defaultValue);
105    }
106
107
108    /**
109     * @return string - the separator used when we receive or store/send an element
110     */
111    function getStringSeparator(): string
112    {
113        return ",";
114    }
115
116    /**
117     * @throws ExceptionBadArgument
118     */
119    public function setFromStoreValue($value): Metadata
120    {
121        $values = $this->toArrayOrNull($value);
122        if ($values === null) {
123            return $this;
124        }
125        $possibleValues = $this->getPossibleValues();
126        if ($possibleValues !== null) {
127            foreach ($values as $value) {
128                if (!in_array($value, $possibleValues)) {
129                    throw new ExceptionBadArgument("The value ($value) for ($this) is not a possible value (" . implode(",", $possibleValues) . ")", $this->getCanonical());
130                }
131            }
132        }
133        $this->array = $values;
134        return $this;
135    }
136
137    /**
138     * @throws ExceptionBadArgument
139     */
140    protected function toArrayOrNull($value): ?array
141    {
142        /**
143         * Empty String is the default for HTML form
144         */
145        if ($value === null || $value === "") {
146            return null;
147        }
148
149        /**
150         * Array
151         */
152        if (is_array($value)) {
153            return $value;
154        }
155
156        /**
157         * String
158         */
159        if (!is_string($value)) {
160            throw new ExceptionBadArgument("The value for $this is not an array, nor a string (value: $value)", get_class($this));
161        }
162        $stringSeparator = $this->getStringSeparator();
163        return explode($stringSeparator, $value);
164
165    }
166
167
168    public function setFromStoreValueWithoutException($value): Metadata
169    {
170        try {
171            $this->array = $this->toArrayOrNull($value);
172        } catch (ExceptionCompile $e) {
173            LogUtility::msg($e->getMessage(), $e->getCanonical());
174        }
175        return $this;
176
177    }
178}
179