Completed
Push — master ( 9c45fe...2e51e7 )
by
unknown
29:13 queued 13:18
created

Type::isSearchable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
declare(strict_types=1);
8
9
namespace eZ\Publish\SPI\FieldType\Generic;
10
11
use eZ\Publish\API\Repository\Values\ContentType\FieldDefinition;
12
use eZ\Publish\SPI\Exception\InvalidArgumentType;
13
use eZ\Publish\SPI\FieldType\FieldType;
14
use eZ\Publish\SPI\FieldType\Generic\ValidationError\ConstraintViolationAdapter;
15
use eZ\Publish\SPI\FieldType\ValidationError\NonConfigurableValidationError;
16
use eZ\Publish\SPI\FieldType\ValidationError\UnknownValidatorValidationError;
17
use eZ\Publish\SPI\FieldType\Value;
18
use eZ\Publish\SPI\FieldType\ValueSerializerInterface;
19
use eZ\Publish\SPI\Persistence\Content\FieldValue as PersistenceValue;
20
use Symfony\Component\Validator\Constraints as Assert;
21
use Symfony\Component\Validator\ConstraintViolationListInterface;
22
use Symfony\Component\Validator\Validator\ValidatorInterface;
23
24
abstract class Type extends FieldType
25
{
26
    /** @var \eZ\Publish\SPI\FieldType\ValueSerializerInterface */
27
    protected $serializer;
28
29
    /** @var \Symfony\Component\Validator\Validator\ValidatorInterface */
30
    protected $validator;
31
32
    public function __construct(ValueSerializerInterface $serializer, ValidatorInterface $validator)
33
    {
34
        $this->serializer = $serializer;
35
        $this->validator = $validator;
36
    }
37
38
    public function getName(Value $value, FieldDefinition $fieldDefinition, string $languageCode): string
39
    {
40
        return (string)$value;
41
    }
42
43
    public function getEmptyValue(): Value
44
    {
45
        $class = $this->getValueClass();
46
47
        return new $class();
48
    }
49
50
    public function fromHash($hash): Value
51
    {
52
        if ($hash) {
53
            return $this->serializer->denormalize($hash, $this->getValueClass());
54
        }
55
56
        return $this->getEmptyValue();
57
    }
58
59
    public function toHash(Value $value): ?array
60
    {
61
        if ($this->isEmptyValue($value)) {
62
            return null;
63
        }
64
65
        return $this->serializer->normalize($value);
66
    }
67
68
    /**
69
     * @see https://symfony.com/doc/current/validation/raw_values.html
70
     */
71
    protected function getFieldSettingsConstraints(): ?Assert\Collection
72
    {
73
        return null;
74
    }
75
76
    /**
77
     * @see https://symfony.com/doc/current/validation/raw_values.html
78
     */
79
    protected function getFieldValueConstraints(FieldDefinition $fieldDefinition): ?Assert\Collection
0 ignored issues
show
Unused Code introduced by
The parameter $fieldDefinition is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
80
    {
81
        return null;
82
    }
83
84
    protected function mapConstraintViolationList(ConstraintViolationListInterface $constraintViolationList): array
85
    {
86
        $errors = [];
87
88
        /** @var \Symfony\Component\Validator\ConstraintViolationInterface $constraintViolation */
89
        foreach ($constraintViolationList as $constraintViolation) {
90
            $errors[] = new ConstraintViolationAdapter($constraintViolation);
91
        }
92
93
        return $errors;
94
    }
95
96
    public function getSettingsSchema(): array
97
    {
98
        return [];
99
    }
100
101
    public function getValidatorConfigurationSchema(): array
102
    {
103
        return [];
104
    }
105
106
    public function validate(FieldDefinition $fieldDefinition, Value $value): array
107
    {
108
        if ($this->isEmptyValue($value)) {
109
            return [];
110
        }
111
112
        return $this->mapConstraintViolationList(
113
            $this->validator->validate($value, $this->getFieldValueConstraints($fieldDefinition))
114
        );
115
    }
116
117
    public function validateValidatorConfiguration($validatorConfiguration): array
118
    {
119
        $validationErrors = [];
120
121
        foreach ((array)$validatorConfiguration as $validatorIdentifier => $constraints) {
122
            $validationErrors[] = new UnknownValidatorValidationError(
123
                $validatorIdentifier,
124
                "[$validatorIdentifier]"
125
            );
126
        }
127
128
        return $validationErrors;
129
    }
130
131
    public function applyDefaultValidatorConfiguration(&$validatorConfiguration): void
132
    {
133
        if ($validatorConfiguration !== null && !is_array($validatorConfiguration)) {
134
            throw new InvalidArgumentType('$validatorConfiguration', 'array|null', $validatorConfiguration);
135
        }
136
137
        foreach ($this->getValidatorConfigurationSchema() as $validatorName => $configurationSchema) {
138
            // Set configuration of specific validator to empty array if it is not already provided
139
            if (!isset($validatorConfiguration[$validatorName])) {
140
                $validatorConfiguration[$validatorName] = [];
141
            }
142
143
            foreach ($configurationSchema as $settingName => $settingConfiguration) {
144
                // Check that a default entry exists in the configuration schema for the validator but that no value has been provided
145
                if (!isset($validatorConfiguration[$validatorName][$settingName]) && array_key_exists('default', $settingConfiguration)) {
146
                    $validatorConfiguration[$validatorName][$settingName] = $settingConfiguration['default'];
147
                }
148
            }
149
        }
150
    }
151
152
    public function validateFieldSettings($fieldSettings): array
153
    {
154
        if (empty($this->settingsSchema) && !empty($fieldSettings)) {
0 ignored issues
show
Bug introduced by
The property settingsSchema does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
155
            return [
156
                new NonConfigurableValidationError($this->getFieldTypeIdentifier(), 'fieldType'),
157
            ];
158
        }
159
160
        if (empty($fieldSettings)) {
161
            return [];
162
        }
163
164
        return $this->mapConstraintViolationList(
165
            $this->validator->validate($fieldSettings, $this->getFieldSettingsConstraints())
166
        );
167
    }
168
169
    public function applyDefaultSettings(&$fieldSettings): void
170
    {
171
        if ($fieldSettings !== null && !is_array($fieldSettings)) {
172
            throw new InvalidArgumentType('$fieldSettings', 'array|null', $fieldSettings);
173
        }
174
175
        foreach ($this->getSettingsSchema() as $settingName => $settingConfiguration) {
176
            // Checking that a default entry exists in the settingsSchema but that no value has been provided
177
            if (!array_key_exists($settingName, (array)$fieldSettings) && array_key_exists('default', $settingConfiguration)) {
178
                $fieldSettings[$settingName] = $settingConfiguration['default'];
179
            }
180
        }
181
    }
182
183
    /**
184
     * Returns information for FieldValue->$sortKey relevant to the field type.
185
     *
186
     * Return value is mixed. It should be something which is sensible for
187
     * sorting.
188
     *
189
     * It is up to the persistence implementation to handle those values.
190
     * Common string and integer values are safe.
191
     *
192
     * For the legacy storage it is up to the field converters to set this
193
     * value in either sort_key_string or sort_key_int.
194
     *
195
     * In case of multi value, values should be string and separated by "-" or ",".
196
     *
197
     * @param \eZ\Publish\Core\FieldType\Value $value
198
     *
199
     * @return mixed
200
     */
201
    protected function getSortInfo(Value $value)
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
202
    {
203
        return null;
204
    }
205
206
    public function toPersistenceValue(Value $value): PersistenceValue
207
    {
208
        return new PersistenceValue(
209
            [
210
                'data' => $this->toHash($value),
211
                'externalData' => null,
212
                'sortKey' => $this->getSortInfo($value),
213
            ]
214
        );
215
    }
216
217
    public function fromPersistenceValue(PersistenceValue $fieldValue)
218
    {
219
        return $this->fromHash($fieldValue->data);
220
    }
221
222
    public function isSearchable(): bool
223
    {
224
        return false;
225
    }
226
227
    public function isSingular(): bool
228
    {
229
        return false;
230
    }
231
232
    public function onlyEmptyInstance(): bool
233
    {
234
        return false;
235
    }
236
237
    public function isEmptyValue(Value $value): bool
238
    {
239
        return $value == $this->getEmptyValue();
240
    }
241
242
    final public function acceptValue($inputValue): Value
243
    {
244
        if ($inputValue === null) {
245
            return $this->getEmptyValue();
246
        }
247
248
        $value = $this->createValueFromInput($inputValue);
249
250
        $this->checkValueType($value);
251
252
        if ($this->isEmptyValue($value)) {
253
            return $this->getEmptyValue();
254
        }
255
256
        return $value;
257
    }
258
259
    /**
260
     * Inspects given $inputValue and potentially converts it into a dedicated value object.
261
     *
262
     * If given $inputValue could not be converted or is already an instance of dedicate value object,
263
     * the method should simply return it.
264
     *
265
     * This is an operation method for {@see acceptValue()}.
266
     *
267
     * Example implementation:
268
     * <code>
269
     *  protected function createValueFromInput( $inputValue )
270
     *  {
271
     *      if ( is_array( $inputValue ) )
272
     *      {
273
     *          $inputValue = \eZ\Publish\Core\FieldType\CookieJar\Value( $inputValue );
274
     *      }
275
     *
276
     *      return $inputValue;
277
     *  }
278
     * </code>
279
     *
280
     * @param mixed $inputValue
281
     *
282
     * @return mixed The potentially converted input value.
283
     */
284
    protected function createValueFromInput($inputValue)
285
    {
286
        if (is_string($inputValue)) {
287
            $inputValue = $this->serializer->denormalize(
288
                $this->serializer->decode($inputValue),
289
                $this->getValueClass()
290
            );
291
        }
292
293
        return $inputValue;
294
    }
295
296
    /**
297
     * Returns FQN of class representing Field Type Value.
298
     *
299
     * @return string
300
     */
301
    protected function getValueClass(): string
302
    {
303
        return substr_replace(static::class, 'Value', strrpos(static::class, '\\') + 1);
304
    }
305
306
    /**
307
     * Throws an exception if the given $value is not an instance of the supported value subtype.
308
     *
309
     * This is an operation method for {@see acceptValue()}.
310
     *
311
     * Default implementation expects the value class to reside in the same namespace as its
312
     * FieldType class and is named "Value".
313
     *
314
     * Example implementation:
315
     * <code>
316
     *  protected function checkValueType($value): void
317
     *  {
318
     *      if ( !$inputValue instanceof \eZ\Publish\Core\FieldType\CookieJar\Value ) )
319
     *      {
320
     *          throw new InvalidArgumentException( "Given value type is not supported." );
321
     *      }
322
     *  }
323
     * </code>
324
     *
325
     * @param mixed $value A value returned by {@see createValueFromInput()}.
326
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If the parameter is not an instance of the supported value subtype.
327
     */
328
    protected function checkValueType($value): void
329
    {
330
        $valueClass = $this->getValueClass();
331
        if (!$value instanceof $valueClass) {
332
            throw new InvalidArgumentType('$value', $valueClass, $value);
333
        }
334
    }
335
336
    public function fieldSettingsToHash($fieldSettings)
337
    {
338
        return $fieldSettings;
339
    }
340
341
    public function fieldSettingsFromHash($fieldSettingsHash)
342
    {
343
        return $fieldSettingsHash;
344
    }
345
346
    public function validatorConfigurationToHash($validatorConfiguration)
347
    {
348
        return $validatorConfiguration;
349
    }
350
351
    public function validatorConfigurationFromHash($validatorConfiguration)
352
    {
353
        return $validatorConfiguration;
354
    }
355
356
    public function getRelations(Value $value): array
357
    {
358
        return [];
359
    }
360
}
361