ClassViewHelper::getFormResultClass()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 3
nc 2
nop 0
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\ViewHelpers;
15
16
use Romm\Formz\Configuration\View\Classes\ViewClass;
17
use Romm\Formz\Exceptions\EntryNotFoundException;
18
use Romm\Formz\Exceptions\InvalidEntryException;
19
use Romm\Formz\Exceptions\UnregisteredConfigurationException;
20
use Romm\Formz\Service\ViewHelper\Field\FieldViewHelperService;
21
use Romm\Formz\Service\ViewHelper\Form\FormViewHelperService;
22
use TYPO3\CMS\Core\Utility\GeneralUtility;
23
use TYPO3\CMS\Extbase\Error\Result;
24
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
25
26
/**
27
 * This view helper is used to manage the properties set in TypoScript at the
28
 * path `config.tx_formz.view.classes`.
29
 *
30
 * Two groups of classes are handled: `errors` and `valid`. The classes will be
31
 * "activated" only when the field has been validated, and the result matches
32
 * the class group.
33
 *
34
 * In the option `name`, you must indicate which class from which group you want
35
 * to manage, for example `errors.has-error` for the class `has-error` from the
36
 * group `errors`.
37
 *
38
 * If the field currently being rendered with Fluid is not using the view helper
39
 * `FieldViewHelper` (all its skeleton is written manually), you may have to use
40
 * the option `field`, which should then contain the name of the field.
41
 *
42
 * Please be aware that this view helper is useful only when used at the same
43
 * level or under the HTML element containing the field selector (usually the
44
 * one with the data attribute `fz-field-container`). You may encounter
45
 * strange behaviours if you do not respect this requirement.
46
 */
47
class ClassViewHelper extends AbstractViewHelper
48
{
49
    const CLASS_ERRORS = 'errors';
50
    const CLASS_VALID = 'valid';
51
52
    /**
53
     * @var array
54
     */
55
    protected static $acceptedClassesNameSpace = [self::CLASS_ERRORS, self::CLASS_VALID];
56
57
    /**
58
     * @var FormViewHelperService
59
     */
60
    protected $formService;
61
62
    /**
63
     * @var FieldViewHelperService
64
     */
65
    protected $fieldService;
66
67
    /**
68
     * @var string
69
     */
70
    protected $fieldName;
71
72
    /**
73
     * @var string
74
     */
75
    protected $classValue;
76
77
    /**
78
     * @var string
79
     */
80
    protected $classNameSpace;
81
82
    /**
83
     * @var string
84
     */
85
    protected $className;
86
87
    /**
88
     * @inheritdoc
89
     */
90
    public function initializeArguments()
91
    {
92
        parent::initializeArguments();
93
94
        $this->registerArgument('name', 'string', 'Name of the class which will be managed.', true);
95
        $this->registerArgument('field', 'string', 'Name of the field which will be managed. By default, it is the field from the current `FieldViewHelper`.');
96
    }
97
98
    /**
99
     * @inheritdoc
100
     */
101
    public function render()
102
    {
103
        $this->initializeClassNames();
104
        $this->initializeClassValue();
105
        $this->initializeFieldName();
106
107
        $result = vsprintf(
108
            'fz-%s-%s',
109
            [
110
                $this->classNameSpace,
111
                str_replace(' ', '-', $this->classValue)
112
            ]
113
        );
114
115
        $result .= $this->getFormResultClass();
116
117
        return $result;
118
    }
119
120
    /**
121
     * Will initialize the namespace and name of the class which is given as
122
     * argument to this ViewHelper.
123
     *
124
     * @throws InvalidEntryException
125
     */
126
    protected function initializeClassNames()
127
    {
128
        list($this->classNameSpace, $this->className) = GeneralUtility::trimExplode('.', $this->arguments['name']);
129
130
        if (false === in_array($this->classNameSpace, self::$acceptedClassesNameSpace)) {
131
            throw InvalidEntryException::invalidCssClassNamespace($this->arguments['name'], self::$acceptedClassesNameSpace);
132
        }
133
    }
134
135
    /**
136
     * Fetches the name of the field which should refer to this class. It can
137
     * either be a given value, or be empty if the ViewHelper is used inside a
138
     * `FieldViewHelper`.
139
     *
140
     * @throws EntryNotFoundException
141
     */
142
    protected function initializeFieldName()
143
    {
144
        $this->fieldName = $this->arguments['field'];
145
146
        if (empty($this->fieldName)
147
            && $this->fieldService->fieldContextExists()
148
        ) {
149
            $this->fieldName = $this->fieldService
150
                ->getCurrentField()
151
                ->getName();
152
        }
153
154
        if (null === $this->fieldName) {
155
            throw EntryNotFoundException::classViewHelperFieldNotFound($this->arguments['name']);
156
        }
157
    }
158
159
    /**
160
     * Fetches the corresponding value of this class, which was defined in
161
     * TypoScript.
162
     *
163
     * @throws UnregisteredConfigurationException
164
     */
165
    protected function initializeClassValue()
166
    {
167
        $classesConfiguration = $this->formService
168
            ->getFormObject()
169
            ->getConfiguration()
170
            ->getRootConfiguration()
171
            ->getView()
172
            ->getClasses();
173
174
        /** @var ViewClass $class */
175
        $class = ObjectAccess::getProperty($classesConfiguration, $this->classNameSpace);
176
177
        if (false === $class->hasItem($this->className)) {
178
            throw UnregisteredConfigurationException::cssClassNameNotFound($this->arguments['name'], $this->classNameSpace, $this->className);
179
        }
180
181
        $this->classValue = $class->getItem($this->className);
0 ignored issues
show
Documentation Bug introduced by
It seems like $class->getItem($this->className) of type array is incompatible with the declared type string of property $classValue.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
182
    }
183
184
    /**
185
     * Checks if the form was submitted, then parses its result to handle
186
     * classes depending on TypoScript configuration.
187
     *
188
     * @return string
189
     */
190
    protected function getFormResultClass()
191
    {
192
        $result = '';
193
        $formObject = $this->formService->getFormObject();
194
195
        if ($formObject->formWasSubmitted()
196
            && $formObject->hasFormResult()
197
        ) {
198
            $fieldResult = $formObject->getFormResult()->forProperty($this->fieldName);
199
            $result = $this->getPropertyResultClass($fieldResult);
200
        }
201
202
        return $result;
203
    }
204
205
    /**
206
     * @param Result $propertyResult
207
     * @return string
208
     */
209
    protected function getPropertyResultClass(Result $propertyResult)
210
    {
211
        $result = '';
212
213
        switch ($this->classNameSpace) {
214
            case self::CLASS_ERRORS:
215
                $result = $this->getPropertyErrorClass($propertyResult);
216
                break;
217
            case self::CLASS_VALID:
218
                $result = $this->getPropertyValidClass($propertyResult);
219
                break;
220
        }
221
222
        return $result;
223
    }
224
225
    /**
226
     * @param Result $propertyResult
227
     * @return string
228
     */
229
    protected function getPropertyErrorClass(Result $propertyResult)
230
    {
231
        return (true === $propertyResult->hasErrors())
232
            ? ' ' . $this->classValue
233
            : '';
234
    }
235
236
    /**
237
     * @param Result $propertyResult
238
     * @return string
239
     */
240
    protected function getPropertyValidClass(Result $propertyResult)
241
    {
242
        $result = '';
243
        $formObject = $this->formService->getFormObject();
244
        $field = $formObject->getConfiguration()->getField($this->fieldName);
245
246
        if ($formObject->hasForm()
247
            && false === $propertyResult->hasErrors()
248
            && false === $formObject->getFormResult()->fieldIsDeactivated($field)
249
        ) {
250
            $fieldValue = ObjectAccess::getProperty($formObject->getForm(), $this->fieldName);
251
252
            if (false === empty($fieldValue)) {
253
                $result .= ' ' . $this->classValue;
254
            }
255
        }
256
257
        return $result;
258
    }
259
260
    /**
261
     * @param FormViewHelperService $service
262
     */
263
    public function injectFormService(FormViewHelperService $service)
264
    {
265
        $this->formService = $service;
266
    }
267
268
    /**
269
     * @param FieldViewHelperService $service
270
     */
271
    public function injectFieldService(FieldViewHelperService $service)
272
    {
273
        $this->fieldService = $service;
274
    }
275
}
276