Form   D
last analyzed

Complexity

Total Complexity 160

Size/Duplication

Total Lines 1606
Duplicated Lines 1.43 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 23
loc 1606
rs 4.4102
c 0
b 0
f 0
wmc 160
lcom 1
cbo 4

75 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 21 6
A setMethod() 0 12 3
A getMethod() 0 9 2
A setAction() 0 6 1
A getAction() 0 4 1
A isAutoComplete() 0 4 2
A getTarget() 0 4 1
B setTarget() 0 12 5
A isNoValidation() 0 4 2
A setNoValidation() 0 6 1
A setAttribute() 0 4 1
A copyObjectProperties() 0 15 3
A setID() 0 6 1
A setName() 0 6 1
A setAcceptCharset() 0 6 1
A setClass() 0 6 1
A getClass() 0 4 1
A setDescription() 0 6 1
A getDescription() 0 4 1
A setHeading() 0 6 1
A getHeading() 0 4 1
A setEncoding() 0 6 1
A getFormelements() 0 4 1
A formHasErrors() 0 4 1
B render() 0 35 3
A fileExists() 0 17 4
A getElementByPosition() 0 8 3
A addDecorators() 0 7 2
A getDecorators() 0 4 1
A useDefaultFormDecorators() 0 4 1
A getDecorator() 0 8 2
A setDecoratorAttributesArray() 0 4 1
A getDecoratorAttributesArray() 0 4 1
A setFormelementDecorator() 0 4 1
A removeFormelementDecorator() 0 5 1
A hasErrors() 0 8 2
A addErrorMessage() 0 4 1
A getErrorMessages() 0 4 1
A __get() 0 4 1
A setAutoComplete() 0 6 1
A getAttribute() 0 8 2
B setAttributes() 0 23 4
A getID() 0 4 1
A getName() 0 4 1
A getAcceptCharset() 0 8 2
A setLegend() 0 6 1
A getLegend() 0 4 1
A getEncoding() 0 10 2
A setFormelements() 0 4 1
A registerDefaultFormelementDecorators() 0 6 1
B renderAllFormelements() 0 55 6
A __toString() 0 4 1
B addElement() 0 57 8
B regenerateFormelementIdentifiers() 0 32 2
A arrayInsert() 0 4 1
A delElementByName() 0 13 3
A getElementByName() 0 10 3
A getElement() 0 21 3
A formelementFactory() 0 20 2
A processForm() 0 18 2
A bind() 0 3 1
C setValues() 0 32 7
A getValues() 0 14 2
A setDecorator() 0 4 1
C addDecorator() 0 41 7
A registerDefaultFormDecorators() 0 6 1
A removeDecorator() 0 15 4
A decoratorFactory() 0 17 3
C applyDecoratorAttributes() 23 37 8
A addFormelementDecorator() 0 14 3
A addValidator() 0 7 3
A validateForm() 0 12 4
A addErrorMessages() 0 4 1
A resetErrorMessages() 0 4 1
A __set() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Form often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Form, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Koch Framework
5
 * Jens-André Koch © 2005 - onwards.
6
 *
7
 * This file is part of "Koch Framework".
8
 *
9
 * License: GNU/GPL v2 or any later version, see LICENSE file.
10
 *
11
 * This program is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 2 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
namespace Koch\Form;
26
27
/**
28
 * Koch Framework - Class for creation and handling of HTML Forms.
29
 *
30
 * The Formular Object provides methods to deal with the following problem:
31
 *
32
 * Normally you would define your form on html side. When the form gets submitted
33
 * you would perform a server-side validation on the incomming formdata against
34
 * certain validation rules. If your system is one of the better ones, you would
35
 * add these validations also on client-side as an useability enhancement.
36
 *
37
 * Problem:
38
 * This means that you have to implement the validation rules and validation methods two times.
39
 * One time via javascript on client-side, one time via php on server-side.
40
 *
41
 * Koch Framework's formhandling abstracts the form generation and solves the problem described above.
42
 *
43
 * The formular handling process can be described as the following:
44
 *
45
 * 1) Formcreation
46
 *    The formular is defined/described only one-time in xml (Data-Dictionary).
47
 *
48
 *    The form-definition/description contains:
49
 *    a) Elements
50
 *    b) Attributes
51
 *    c) Validation rules
52
 *
53
 * 2) Transformation / Generation
54
 *    The formular definition is then transformed into a valid html/xhtml/xml document segment
55
 *    with client-side validation rules and methods applied.
56
 *
57
 *    The form contains:
58
 *    a) Formular
59
 *    b) Client-side formular validation rules
60
 *    c) Client-side formular validation methods
61
 *
62
 * 3) The generated form is ready for getting embedded into the template/document providing the formular.
63
 *    The form element represents a collection of form-associated elements, some of which can represent
64
 *    editable values that can be submitted to a server for processing.
65
 *
66
 * Form Workflow
67
 *
68
 *    a) Embed formular
69
 *       -> Perform client-side validation while data is collected from user
70
 *       -> If validation is ok:
71
 *    b) Submit
72
 *       -> Perform server-side validation on incomming data
73
 *       -> If validation is ok:
74
 *          -> Save Data !
75
 *       -> Else
76
 *    c) Repopulate formfields on submission error
77
 *       -> goto a)
78
 *
79
 * @link http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html
80
 */
81
class Form implements FormInterface
82
{
83
    /**
84
     * Contains all formelements / formobjects registered for this form.
85
     *
86
     * @var array
87
     */
88
    protected $formelements = [];
89
90
    /**
91
     * Form attributes:.
92
     *
93
     * accept-charset, action, autocomplete, enctype, method, name, novalidate, target
94
     *
95
     * @link http://dev.w3.org/html5/html-author/#forms
96
     */
97
98
    /**
99
     * Contains accept-charset of the form.
100
     *
101
     * @var string
102
     */
103
    protected $acceptcharset;
104
105
    /**
106
     * Contains action of the form.
107
     *
108
     * @var string
109
     */
110
    protected $action;
111
112
    /**
113
     * Contains autocomplete state of the form.
114
     *
115
     * @var bool
116
     */
117
    protected $autocomplete;
118
119
    /**
120
     * Contains encoding of the form.
121
     *
122
     * @var string
123
     */
124
    protected $encoding;
125
126
    /**
127
     * Contains action of the form.
128
     *
129
     * @var string
130
     */
131
    protected $method;
132
133
    /**
134
     * Contains action of the form.
135
     *
136
     * @var string
137
     */
138
    protected $name;
139
    protected $noValidation;
140
    protected $target;
141
142
    /**
143
     * Contains id of the form.
144
     *
145
     * @var string
146
     */
147
    protected $id;
148
149
    /**
150
     * Contains class of the form.
151
     *
152
     * @var string
153
     */
154
    protected $class;
155
156
    /**
157
     * Contains description of the form.
158
     *
159
     * @var string
160
     */
161
    protected $description;
162
163
    /**
164
     * Contains heading of the form.
165
     *
166
     * @var string
167
     */
168
    protected $heading;
169
170
    /**
171
     * Flag variable to indicate, if form has an error.
172
     *
173
     * @var bool
174
     */
175
    protected $error = false;
176
177
    /**
178
     * Form Decorators Array, contains one or several formdecorator objects.
179
     *
180
     * @var array
181
     */
182
    private $formdecorators = [];
183
184
    /**
185
     * Toogle variable to control registering of default Formdecorators during rendering.
186
     *
187
     * @var bool
188
     */
189
    private $useDefaultFormDecorators = true;
190
191
    /**
192
     * Form Groups Array, contains one or several formgroup objects.
193
     *
194
     * @var array
195
     */
196
    protected $formgroups = [];
197
198
    /**
199
     * Errormessages Stack.
200
     *
201
     * @var array
202
     */
203
    protected $errorMessages = [];
204
205
    /**
206
     * Construct.
207
     *
208
     * @example
209
     * $form = Koch_Form('news_form', 'post', 'index.php?mod=news&sub=admin&action=update&type=create');
210
     *
211
     * @param mixed|array|string $name_or_attributes Set the name of the form OR and array with attributes.
212
     * @param string             $method             Set the method of the form. Valid are get/post.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $method not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
213
     * @param string             $action             Set the action of the form.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $action not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
214
     */
215
    public function __construct($name_or_attributes = null, $method = null, $action = null)
0 ignored issues
show
Coding Style introduced by
$name_or_attributes does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
216
    {
217
        if (null === $name_or_attributes) {
0 ignored issues
show
Coding Style introduced by
$name_or_attributes does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
218
            throw new \InvalidArgumentException(
219
                'Missing argument 1. Expected a string (Name of Form) or an array (Form Description Array).'
220
            );
221
        }
222
223
        if (is_string($name_or_attributes)) {
0 ignored issues
show
Coding Style introduced by
$name_or_attributes does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
224
            // case 1: $name is a string, the name of the form
225
            $this->setName($name_or_attributes);
0 ignored issues
show
Coding Style introduced by
$name_or_attributes does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
226
        } elseif (is_array($name_or_attributes)) {
0 ignored issues
show
Coding Style introduced by
$name_or_attributes does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
227
            // case 2: $name is an array with several attribute => value relationships
228
            $this->setAttributes($name_or_attributes);
0 ignored issues
show
Coding Style introduced by
$name_or_attributes does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
229
        }
230
231
        if ($method !== null and $action !== null) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
232
            $this->setMethod($method);
233
            $this->setAction($action);
234
        }
235
    }
236
237
    /**
238
     * Sets the method (POST, GET) to the form.
239
     *
240
     * @param string $method POST or GET
241
     *
242
     * @return Form
243
     */
244
    public function setMethod($method)
245
    {
246
        if ($method === 'POST' or $method === 'GET') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
247
            $this->method = $method;
248
        } else {
249
            throw new \InvalidArgumentException(
250
                _('The method parameter is "' . $method . '", but has to be GET or POST.')
251
            );
252
        }
253
254
        return $this;
255
    }
256
257
    /**
258
     * Returns method (GET or POST) of this form.
259
     *
260
     * @return string Name of the method of this form. Defaults to POST.
261
     */
262
    public function getMethod()
263
    {
264
        // defaults to post
265
        if ($this->method === null) {
266
            $this->method = 'POST';
267
        }
268
269
        return $this->method;
270
    }
271
272
    /**
273
     * Set action of this form (which is the target url).
274
     *
275
     * @param string $action string Target URL of the action of this form.
276
     *
277
     * @return Form
278
     */
279
    public function setAction($action)
280
    {
281
        $this->action = \Koch\Router\Router::buildURL($action);
282
283
        return $this;
284
    }
285
286
    /**
287
     * Returns action of this form (target url).
288
     *
289
     * @return string Target Url as the action of this form.
290
     */
291
    public function getAction()
292
    {
293
        return $this->action;
294
    }
295
296
    /**
297
     * Returns the auto-completion state of this form.
298
     *
299
     * @return string Returns the auto-completion state of this form.
300
     */
301
    public function isAutoComplete()
302
    {
303
        return ($this->autocomplete === true) ? 'on' : 'off';
304
    }
305
306
    /**
307
     * Set autocomplete of this form.
308
     * If "on" browsers can store the form's input values, to auto-fill the form if the user returns to the page.
309
     *
310
     * @param bool $bool boolean state to set for autocomplete.
311
     *
312
     * @return Form
313
     */
314
    public function setAutoComplete($bool)
315
    {
316
        $this->autocomplete = (bool) $bool;
317
318
        return $this;
319
    }
320
321
    /**
322
     * Gets the target (_blank, _self, _parent, _top).
323
     *
324
     * @return string string
325
     */
326
    public function getTarget()
327
    {
328
        return $this->target;
329
    }
330
331
    /**
332
     * Set the target of the form.
333
     *
334
     * _blank    Open in a new window
335
     * _self      Open in the same frame as it was clicked
336
     * _parent  Open in the parent frameset
337
     * _top
338
     *
339
     * @param string $target _blank, _self, _parent, _top
340
     *
341
     * @return Form
342
     */
343
    public function setTarget($target)
344
    {
345
        if ($target === '_blank' or $target === '_self' or $target === '_parent' or $target === '_top') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
346
            $this->target = $target;
347
        } else {
348
            throw new \InvalidArgumentException(
349
                'The target parameter is "' . $target . '", but has to be one of _blank, _self, _parent, _top.'
350
            );
351
        }
352
353
        return $this;
354
    }
355
356
    /**
357
     * Returns novalidation state of this form.
358
     * If present the form should not be validated when submitted.
359
     *
360
     * @return string Returns novalidation state of this form.
361
     */
362
    public function isNoValidation()
363
    {
364
        return ($this->noValidation === true) ? 'novalidate' : '';
365
    }
366
367
    /**
368
     * Set novalidation state of this form.
369
     * If true the form should not be validated when submitted.
370
     *
371
     * @link http://dev.w3.org/html5/spec-author-view/association-of-controls-and-forms.html#attr-fs-novalidate
372
     *
373
     * @param bool $bool boolean state to set for novalidation.
374
     *
375
     * @return Form
376
     */
377
    public function setNoValidation($bool)
378
    {
379
        $this->noValidation = (bool) $bool;
380
381
        return $this;
382
    }
383
384
    /**
385
     * Returns the requested attribute if existing else null.
386
     *
387
     * @param $parametername
388
     *
389
     * @return mixed null or value of the attribute
390
     */
391
    public function getAttribute($attributename)
392
    {
393
        if (isset($this->{$attributename})) {
394
            return $this->{$attributename};
395
        } else {
396
            return;
397
        }
398
    }
399
400
    /**
401
     * Setter method for Attribute.
402
     *
403
     * @param array $attribute attribute name
404
     * @param array $value     value
405
     */
406
    public function setAttribute($attribute, $value)
407
    {
408
        $this->{$attribute} = $value;
409
    }
410
411
    /**
412
     * Setter method for Attributes.
413
     *
414
     * @param array $attributes Array with one or several attributename => value relationships.
415
     */
416
    public function setAttributes($attributes)
417
    {
418
        if (is_array($attributes)) {
419
            /*
420
             * The incomming attributes array contains a form description array for the formgenerator.
421
             */
422
            if (isset($attributes['form'])) {
423
                // generate form
424
                $form = new \Koch\Form\Generator\PHPArray($attributes);
425
                // copy all properties of the inner form object to ($this) outer form object =)
426
                $this->copyObjectProperties($form, $this);
427
                // unset inner form
428
                unset($form);
429
            } else {
430
                /*
431
                 * Just normal <form attribute(s)=value></form>
432
                 */
433
                foreach ($attributes as $attribute => $value) {
434
                    $this->setAttribute($attribute, $value);
0 ignored issues
show
Documentation introduced by
$attribute is of type string, but the function expects a array.

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...
Documentation introduced by
$value is of type null, but the function expects a array.

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...
435
                }
436
            }
437
        }
438
    }
439
440
    /**
441
     * Copy properties from object A to object B.
442
     *
443
     * @param object $object_to_copy The Object to copy the properties from.
444
     * @param object $target         The Object to copy the properties to. Defaults to $this.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $target not be object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
445
     */
446
    public function copyObjectProperties($object_to_copy, $target = null)
0 ignored issues
show
Coding Style introduced by
$object_to_copy does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
447
    {
448
        $varArray = get_object_vars($object_to_copy);
0 ignored issues
show
Coding Style introduced by
$object_to_copy does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
449
450
        foreach ($varArray as $key => $value) {
451
            // use this object, if no target object is specified
452
            if ($target === null) {
453
                $this->$key = $value;
454
            } else {
455
                $target->$key = $value;
456
            }
457
        }
458
459
        unset($key, $value);
460
    }
461
462
    /**
463
     * Set id of this form.
464
     *
465
     * @param string $id ID of this form.
466
     *
467
     * @return Form
468
     */
469
    public function setID($id)
470
    {
471
        $this->id = $id;
472
473
        return $this;
474
    }
475
476
    /**
477
     * Returns action of this form.
478
     *
479
     * @return string ID of this form.
480
     */
481
    public function getID()
482
    {
483
        return $this->id;
484
    }
485
486
    /**
487
     * Set name of this form.
488
     *
489
     * @param string $name Name of this form.
490
     *
491
     * @return Form
492
     */
493
    public function setName($name)
494
    {
495
        $this->name = $name;
496
497
        return $this;
498
    }
499
500
    /**
501
     * Returns name of this form.
502
     *
503
     * @return string Name of this form.
504
     */
505
    public function getName()
506
    {
507
        return $this->name;
508
    }
509
510
    /**
511
     * Set accept-charset of this form.
512
     * Like accept-charset="ISO-8859-1".
513
     *
514
     * @param string $charset Charset of this form (utf-8, iso-8859-1).
515
     *
516
     * @return Form
517
     */
518
    public function setAcceptCharset($charset)
519
    {
520
        $this->acceptcharset = $charset;
521
522
        return $this;
523
    }
524
525
    /**
526
     * Returns accept-charset of this form.
527
     *
528
     * @return string Accept-charset of this form. Defaults to UTF-8.
529
     */
530
    public function getAcceptCharset()
531
    {
532
        if (empty($this->acceptcharset)) {
533
            $this->setAcceptCharset('utf-8');
534
        }
535
536
        return $this->acceptcharset;
537
    }
538
539
    /**
540
     * Set class of this form.
541
     *
542
     * @param string $class Css Classname of this form.
543
     *
544
     * @return Form
545
     */
546
    public function setClass($class)
547
    {
548
        $this->class = $class;
549
550
        return $this;
551
    }
552
553
    /**
554
     * Returns css classname of this form.
555
     *
556
     * @return string Css Classname of this form.
557
     */
558
    public function getClass()
559
    {
560
        return $this->class;
561
    }
562
563
    /**
564
     * Sets the description text of this form.
565
     * The description is a p tag after the heading (form > h2 > p).
566
     *
567
     * @param string $description Description of this form.
568
     *
569
     * @return Form
570
     */
571
    public function setDescription($description)
572
    {
573
        $this->description = $description;
574
575
        return $this;
576
    }
577
578
    /**
579
     * Returns class of this form.
580
     *
581
     * @return string Description of this form.
582
     */
583
    public function getDescription()
584
    {
585
        return $this->description;
586
    }
587
588
    /**
589
     * Set a heading for this form.
590
     * The heading is a h2 tag directly after the opening form tag.
591
     *
592
     * @param string $heading Heading of this form.
593
     *
594
     * @return Form
595
     */
596
    public function setHeading($heading)
597
    {
598
        $this->heading = $heading;
599
600
        return $this;
601
    }
602
603
    /**
604
     * Returns heading of this form.
605
     *
606
     * @return string Heading of this form.
607
     */
608
    public function getHeading()
609
    {
610
        return $this->heading;
611
    }
612
613
    /**
614
     * Shortcut to set the Legend text of the fieldset decorator.
615
     *
616
     * The legend tag belongs to the fieldset decorator.
617
     * The fieldset decorator is a default decorator instantiated, when rendering the form.
618
     * It does not exist at the time of form definition.
619
     * So we keep the legend value stored, till the fieldset decorator is instantiated.
620
     * Then the decorator attributes array is automatically assigned to the form and it's objects.
621
     *
622
     * Note: you can use the long form (array notation) anytime, when defining your form.
623
     * Though using method chaining is a bit nicer (fluent interface).
624
     *
625
     * @param string String for the legend tag of the fieldset.
626
     * @param string $legend
627
     *
628
     * @return Form Koch_Form
629
     */
630
    public function setLegend($legend)
631
    {
632
        $this->setDecoratorAttributesArray(['form' => ['fieldset' => ['legend' => $legend]]]);
633
634
        return $this;
635
    }
636
637
    public function getLegend()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
638
    {
639
        return $this->decoratorAttributes['form']['fieldset']['legend'];
0 ignored issues
show
Documentation introduced by
The property decoratorAttributes does not exist on object<Koch\Form\Form>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
640
    }
641
642
    /**
643
     * Set encoding type of this form.
644
     *
645
     * - application/x-www-form-urlencoded
646
     *  All characters are encoded before sent (this is default)
647
     * - multipart/form-data
648
     *  No characters are encoded.
649
     *  This value is required when you are using forms that have a file upload control
650
     * - text/plain
651
     *  Spaces are converted to "+" symbols, but no special characters are encoded
652
     *
653
     * @param string $encoding Encoding type of this form.
654
     *
655
     * @return Form
656
     */
657
    public function setEncoding($encoding)
658
    {
659
        $this->encoding = $encoding;
660
661
        return $this;
662
    }
663
664
    /**
665
     * Returns encoding type of this form.
666
     *
667
     * @return string Encoding type of this form.
668
     */
669
    public function getEncoding()
670
    {
671
        if (empty($this->encoding)) {
672
            $this->encoding = 'multipart/form-data';
673
674
            return $this->encoding;
675
        } else {
676
            return $this->encoding;
677
        }
678
    }
679
680
    /**
681
     * Getter for formelements array.
682
     *
683
     * @return array Formelements
684
     */
685
    public function getFormelements()
686
    {
687
        return $this->formelements;
688
    }
689
690
    /**
691
     * Set formelements.
692
     *
693
     * @param string[] $formelements
694
     */
695
    public function setFormelements(array $formelements)
696
    {
697
        $this->formelements = $formelements;
698
    }
699
700
    /**
701
     * ===================================================================================
702
     *      Form Errors
703
     * ===================================================================================.
704
     */
705
706
    /**
707
     * Get the form error status.
708
     *
709
     * @return bool
710
     */
711
    public function formHasErrors()
0 ignored issues
show
Coding Style introduced by
function formHasErrors() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
712
    {
713
        return $this->error;
714
    }
715
716
    /**
717
     * ===================================================================================
718
     *      Render
719
     * ===================================================================================.
720
     */
721
722
    /**
723
     * Registers the default decorators for a formelement.
724
     * The default decorators are: label, description, div.
725
     *
726
     * @param object $formelement \Koch\Form\Element\Interface
727
     */
728
    public function registerDefaultFormelementDecorators($formelement)
729
    {
730
        $formelement->addDecorator('label');
731
        $formelement->addDecorator('description');
732
        $formelement->addDecorator('div')->setCssClass('formline');
733
    }
734
735
    /**
736
     * Renders all fromelements.
737
     *
738
     * @return string HTML of Formelements.
739
     */
740
    public function renderAllFormelements()
741
    {
742
        $html_form        = '';
0 ignored issues
show
Coding Style introduced by
$html_form does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
743
        $html_formelement = '';
0 ignored issues
show
Coding Style introduced by
$html_formelement does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
Unused Code introduced by
$html_formelement is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
744
745
        // fetch all formelements
746
        $formelements = $this->getFormelements();
747
748
        #\Koch\Debug::printR($formelements);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
749
        // developer hint: when $form->render() was triggered, but no formelement was added before
750
        if (count($formelements) === 0) {
751
            throw new \Koch\Exception\Exception(
752
                _('Error rendering formelements. ') .
753
                _('No formelements on form object. Consider adding some formelements using addElement().')
754
            );
755
        }
756
757
        // sort formelements by index
758
        ksort($formelements);
759
760
        // loop over all registered formelements of this form and render them
761
        foreach ($formelements as $formelement) {
762
            // fetch all decorators of this formelement
763
            $formelementdecorators = $formelement->getDecorators();
764
765
            /*
766
             * Do not add default formelement decorators
767
             * 1) if some were already added manually
768
             * 2) if the feature is disabled (setting is then incomming from inside the formelement)
769
             */
770
            if (empty($formelementdecorators) && ($formelement->disableDefaultDecorators === false)) {
771
                // apply default decorators to the formelement
772
                $this->registerDefaultFormelementDecorators($formelement);
773
774
                // fetch again all decorators of this formelement
775
                $formelementdecorators = $formelement->getDecorators();
776
            }
777
778
            // then render this formelement
779
            $html_formelement = $formelement->render();
0 ignored issues
show
Coding Style introduced by
$html_formelement does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
780
781
            // for each decorator, decorate the formelement and render it
782
            foreach ($formelementdecorators as $formelementdecorator) {
783
                $formelementdecorator->decorateWith($formelement);
784
                $html_formelement = $formelementdecorator->render($html_formelement);
0 ignored issues
show
Coding Style introduced by
$html_formelement does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
785
            }
786
787
            // append the form html with the decorated formelement html
788
            $html_form .= $html_formelement;
0 ignored issues
show
Coding Style introduced by
$html_form does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
789
        }
790
791
        #\Koch\Debug::printR($html_form);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
792
793
        return $html_form;
0 ignored issues
show
Coding Style introduced by
$html_form does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
794
    }
795
796
    /**
797
     * Render this form.
798
     *
799
     * @return Koch_Formelement
800
     */
801
    public function render()
802
    {
803
        // a) the content of the form are all the formelements
804
        $html_form = $this->renderAllFormelements();
0 ignored issues
show
Coding Style introduced by
$html_form does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
805
806
        // b) attach default decorators
807
        //if (empty($this->formdecorators)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
808
            // should the default form decorators be applied?
809
            if ($this->useDefaultFormDecorators === true) {
810
                // set a common style to the form by registering one or more decorators
811
                $this->registerDefaultFormDecorators();
812
            }
813
        //}
814
815
        // iterate over all decorators
816
        foreach ($this->getDecorators() as $decorator) {
817
            // stick form into the decorator decorator
818
            $decorator->decorateWith($this);
819
820
            // apply some settings or call some methods on the decorator
821
            // before rendering $decorator->$value; or $decorator->$method($value);
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
822
            // combined into $decorator->setAttributes();
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
823
            $this->applyDecoratorAttributes();
824
825
            $html_form = $decorator->render($html_form);
0 ignored issues
show
Coding Style introduced by
$html_form does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
826
827
            // remove the processed decorator from the decorators stack
828
            $this->removeDecorator($decorator);
829
830
            // unset decorator var in foreach context
831
            unset($decorator);
832
        }
833
834
        return $html_form;
0 ignored issues
show
Coding Style introduced by
$html_form does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
835
    }
836
837
    /**
838
     * Returns a XHTML string representation of the form.
839
     *
840
     * @see Koch_Form::render()
841
     *
842
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be Koch_Formelement?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
843
     */
844
    public function __toString()
845
    {
846
        return $this->render();
847
    }
848
849
    /**
850
     * ===================================================================================
851
     *      Formelement Handling (add, del, getByPos, getByName)
852
     * ===================================================================================.
853
     */
854
855
    /**
856
     * PSR-0 is idiotic! Inventors should shit theirs pants and attend PHP conferences wearing them.
857
     *
858
     * This is a case-insensitive file exists check.
859
     * This allows checking for names/file, which are not only ucfirst(), e.g. "SubmitButton".
860
     *
861
     * @param string $fileName
862
     *
863
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
864
     */
865
    public static function fileExists($fileName)
866
    {
867
        if (is_file($fileName)) {
868
            return $fileName;
869
        }
870
871
        // handle case insensitive requests
872
        $directoryName = dirname($fileName);
873
        $fileArray     = glob($directoryName . '/*', GLOB_NOSORT);
874
        foreach ($fileArray as $file) {
875
            if (false !== stripos($file, $fileName . '.')) {
876
                return realpath($file);
877
            }
878
        }
879
880
        return false;
881
    }
882
883
    /**
884
     * Adds a formelement to the form.
885
     *
886
     * You don't know the formelements available? Then take a look at
887
     * a) the directory core\viewhelper\form\formelements\*
888
     * b) the manual
889
     *
890
     * @param $formelement string|object Name of formelement or Object implementing the Koch_Form_Interface
891
     * @param $attributes array Attributes for the formelement.
892
     * @param $position integer The position of this formelement in the formelements stack.
893
     *
894
     * @return object \Koch\Form\Form
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use Koch_Formelement|FormElementInterface.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
895
     */
896
    public function addElement($formelement, $attributes = null, $position = null)
897
    {
898
        /**
899
         * Continue, if parameter $formelement is an formelement object, implementing
900
         * the \Koch\Form\Element\Interface. Else it's a string with the name of the formelement,
901
         * which we pass to the factory to deliver that formelement object.
902
         *
903
         * Note: Checking for the interface is necessary here, because checking for type string,
904
         * like if(is_string(formelement)), would result in true, because all formelement
905
         * objects provide the __toString() method for easier rendering.
906
         */
907
        if (($formelement instanceof \Koch\Form\FormelementInterface) === false) {
908
            $formelement = self::formelementFactory($formelement);
909
        }
910
911
        // for easier use of the formelement "file":
912
        // this switches the "encytype" attribute of the form tag.
913
        if ($formelement instanceof \Koch\Form\Formelement\File) {
0 ignored issues
show
Bug introduced by
The class Koch\Form\Formelement\File does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
914
            $this->setEncoding('multipart/form-data');
915
        }
916
917
        // helper for setting formelement attributes directly when adding
918
        if (is_array($attributes)) {
919
            $formelement->setAttributes($attributes);
0 ignored issues
show
Bug introduced by
The method setAttributes() does not exist on Koch\Form\FormElementInterface. Did you maybe mean setAttribute()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
920
        }
921
922
        /*
923
         * create formelement identifier automatically if not set manually.
924
         * this is needed for javascript selections via id tag.
925
         */
926
        if (strlen($formelement->getID()) === 0) {
927
            $formelement->setID($formelement->type . '-formelement-' . count($this->formelements));
928
        }
929
930
        // if we don't have a position to order the elements, we just add an element
931
        // this is the default behaviour
932
        if ($position === null) {
933
            $this->formelements[] = $formelement;
934
        } elseif (is_int($position)) {
935
            // else we position the element under it's number to keep things in an order
936
937
            // hmpf, there is already an element at this position
938
            if ($this->formelements[$position] !== null) {
939
                // insert the new element to the requested position and reorder
940
                $this->formelements = $this->arrayInsert($formelement, $position, $this->formelements);
941
942
                // after repositioning we need to recalculate the formelement ids
943
                $this->regenerateFormelementIdentifiers();
944
            }
945
        } else {
946
            // just add to the requested position
947
            $this->formelements[$position] = $formelement;
948
        }
949
950
        // return formelement object -> fluent interface / method chaining
951
        return $formelement;
952
    }
953
954
    /**
955
     * Regenerates the generic identifier of each formelement in the stack by it's position.
956
     * The formelement at stack position 1 becomes "name-formelement-1", etc.
957
     */
958
    public function regenerateFormelementIdentifiers()
959
    {
960
        $pos_lastpart = '';
0 ignored issues
show
Coding Style introduced by
$pos_lastpart does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
961
        $pos          = '';
962
        $firstpart    = '';
963
        $id           = '';
964
965
        $i = 0;
966
967
        foreach ($this->formelements as $formelement) {
968
            $id = $formelement->getID();
969
970
            /*
971
             * the autogenerated id string has the following abstract format:
972
             * "type-formelement-id". it's exact string length is unknown.
973
             * the last part separated by a minus (the id part) is stripped off
974
             * of the string.
975
             */
976
            $pos_lastpart = strrpos($id, '-') + 1;
0 ignored issues
show
Coding Style introduced by
$pos_lastpart does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
977
            $pos          = strlen($id) - $pos_lastpart;
0 ignored issues
show
Coding Style introduced by
$pos_lastpart does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
978
            $firstpart    = substr($id, 0, -$pos);
979
980
            // the new id is then appended to the remaining firstpart of the string
981
            $id = $firstpart .= $i;
982
983
            $formelement->setID($id);
984
985
            ++$i;
986
        }
987
988
        unset($i, $pos_lastpart, $pos, $firstpart, $id);
0 ignored issues
show
Coding Style introduced by
$pos_lastpart does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
989
    }
990
991
    /**
992
     * Inserts value at a certain index into an array.
993
     *
994
     * @param mixed $value The new element to insert into the array.
995
     * @param array $array The "old" array.
996
     * @param int   $index The index to insert the value
997
     *
998
     * @return array $array with $value at position $index.
999
     */
1000
    private function arrayInsert($value, $index, &$array)
1001
    {
1002
        return array_merge(array_slice($array, 0, $index), [$value], array_slice($array, $index));
1003
    }
1004
1005
    /**
1006
     * Removes a formelement by name (not type!).
1007
     *
1008
     * @param string $name
1009
     *
1010
     * @return bool
1011
     */
1012
    public function delElementByName($name)
1013
    {
1014
        $cnt_formelements = count($this->formelements);
0 ignored issues
show
Coding Style introduced by
$cnt_formelements does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1015
        for ($i = 0; $i < $cnt_formelements; ++$i) {
0 ignored issues
show
Coding Style introduced by
$cnt_formelements does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1016
            if ($name === $this->formelements[$i]->getName()) {
1017
                unset($this->formelements[$i]);
1018
1019
                return true;
1020
            }
1021
        }
1022
1023
        return false;
1024
    }
1025
1026
    /**
1027
     * Fetches a formelement via it's position number.
1028
     *
1029
     * @param $position integer The position number the requested formelement (ordering).
1030
     *
1031
     * @return Koch_Formelement $formelement Object implementing the Koch_Form_Interface
1032
     */
1033
    public function getElementByPosition($position)
1034
    {
1035
        if (is_numeric($position) and isset($this->formelements[$position])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1036
            return $this->formelements[$position];
1037
        }
1038
1039
        return;
1040
    }
1041
1042
    /**
1043
     * Fetches a formelement via it's name (not type!).
1044
     *
1045
     * @param $name string The name of the requested formelement.
1046
     *
1047
     * @return Koch_Formelement $formelement Object
1048
     */
1049
    public function getElementByName($name)
1050
    {
1051
        foreach ($this->formelements as $formelement) {
1052
            if ($name === $formelement->getName()) {
1053
                return $formelement;
1054
            }
1055
        }
1056
1057
        return;
1058
    }
1059
1060
    /**
1061
     * Fetches a formelement by it's name or position or
1062
     * returns the last element in the stack as default.
1063
     *
1064
     * @param $position string|int Name or position of the formelement.
1065
     *
1066
     * @return Koch_Formelement $formelement Object
1067
     */
1068
    public function getElement($position = null)
1069
    {
1070
        $formelement_object = '';
0 ignored issues
show
Unused Code introduced by
$formelement_object is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Coding Style introduced by
$formelement_object does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1071
1072
        // if no position is incomming, the last formelement is returned.
1073
        // this is the normal call to this method, while chaining.
1074
        if ($position === null) {
1075
            // fetch last item of array = last_formelement
1076
            $formelement_object = end($this->formelements);
0 ignored issues
show
Coding Style introduced by
$formelement_object does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1077
        } elseif (is_numeric($position)) {
1078
            // fetch formelements from certain position
1079
            $formelement_object = $this->getElementByPosition($position);
0 ignored issues
show
Coding Style introduced by
$formelement_object does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1080
        } else {
1081
            // position is_string
1082
            $formelement_object = $this->getElementByName($position);
0 ignored issues
show
Coding Style introduced by
$formelement_object does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1083
        }
1084
1085
        /* @var \Koch\Form\FormElement */
1086
1087
        return $formelement_object;
0 ignored issues
show
Coding Style introduced by
$formelement_object does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1088
    }
1089
1090
    /**
1091
     * ===================================================================================
1092
     *      Formelement Factory
1093
     * ===================================================================================.
1094
     */
1095
1096
    /**
1097
     * Factory method. Instantiates and returns a new formelement object.
1098
     * For a list of all available formelements visit the "/formelements" directory.
1099
     *
1100
     * @return Koch_Formelement object
1101
     */
1102
    public static function formelementFactory($formelement)
1103
    {
1104
        // case-insensitve file in folder check to get filename, which is the classname
1105
        // thanks to PSR-0
1106
        $file = self::fileExists(__DIR__ . '/Elements/' . $formelement);
1107
1108
        if ($file === false) {
1109
            throw new \Exception('The Formelement "' . $formelement . '" does not exist.');
1110
        }
1111
1112
        // get PSR-0 classname from file
1113
        $pi        = pathinfo($file);
1114
        $classname = $pi['filename'];
1115
1116
        // class = namespace "Koch\Form\Element\" + formelement name
1117
        $class = '\Koch\Form\Elements\\' . $classname;
1118
1119
        // instantiate the new formelement and return
1120
        return new $class();
1121
    }
1122
1123
    /**
1124
     * ===================================================================================
1125
     *      Form Processing
1126
     * ===================================================================================.
1127
     */
1128
1129
    /**
1130
     * processForm.
1131
     *
1132
     * This is the main formular processing loop.
1133
     * If the form does not validate, then redisplay it,
1134
     * else present "Success"-Message!
1135
     */
1136
    public function processForm()
1137
    {
1138
        // check, if form has been submitted properly
1139
        if ($this->validateForm()) {
1140
            /*
1141
             * Success - form content valid.
1142
             * The "noerror" decorator implementation decides,
1143
             * if a success web page or a flashmessage is used.
1144
             */
1145
            $this->addDecorator('NoError');
0 ignored issues
show
Documentation introduced by
'NoError' is of type string, but the function expects a array.

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...
1146
        } else {
1147
            /*
1148
             * Failure - form was not filled properly.
1149
             * Redisplay the form with error decorator added.
1150
             */
1151
            $this->addDecorator('Errors');
0 ignored issues
show
Documentation introduced by
'Errors' is of type string, but the function expects a array.

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...
1152
        }
1153
    }
1154
1155
    /**
1156
     * Get the data array.
1157
     *
1158
     * @return array containing all the form data.
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
1159
     */
1160
    protected function bind()
1161
    {
1162
    }
1163
1164
    /**
1165
     * Set Values to Form.
1166
     *
1167
     * An associative array is used to pre-populate form elements.
1168
     * The keys of this array correspond with the element names.
1169
     *
1170
     * There are two use cases for this method:
1171
     * 1) pre-filled form
1172
     *    Some default values are set to the form, which then get altered by the user.
1173
     * b) incomming post data
1174
     *    Set the incomming POST data values are set to the form for validation.
1175
     *
1176
     * @param object|array $data Object or Array. If null (default), POST parameters are used.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $data not be object|array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1177
     */
1178
    public function setValues($data = null)
1179
    {
1180
        // because $data might be an object, typecast $data object to array
1181
        if (is_object($data)) {
1182
            $data = (array) $data;
1183
        }
1184
        if (null === $data) { // fetch data from POST
1185
            if ('POST' === \Koch\Http\HttpRequest::getRequestMethod()) {
1186
                $data = \Koch\Http\HttpRequest::getPost();
1187
            }
1188
        }
1189
1190
        // now we got an $data array to populate all the formelements with (setValue)
1191
        foreach ($data as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $data of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1192
            foreach ($this->formelements as $formelement) {
1193
1194
                /*
1195
                 * Exclude some formelements from setValue() by type, e.g. Buttons, etc.
1196
                 * Setting the value would just change the visible "name" of these elements.
1197
                 */
1198
                $type = $formelement->getType();
1199
                if (true === in_array($type, ['submit', 'button', 'cancelbutton', 'resetbutton'], true)) {
1200
                    continue;
1201
                }
1202
1203
                // data[key] and formelement[name] have to match
1204
                //if ($formelement->getName() == ucfirst($key)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1205
                    $formelement->setValue($value);
1206
                //}
1207
            }
1208
        }
1209
    }
1210
1211
    /**
1212
     * Get all values of the form.
1213
     *
1214
     * Or a bit more exact:
1215
     * Get an array with the values of all the formelements objects which are registered to the form object.
1216
     * The values are validated and ready for further processing, e.g. insert to model object.
1217
     *
1218
     * The validation is the big difference between using the $_POST array directly or indirectly.
1219
     *
1220
     * @return array
1221
     */
1222
    public function getValues()
1223
    {
1224
        $values = [];
1225
1226
        foreach ($this->formelements as $formelement) {
1227
            /*
1228
             * Create an associative array $value[id] => value
1229
             */
1230
            $values[$formelement->getId()] = $formelement->getValue();
1231
        }
1232
1233
        // return validated values, ready for further processing (model insert)
1234
        return $values;
1235
    }
1236
1237
    /**
1238
     * ===================================================================================
1239
     *      Form Decoration
1240
     * ===================================================================================.
1241
     */
1242
1243
    /**
1244
     * Is a shortcut/proxy/convenience method for addDecorator()
1245
     * <strong>WATCH OUT! THIS BREAKS THE CHAINING IN REGARD TO THE FORM</strong>.
1246
     *
1247
     * @see $this->addDecorator()
1248
     *
1249
     * @param string $decorators Array of decorator objects or names or just one string.
1250
     * @param array  $attributes Array of properties for the decorator object.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $attributes not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1251
     *
1252
     * @return Koch_Formdecorator object
1253
     */
1254
    public function setDecorator($decorators, $attributes = null)
1255
    {
1256
        return $this->addDecorator($decorators, $attributes);
0 ignored issues
show
Documentation introduced by
$decorators is of type string, but the function expects a array.

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...
1257
    }
1258
1259
    /**
1260
     * Add multiple decorators at once.
1261
     *
1262
     * @param array $decorators Array of decorator objects or names.
1263
     */
1264
    public function addDecorators($decorators)
1265
    {
1266
        // address each one of those decorators
1267
        foreach ($decorators as $decorator) {
1268
            $this->addDecorator($decorator);
1269
        }
1270
    }
1271
1272
    /**
1273
     * Adds a decorator to the form
1274
     * <strong>WATCH OUT! THIS BREAKS THE CHAINING IN REGARD TO THE FORM</strong>.
1275
     *
1276
     * @example
1277
     * $form->addDecorator('fieldset')->setLegend('legendname');
1278
     *
1279
     * @param array $decorator  Array of decorator objects or names or just one string.
1280
     * @param array $attributes Array of properties for the decorator object.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $attributes not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1281
     *
1282
     * @return Koch_Formdecorator object
1283
     */
1284
    public function addDecorator($decorator, $attributes = null)
1285
    {
1286
        // check if multiple decorator are incomming at once
1287
        if (is_array($decorator)) {
1288
            $this->addDecorators($decorator);
1289
        }
1290
1291
        // if we got a string
1292
        if (is_string($decorator)) {
1293
            // turn string into an decorator object
1294
            $decorator = $this->decoratorFactory($decorator);
1295
        }
1296
1297
        // and check if it is an object implementing the right interface
1298
        if ($decorator instanceof \Koch\Form\DecoratorInterface) {
1299
            // if so, fetch this decorator objects name
1300
            $decoratorname = '';
0 ignored issues
show
Unused Code introduced by
$decoratorname is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1301
            $decoratorname = $decorator->name;
1302
        }
1303
1304
        // apply attributes (2nd param) to the decorator
1305
        if ($attributes !== null) {
1306
            foreach ($attributes as $attribute => $value) {
1307
                $decorator->$attribute = $value;
1308
            }
1309
            #$decorator->setDecoratorAttributesArray($attributes);
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1310
            #\Koch\Debug::printR($decorator);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1311
        }
1312
1313
        // now check if this decorator is not already set (prevent decorator duplications)
1314
        if (false === in_array($decorator, $this->formdecorators, true)) {
1315
            // set this decorator object under its name into the array
1316
            $this->formdecorators[$decoratorname] = $decorator;
0 ignored issues
show
Bug introduced by
The variable $decoratorname does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1317
        }
1318
1319
        // WATCH OUT! THIS BREAKS THE CHAINING IN REGARD TO THE FORM
1320
        // We dont return $this here, because $this would be the FORM.
1321
        // Instead the decorator is returned, to apply some properties.
1322
        // @return decorator object
1323
        return $this->formdecorators[$decoratorname];
1324
    }
1325
1326
    /**
1327
     * Getter Method for the formdecorators.
1328
     *
1329
     * @return array with registered formdecorators
1330
     */
1331
    public function getDecorators()
1332
    {
1333
        return $this->formdecorators;
1334
    }
1335
1336
    /**
1337
     * Toggles the Usage of Default Form Decorators
1338
     * If set to false, registerDefaultFormDecorators() is not called during render().
1339
     *
1340
     * @see render()
1341
     * @see registerDefaultFormDecorators()
1342
     *
1343
     * @param type $boolean Form is decorated on true (default), not decorated on false.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $boolean not be boolean|type?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1344
     */
1345
    public function useDefaultFormDecorators($boolean = true)
1346
    {
1347
        $this->useDefaultFormDecorators = $boolean;
0 ignored issues
show
Documentation Bug introduced by
It seems like $boolean can also be of type object<Koch\Form\type>. However, the property $useDefaultFormDecorators is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1348
    }
1349
1350
    /**
1351
     * Set default form decorators (form).
1352
     */
1353
    public function registerDefaultFormDecorators()
1354
    {
1355
        $this->addDecorator('form');
0 ignored issues
show
Documentation introduced by
'form' is of type string, but the function expects a array.

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...
1356
        $this->addDecorator('fieldset');
0 ignored issues
show
Documentation introduced by
'fieldset' is of type string, but the function expects a array.

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...
1357
        $this->addDecorator('div')->setId('forms');
0 ignored issues
show
Documentation introduced by
'div' is of type string, but the function expects a array.

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...
1358
    }
1359
1360
    /**
1361
     * Removes a form decorator from the decorator stack by name or object.
1362
     *
1363
     * @param mixed|string|object $decorator Object or String identifying the Form Decorator.
1364
     */
1365
    public function removeDecorator($decorator)
1366
    {
1367
        // check if it is an object implementing the right interface
1368
        if ($decorator instanceof \Koch\Form\DecoratorInterface) {
1369
            // if so, fetch this decorator objects name
1370
            // and overwrite $decorator variable containing the object
1371
            // with the decorator name string
1372
            $decorator = (string) $decorator->name;
0 ignored issues
show
Bug introduced by
Accessing name on the interface Koch\Form\DecoratorInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1373
        }
1374
1375
        // here variable $decorator must be string
1376
        if (isset($this->formdecorators[$decorator]) || array_key_exists($decorator, $this->formdecorators)) {
1377
            unset($this->formdecorators[$decorator]);
1378
        }
1379
    }
1380
1381
    public function getDecorator($decorator)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1382
    {
1383
        if (isset($this->formdecorators[$decorator])) {
1384
            return $this->formdecorators[$decorator];
1385
        } else {
1386
            throw new \InvalidArgumentException('The Form does not have a Decorator called "' . $decorator . '".');
1387
        }
1388
    }
1389
1390
    /**
1391
     * Factory method. Instantiates and returns a new formdecorator object.
1392
     *
1393
     * @param string Name of Formdecorator.
1394
     * @param string $decorator
1395
     *
1396
     * @return Koch_Formdecorator
1397
     */
1398
    public function decoratorFactory($decorator)
1399
    {
1400
        $classmap = [
1401
            'html5validation' => 'Html5Validation',
1402
            'noerror'         => 'NoError',
1403
        ];
1404
1405
        if (isset($classmap[$decorator]) || array_key_exists($decorator, $classmap)) {
1406
            $decorator = $classmap[$decorator];
1407
        } else {
1408
            $decorator = ucfirst($decorator);
1409
        }
1410
1411
        $class = 'Koch\Form\Decorators\Form\\' . ucfirst($decorator);
1412
1413
        return new $class();
1414
    }
1415
1416
    /**
1417
     * Sets the Decorator Attributes Array.
1418
     *
1419
     * Decorators are not instantiated at the time of the form definition via an array.
1420
     * So configuration can only be applied indirtly to these objects.
1421
     * The values are keept in this array and are autmatically applied, when rendering the form.
1422
     *
1423
     * @return array decoratorAttributes
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
1424
     */
1425
    public function setDecoratorAttributesArray(array $attributes)
1426
    {
1427
        $this->decoratorAttributes = $attributes;
0 ignored issues
show
Documentation introduced by
The property decoratorAttributes does not exist on object<Koch\Form\Form>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1428
    }
1429
1430
    /**
1431
     * Returns the Decorator Attributes Array.
1432
     *
1433
     * Decorators are not instantiated at the time of the form definition via an array.
1434
     * So configuration can only be applied indirtly to these objects.
1435
     * The values are keept in this array and are autmatically applied, when rendering the form.
1436
     *
1437
     * @return array decoratorAttributes
1438
     */
1439
    public function getDecoratorAttributesArray()
1440
    {
1441
        return $this->decoratorAttributes;
0 ignored issues
show
Documentation introduced by
The property decoratorAttributes does not exist on object<Koch\Form\Form>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1442
    }
1443
1444
    /**
1445
     * Array Structure.
1446
     *
1447
     * $decorator_attributes = array(
1448
     *  Level 1 - key = decorator type
1449
     *  'form'  => array (
1450
     *              Level 2 - key = decorator name
1451
     *             'fieldset' => array (
1452
     *                   Level 3 - key = attribute name and value = mixed(string|int)
1453
     *                  'description' =>  'description test')
1454
     *                  )     *
1455
     *  'formelement' = array ( array() )
1456
     * );
1457
     * form => array ( fieldset => array( description => description text ) )
1458
     */
1459
    public function applyDecoratorAttributes()
1460
    {
1461
        $attributes = (array) $this->decoratorAttributes;
1462
1463
        #\Koch\Debug::printR($attributes);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1464
        // level 1
1465
        foreach ($attributes as $decorator_type => $decoratorname_array) {
0 ignored issues
show
Coding Style introduced by
$decorator_type does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1466
            // apply settings for the form itself
1467 View Code Duplication
            if ($decorator_type === 'form') {
0 ignored issues
show
Coding Style introduced by
$decorator_type does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1468
                // level 2
1469
                foreach ($decoratorname_array as $decoratorname => $attribute_and_value) {
0 ignored issues
show
Coding Style introduced by
$decoratorname_array does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1470
                    $decorator = $this->getDecorator($decoratorname);
1471
                    #\Koch\Debug::printR($attribute_and_value);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1472
                    // level 3
1473
                    foreach ($attribute_and_value as $attribute => $value) {
0 ignored issues
show
Coding Style introduced by
$attribute_and_value does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1474
                        $decorator->$attribute = $value;
1475
                    }
1476
                    #\Koch\Debug::printR($decorator);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1477
                }
1478
            }
1479
1480
            // apply settings to a formelement of the form
1481 View Code Duplication
            if ($decorator_type === 'formelement') {
0 ignored issues
show
Coding Style introduced by
$decorator_type does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1482
                // level 2
1483
                foreach ($decoratorname_array as $decoratorname => $attribute_and_value) {
0 ignored issues
show
Coding Style introduced by
$decoratorname_array does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1484
                    $decorator = $this->getFormelementDecorator($decoratorname);
0 ignored issues
show
Bug introduced by
The method getFormelementDecorator() does not seem to exist on object<Koch\Form\Form>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1485
                    #\Koch\Debug::printR($attribute_and_value);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1486
                    // level 3
1487
                    foreach ($attribute_and_value as $attribute => $value) {
0 ignored issues
show
Coding Style introduced by
$attribute_and_value does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1488
                        $decorator->$attribute = $value;
1489
                    }
1490
                }
1491
            }
1492
        }
1493
1494
        unset($attributes, $this->decoratorAttributes);
1495
    }
1496
1497
    /**
1498
     * ===================================================================================
1499
     *      Formelement Decoration
1500
     * ===================================================================================.
1501
     */
1502
1503
    /**
1504
     * setFormelementDecorator.
1505
     *
1506
     * Is a shortcut/proxy/convenience method for addFormelementDecorator()
1507
     *
1508
     * @see $this->addFormelementDecorator()
1509
     *
1510
     * WATCH OUT! THIS BREAKS THE CHAINING IN REGARD TO THE FORM
1511
     *
1512
     * @param string $decorator
1513
     *
1514
     * @return Koch_Formdecorator object
1515
     */
1516
    public function setFormelementDecorator($decorator, $formelement_position = null)
0 ignored issues
show
Coding Style introduced by
$formelement_position does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1517
    {
1518
        return $this->addFormelementDecorator($decorator, $formelement_position);
0 ignored issues
show
Coding Style introduced by
$formelement_position does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1519
    }
1520
1521
    /**
1522
     * Adds a decorator to a formelement.
1523
     *
1524
     * The first parameter accepts the formelement decorator.
1525
     * You might specify a decorater
1526
     * (a) by its name or
1527
     * (b) multiple decorators as an array or
1528
     * (c) a instantied decorator object might me handed to this method.
1529
     *
1530
     * @see addDecorator()
1531
     *
1532
     * The second parameter specifies the formelement_position.
1533
     * If no position is given, it defaults to the last formelement in the stack of formelements.
1534
     *
1535
     * <strong>WATCH OUT! THIS BREAKS THE CHAINING IN REGARD TO THE FORM</strong>
1536
     *
1537
     * @example
1538
     * $form->addFormelementDecorator('fieldset')->setLegend('legendname');
1539
     * This would attach the decorator fieldset to the last formelement of $form.
1540
     *
1541
     * @param string            $decorator                The formelement decorator(s) to apply to the formelement.
1542
     * @param int|string|object $formelement_pos_name_obj Position in the formelement stack or Name of formelement.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $formelement_pos_name_obj not be integer|string|object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1543
     *
1544
     * @return object \Koch\Form\Decorators\Formelement\Interface
1545
     */
1546
    public function addFormelementDecorator($decorator, $formelement_pos_name_obj = null)
0 ignored issues
show
Coding Style introduced by
$formelement_pos_name_obj does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1547
    {
1548
        if (true === empty($this->formelements)) {
1549
            throw new \RuntimeException('No Formelements found. Add the formelement(s) first, then decorate!');
1550
        }
1551
1552
        $formelement_object = '';
0 ignored issues
show
Coding Style introduced by
$formelement_object does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1553
1554
        if (false === is_object($formelement_pos_name_obj)) {
0 ignored issues
show
Coding Style introduced by
$formelement_pos_name_obj does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1555
            $formelement_object = $this->getElement($formelement_pos_name_obj);
0 ignored issues
show
Coding Style introduced by
$formelement_object does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1556
        }
1557
1558
        return $formelement_object->addDecorator($decorator);
0 ignored issues
show
Coding Style introduced by
$formelement_object does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1559
    }
1560
1561
    /**
1562
     * Removes a decorator from a formelement.
1563
     *
1564
     * @param string $decorator
1565
     * @param type   $formelement_position
0 ignored issues
show
Documentation introduced by
Should the type for parameter $formelement_position not be type|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1566
     */
1567
    public function removeFormelementDecorator($decorator, $formelement_position = null)
0 ignored issues
show
Coding Style introduced by
$formelement_position does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1568
    {
1569
        $formelement = $this->getElement($formelement_position);
0 ignored issues
show
Coding Style introduced by
$formelement_position does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1570
        $formelement->removeDecorator($decorator);
1571
    }
1572
1573
    /**
1574
     * ===================================================================================
1575
     *      Form Validation
1576
     * ===================================================================================.
1577
     */
1578
1579
    /**
1580
     * Adds a validator to the formelement.
1581
     *
1582
     * @return Form
1583
     */
1584
    public function addValidator($validator)
1585
    {
1586
        if (is_object($validator) and is_a($validator, Koch\Form\ValidatorInterface)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1587
        }
1588
1589
        return $this;
1590
    }
1591
1592
    /**
1593
     * Validates the form.
1594
     *
1595
     * The method iterates (loops over) all formelement objects and calls the validation on each object.
1596
     * In other words: a form is valid, if all formelement are valid. Surprise, surprise.
1597
     * If a formelement is not valid, the error flag on the form is raised and the error message
1598
     * of the formelement is transferred to the error message stack of the form.
1599
     *
1600
     * @return bool Returns true if form validates, false if validation fails, because errors exist.
1601
     */
1602
    public function validateForm()
0 ignored issues
show
Coding Style introduced by
function validateForm() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
1603
    {
1604
        foreach ($this->formelements as $formelement) {
1605
            if ($formelement->validate() === false) {
1606
                $this->hasErrors(true);
1607
                $this->addErrorMessages($formelement->getErrorMessages());
1608
            }
1609
        }
1610
1611
        // if form has errors, it does not validate
1612
        return $this->hasErrors() ? false : true;
1613
    }
1614
1615
    /**
1616
     * ===================================================================================
1617
     *      Form Errormessages
1618
     * ===================================================================================.
1619
     */
1620
1621
    /**
1622
     * Returns the error state of the form.
1623
     *
1624
     * @param bool $boolean
0 ignored issues
show
Documentation introduced by
Should the type for parameter $boolean not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1625
     *
1626
     * @return bool True, if form has an error. False, otherwise.
1627
     */
1628
    public function hasErrors($boolean = null)
1629
    {
1630
        if (is_bool($boolean)) {
1631
            $this->error = $boolean;
1632
        }
1633
1634
        return $this->error;
1635
    }
1636
1637
    /**
1638
     * @param string $errorMessage
1639
     */
1640
    public function addErrorMessage($errorMessage)
1641
    {
1642
        $this->errorMessages[] = $errorMessage;
1643
    }
1644
1645
    public function addErrorMessages(array $errorMessages)
1646
    {
1647
        $this->errorMessages = $errorMessages;
1648
    }
1649
1650
    public function resetErrorMessages()
1651
    {
1652
        $this->errorMessages = [];
1653
    }
1654
1655
    public function getErrorMessages()
1656
    {
1657
        return $this->errorMessages;
1658
    }
1659
1660
    /**
1661
     * ============================
1662
     *    Magic Methods: get/set
1663
     * ============================.
1664
     */
1665
1666
    /**
1667
     * Magic Method: set.
1668
     *
1669
     * @param $name Name of the attribute to set to the form.
1670
     * @param $value The value of the attribute.
1671
     */
1672
    public function __set($name, $value)
1673
    {
1674
        $this->setAttributes([$name => $value]);
1675
    }
1676
1677
    /**
1678
     * Magic Method: get.
1679
     *
1680
     * @param $name
1681
     */
1682
    public function __get($name)
1683
    {
1684
        return $this->getAttribute($name);
1685
    }
1686
}
1687