Completed
Pull Request — wip/steps-v9 (#92)
by
unknown
04:42
created

DataAttributesAssetHandler::formatValue()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 8.8333
c 0
b 0
f 0
cc 7
nc 10
nop 1
1
<?php
2
/*
3
 * 2017 Romain CANON <[email protected]>
4
 *
5
 * This file is part of the TYPO3 FormZ project.
6
 * It is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License, either
8
 * version 3 of the License, or any later version.
9
 *
10
 * For the full copyright and license information, see:
11
 * http://www.gnu.org/licenses/gpl-3.0.html
12
 */
13
14
namespace Romm\Formz\AssetHandler\Html;
15
16
use DateTime;
17
use Romm\Formz\AssetHandler\AbstractAssetHandler;
18
use Romm\Formz\Error\FormResult;
19
use Romm\Formz\Error\FormzMessageInterface;
20
use Romm\Formz\Exceptions\InvalidArgumentTypeException;
21
use Romm\Formz\Service\MessageService;
22
use Romm\Formz\Service\StringService;
23
use Throwable;
24
use Traversable;
25
use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
26
use TYPO3\CMS\Extbase\Error\Result;
27
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
28
use TYPO3\CMS\Extbase\Reflection\Exception\PropertyNotAccessibleException;
29
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
30
31
/**
32
 * This asset handler generates several data attributes which will be added to
33
 * the form element in the Fluid template. Most of these data attributes are
34
 * directly bound to fields and their properties.
35
 *
36
 * Example of data attributes:
37
 *  - Fields values: when a field changes, its new value will be indicated in
38
 *    the form with the attribute: `fz-value-{field name}="value"`.
39
 *  - Fields validation: when a field is considered as valid (it passed all its
40
 *    validation rules), the form gets the attribute: `fz-valid-{field name}`.
41
 *  - Fields errors: when a field validation fails with an error, the form gets
42
 *    the attribute: `fz-error-{field name}-{name of the error}`.
43
 *  - Fields warnings and notices: same as errors.
44
 */
45
class DataAttributesAssetHandler extends AbstractAssetHandler
46
{
47
    /**
48
     * Handles the data attributes containing the values of the form fields.
49
     *
50
     * Example: `fz-value-color="blue"`
51
     *
52
     * @param FormResult $formResult
53
     * @return array
54
     */
55
    public function getFieldsValuesDataAttributes(FormResult $formResult)
56
    {
57
        $result = [];
58
        $formObject = $this->getFormObject();
59
        $formInstance = $formObject->getForm();
60
61
        foreach ($formObject->getDefinition()->getFields() as $field) {
62
            $fieldName = $field->getName();
63
64
            if (false === $formResult->fieldIsDeactivated($field)) {
65
                try {
66
                    $value = ObjectAccess::getProperty($formInstance, $fieldName);
67
                } catch (PropertyNotAccessibleException $exception) {
68
                    continue;
69
                }
70
71
                try {
72
                    $value = $this->formatValue($value);
73
                } catch (Throwable $e) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
74
                    throw InvalidArgumentTypeException::dataAttributeValueNotFormattable($formInstance, $fieldName, $value);
75
                }
76
77
                if (false === empty($value)) {
78
                    $result[self::getFieldDataValueKey($fieldName)] = $value;
79
                }
80
            }
81
        }
82
83
        return $result;
84
    }
85
86
    /**
87
     * @return array
88
     */
89
    public function getFieldSubmissionDoneDataAttribute()
90
    {
91
        return [self::getFieldSubmissionDone() => '1'];
92
    }
93
94
    /**
95
     * Handles the data attributes for the fields which are valid.
96
     *
97
     * Example: `fz-valid-email="1"`
98
     *
99
     * @return array
100
     */
101
    public function getFieldsValidDataAttributes()
102
    {
103
        $result = [];
104
        $formConfiguration = $this->getFormObject()->getDefinition();
105
        $formResult = $this->getFormObject()->getFormResult();
106
107
        foreach ($formConfiguration->getFields() as $field) {
108
            $fieldName = $field->getName();
109
110
            if (false === $formResult->fieldIsOutOfScope($field)
111
                && false === $formResult->fieldIsDeactivated($field)
112
                && false === $formResult->forProperty($fieldName)->hasErrors()
113
            ) {
114
                $result[self::getFieldDataValidKey($fieldName)] = '1';
115
            }
116
        }
117
118
        return $result;
119
    }
120
121
    /**
122
     * Handles the data attributes for the fields which got errors, warnings and
123
     * notices.
124
     *
125
     * Examples:
126
     * - `fz-error-email="1"`
127
     * - `fz-error-email-rule-default="1"`
128
     *
129
     * @return array
130
     */
131
    public function getFieldsMessagesDataAttributes()
132
    {
133
        $result = [];
134
        $formConfiguration = $this->getFormObject()->getDefinition();
135
        $formResult = $this->getFormObject()->getFormResult();
136
137
        foreach ($formResult->getSubResults() as $fieldName => $fieldResult) {
138
            $field = $formConfiguration->getField($fieldName);
139
140
            if (true === $formConfiguration->hasField($fieldName)
141
                && false === $formResult->fieldIsOutOfScope($field)
142
                && false === $formResult->fieldIsDeactivated($field)
143
            ) {
144
                $result += $this->getFieldErrorMessages($fieldName, $fieldResult);
145
                $result += $this->getFieldWarningMessages($fieldName, $fieldResult);
146
                $result += $this->getFieldNoticeMessages($fieldName, $fieldResult);
147
            }
148
        }
149
150
        return $result;
151
    }
152
153
    /**
154
     * @return array
155
     */
156
    public function getCurrentStepDataAttribute()
157
    {
158
        $stepIdentifier = $this->getFormObject()->getCurrentStepDefinition()->getStep()->getIdentifier();
159
160
        return ['fz-current-step' => $stepIdentifier];
161
    }
162
163
    /**
164
     * @param string $fieldName
165
     * @param Result $fieldResult
166
     * @return array
167
     */
168
    protected function getFieldErrorMessages($fieldName, Result $fieldResult)
169
    {
170
        return (true === $fieldResult->hasErrors())
171
            ? $this->addFieldMessageDataAttribute($fieldName, $fieldResult->getErrors(), 'error')
0 ignored issues
show
Documentation introduced by
$fieldResult->getErrors() is of type array<integer,object<TYP...S\Extbase\Error\Error>>, but the function expects a array<integer,object<Rom...FormzMessageInterface>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
172
            : [];
173
    }
174
175
    /**
176
     * @param string $fieldName
177
     * @param Result $fieldResult
178
     * @return array
179
     */
180
    protected function getFieldWarningMessages($fieldName, Result $fieldResult)
181
    {
182
        return (true === $fieldResult->hasWarnings())
183
            ? $this->addFieldMessageDataAttribute($fieldName, $fieldResult->getWarnings(), 'warning')
0 ignored issues
show
Documentation introduced by
$fieldResult->getWarnings() is of type array<integer,object<TYP...Extbase\Error\Warning>>, but the function expects a array<integer,object<Rom...FormzMessageInterface>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
184
            : [];
185
    }
186
187
    /**
188
     * @param string $fieldName
189
     * @param Result $fieldResult
190
     * @return array
191
     */
192
    protected function getFieldNoticeMessages($fieldName, Result $fieldResult)
193
    {
194
        return (true === $fieldResult->hasNotices())
195
            ? $this->addFieldMessageDataAttribute($fieldName, $fieldResult->getNotices(), 'notice')
0 ignored issues
show
Documentation introduced by
$fieldResult->getNotices() is of type array<integer,object<TYP...\Extbase\Error\Notice>>, but the function expects a array<integer,object<Rom...FormzMessageInterface>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
196
            : [];
197
    }
198
199
    /**
200
     * @param string                  $fieldName
201
     * @param FormzMessageInterface[] $messages
202
     * @param string                  $type
203
     * @return array
204
     */
205
    protected function addFieldMessageDataAttribute($fieldName, array $messages, $type)
206
    {
207
        $result = [self::getFieldDataMessageKey($fieldName, $type) => '1'];
208
209
        foreach ($messages as $message) {
210
            $validationName = MessageService::get()->getMessageValidationName($message);
211
            $messageKey = MessageService::get()->getMessageKey($message);
212
213
            $result[self::getFieldDataValidationMessageKey($fieldName, $type, $validationName, $messageKey)] = '1';
214
        }
215
216
        return $result;
217
    }
218
219
    /**
220
     * Checks the type of a given data attribute and formats it if needed.
221
     *
222
     * @param mixed $value
223
     * @return array
224
     */
225
    protected function formatValue($value)
226
    {
227
        if ($value instanceof ObjectStorage) {
228
            $value = $value->toArray();
229
        }
230
231
        if (is_array($value) || $value instanceof Traversable) {
232
            $value = implode(',', $value);
233
        } elseif ($value instanceof DateTime) {
234
            $format = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
235
            $value = $value->format($format);
236
        } elseif ($value instanceof DomainObjectInterface) {
237
            $value = $value->getUid();
238
        } elseif (false === is_string($value)) {
239
            $value = (string)$value;
240
        }
241
242
        return $value;
243
    }
244
245
    /**
246
     * Formats the data value attribute key for a given field name.
247
     *
248
     * @param string $fieldName Name of the field.
249
     * @return string
250
     */
251
    public static function getFieldDataValueKey($fieldName)
252
    {
253
        return 'fz-value-' . StringService::get()->sanitizeString($fieldName);
254
    }
255
256
    /**
257
     * Formats the data valid attribute key for a given field name.
258
     *
259
     * @param string $fieldName Name of the field.
260
     * @return string
261
     */
262
    public static function getFieldDataValidKey($fieldName)
263
    {
264
        return 'fz-valid-' . StringService::get()->sanitizeString($fieldName);
265
    }
266
267
    /**
268
     * Formats the data message attribute key for a given field name.
269
     *
270
     * @param string $fieldName Name of the field.
271
     * @param string $type      Type of the message: `error`, `warning` or `notice`.
272
     * @return string
273
     */
274
    public static function getFieldDataMessageKey($fieldName, $type = 'error')
275
    {
276
        return 'fz-' . $type . '-' . StringService::get()->sanitizeString($fieldName);
277
    }
278
279
    /**
280
     * @return string
281
     */
282
    public static function getFieldSubmissionDone()
283
    {
284
        return 'fz-submission-done';
285
    }
286
287
    /**
288
     * Formats the data message attribute key for a given failed validation for
289
     * the given field name.
290
     *
291
     * @param string $fieldName
292
     * @param string $type Type of the message: `error`, `warning` or `notice`.
293
     * @param string $validationName
294
     * @param string $messageKey
295
     * @return string
296
     */
297
    public static function getFieldDataValidationMessageKey($fieldName, $type, $validationName, $messageKey)
298
    {
299
        $stringService = StringService::get();
300
301
        return vsprintf(
302
            'fz-%s-%s-%s-%s',
303
            [
304
                $type,
305
                $stringService->sanitizeString($fieldName),
306
                $stringService->sanitizeString($validationName),
307
                $stringService->sanitizeString($messageKey)
308
            ]
309
        );
310
    }
311
}
312