Completed
Push — feature/pilot_information ( 13ff1e...cc067b )
by Laurent
01:46
created

Form::sanitize()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
nc 8
nop 2
dl 0
loc 28
rs 8.4444
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 */
5
6
namespace flightlog\form;
7
8
use function Safe\sprintf;
9
use ValidatorInterface;
10
11
/**
12
 * @author Laurent De Coninck <[email protected]>
13
 */
14
abstract class Form implements FormInterface
15
{
16
17
    /**
18
     * @var string
19
     */
20
    private $name;
21
22
    /**
23
     * @var string
24
     */
25
    private $method;
26
27
    /**
28
     * @var array
29
     */
30
    private $options;
31
32
    /**
33
     * @var \stdClass|null
34
     */
35
    private $object;
36
37
    /**
38
     * @var null|\ValidatorInterface
39
     */
40
    private $validator;
41
42
    /**
43
     * @var array|FormElementInterface[]
44
     */
45
    private $elements;
46
47
    /**
48
     * Form constructor.
49
     *
50
     * @param string $name
51
     * @param string $method
52
     * @param array  $options
53
     */
54
    public function __construct($name, $method = FormInterface::METHOD_GET, array $options = [])
55
    {
56
        $this->name = $name;
57
        $this->method = $method;
58
        $this->options = $options;
59
        $this->elements = [];
60
    }
61
62
    /**
63
     * @inheritDoc
64
     */
65
    public function getName()
66
    {
67
        return $this->name;
68
    }
69
70
    /**
71
     * @inheritDoc
72
     */
73
    public function getMethod()
74
    {
75
        return $this->method;
76
    }
77
78
    /**
79
     * @inheritDoc
80
     */
81
    public function getOptions()
82
    {
83
        return $this->options;
84
    }
85
86
    /**
87
     * @inheritDoc
88
     */
89
    public function add(FormElementInterface $element)
90
    {
91
        if(array_key_exists($element->getName(), $this->elements)){
92
            throw new \InvalidArgumentException('Element already exists');
93
        }
94
        $this->elements[$element->getName()] = $element;
95
96
        return $this;
97
    }
98
99
    /**
100
     * @inheritDoc
101
     */
102
    public function remove($fieldName)
103
    {
104
        unset($this->elements[$fieldName]);
105
        return $this;
106
    }
107
108
    /**
109
     * @inheritDoc
110
     */
111
    public function has($fieldName)
112
    {
113
        return isset($this->elements[$fieldName]);
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119
    public function validate()
120
    {
121
        if (!$this->validator) {
122
            return true;
123
        }
124
125
        if (null === $this->object) {
126
            throw new \InvalidArgumentException('Object not bound');
127
        }
128
129
        $validation = $this->validator->isValid($this->object, $_REQUEST);
130
131
        if (!$validation) {
132
            foreach ($this->elements as $fieldName => $field) {
133
                $field->setErrors($this->validator->getError($fieldName));
134
            }
135
        }
136
137
        return $validation;
138
    }
139
140
    /**
141
     * @return array|string[]
142
     */
143
    public function getErrorMessages()
144
    {
145
        if(!$this->validator){
146
            return [];
147
        }
148
149
        return $this->validator->getErrors();
150
    }
151
152
    /**
153
     * @param null|\ValidatorInterface $validator
154
     *
155
     * @return Form
156
     */
157
    protected function setValidator(ValidatorInterface $validator)
158
    {
159
        $this->validator = $validator;
160
        return $this;
161
    }
162
163
164
    /**
165
     * @inheritDoc
166
     */
167
    public function bind($object)
168
    {
169
        foreach ($this->elements as $element) {
170
            $name = $this->camelCase($element->getName());
171
            $methodName = 'get' . $name;
172
            if (!method_exists($object, $methodName)) {
173
                continue;
174
            }
175
176
            $element->setValue($object->{$methodName}());
177
        }
178
179
        $this->object = $object;
180
181
        return $this;
182
    }
183
184
    /**
185
     * @inheritDoc
186
     * @throws \ReflectionException
187
     */
188
    public function setData(array $data)
189
    {
190
        foreach ($data as $fieldName => $currentData) {
191
            if (!key_exists($fieldName, $this->elements) || $this->elements[$fieldName]->isDisabled()) {
192
                continue;
193
            }
194
195
            $this->elements[$fieldName]->setValue($currentData);
196
197
            $methodName = 'set' . $this->camelCase($fieldName);
198
            if (null === $this->object) {
199
                continue;
200
            }
201
202
            if (method_exists($this->object, $methodName)) {
203
204
                $targetMethod = new \ReflectionMethod($this->object, $methodName);
205
                if ($targetMethod->isPublic()) {
206
                    $this->object->{$methodName}($this->sanitize($targetMethod, $currentData));
207
                }
208
                continue;
209
            }
210
211
            if (property_exists($this->object, $fieldName)) {
212
                $this->object->{$fieldName} = $currentData;
213
                continue;
214
            }
215
        }
216
217
        return $this;
218
    }
219
220
    /**
221
     * @param \ReflectionMethod $targetMethod
222
     * @param mixed             $value
223
     *
224
     * @return bool|float|int|string
225
     */
226
    private function sanitize(\ReflectionMethod $targetMethod, $value = null)
227
    {
228
        /** @var \ReflectionNamedType $valueType */
229
        $valueType = $targetMethod->getParameters()[0]->getType();
230
231
        if ($valueType === null) {
232
            return $value;
233
        }
234
235
        switch ($valueType->getName()) {
236
            case 'array':
237
            case 'string':
238
            case 'object':
239
                return $value;
240
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
241
            case 'int':
242
                return intval($value);
243
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
244
            case 'float':
245
                return floatval($value);
246
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
247
            case 'bool':
248
                return boolval($value);
249
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
250
            default:
251
                throw new \InvalidArgumentException(sprintf('Unsupported type %s given.', $valueType->getName()));
252
        }
253
    }
254
255
    /**
256
     * @inheritDoc
257
     */
258
    public function getObject()
259
    {
260
        return $this->object;
261
    }
262
263
    /**
264
     * @inheritDoc
265
     */
266
    public function getElement($elementName)
267
    {
268
        if (!key_exists($elementName, $this->elements)) {
269
            throw new \InvalidArgumentException(sprintf('Element %s not found ', $elementName));
270
        }
271
272
        return $this->elements[$elementName];
273
    }
274
275
    /**
276
     * @param string $name
277
     *
278
     * @return string
279
     */
280
    private function camelCase($name)
281
    {
282
        $str = str_replace('_', '', ucwords($name, '-'));
283
        return lcfirst($str);
284
    }
285
286
}