Test Failed
Push — master ( 194522...eda1b6 )
by Mikael
01:43
created

FormElement::getValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Anax\HTMLForm;
4
5
/**
6
 * A utility class to easy creating and handling of forms
7
 */
8
class FormElement implements \ArrayAccess
9
{
10
11
    /**
12
     * Properties
13
     */
14
    public $attributes;
15
    public $characterEncoding;
16
17
18
19
    /**
20
     * Constructor creating a form element.
21
     *
22
     * @param string $name       of the element.
23
     * @param array  $attributes to set to the element. Default is an empty array.
24
     */
25
    public function __construct($name, $attributes = [])
26
    {
27
        $this->attributes = $attributes;
28
        $this['name'] = $name;
29
        //$this['key'] = $name;
30
        //$this['name'] = isset($this['name']) ? $this['name'] : $name;
31
32
        // Use character encoding from lydia if available, else use UTF-8 OBSOLETE, remove this.
33
        if (is_callable('CLydia::Instance()')) {
34
            $this->characterEncoding = CLydia::Instance()->config['character_encoding'];
35
        } else {
36
            $this->characterEncoding = 'UTF-8';
37
        }
38
    }
39
  
40
  
41
42
    /**
43
     * Implementing ArrayAccess for this->attributes
44
     *
45
     * @return void
46
     */
47
    public function offsetSet($offset, $value)
48
    {
49 View Code Duplication
        if (is_null($offset)) {
0 ignored issues
show
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...
50
            $this->attributes[] = $value;
51
        } else {
52
            $this->attributes[$offset] = $value;
53
        }
54
    }
55
    
56
57
58
    /**
59
     * Implementing ArrayAccess for this->attributes
60
     */
61
    public function offsetExists($offset)
62
    {
63
        return isset($this->attributes[$offset]);
64
    }
65
    
66
67
68
    /**
69
     * Implementing ArrayAccess for this->attributes
70
     */
71
    public function offsetUnset($offset)
72
    {
73
        unset($this->attributes[$offset]);
74
    }
75
    
76
77
78
    /**
79
     * Implementing ArrayAccess for this->attributes
80
     */
81
    public function offsetGet($offset)
82
    {
83
        return isset($this->attributes[$offset]) ? $this->attributes[$offset] : null;
84
    }
85
86
87
88
    /**
89
     * Create a formelement from an array, factory returns the correct
90
     * instance.
91
     *
92
     * @param string $name       name of the element.
93
     * @param array  $attributes to use when creating the element.
94
     *
95
     * @return the instance of the form element.
96
     */
97
    public static function create($name, $attributes)
98
    {
99
        // Not supported is type=image, <button>, list, output, select-optgroup
100
        $types = [
101
102
            // Standard HTML 4.01
103
            'text'              => '\Anax\HTMLForm\FormElementText',
104
            'file'              => '\Anax\HTMLForm\FormElementFile',
105
            'password'          => '\Anax\HTMLForm\FormElementPassword',
106
            'hidden'            => '\Anax\HTMLForm\FormElementHidden',
107
            'textarea'          => '\Anax\HTMLForm\FormElementTextarea',
108
            'radio'             => '\Anax\HTMLForm\FormElementRadio',
109
            'checkbox'          => '\Anax\HTMLForm\FormElementCheckbox',
110
            'select'            => '\Anax\HTMLForm\FormElementSelect',
111
            'select-multiple'   => '\Anax\HTMLForm\FormElementSelectMultiple',
112
            'submit'            => '\Anax\HTMLForm\FormElementSubmit',
113
            'reset'             => '\Anax\HTMLForm\FormElementReset',
114
            'button'            => '\Anax\HTMLForm\FormElementButton',
115
116
            // HTML5
117
            'color'             => '\Anax\HTMLForm\FormElementColor',
118
            'date'              => '\Anax\HTMLForm\FormElementDate',
119
            'number'            => '\Anax\HTMLForm\FormElementNumber',
120
            'range'             => '\Anax\HTMLForm\FormElementRange',
121
            'tel'               => '\Anax\HTMLForm\FormElementTel',
122
            'email'             => '\Anax\HTMLForm\FormElementEmail',
123
            'url'               => '\Anax\HTMLForm\FormElementUrl',
124
            'search'            => '\Anax\HTMLForm\FormElementSearch',
125
            'file-multiple'     => '\Anax\HTMLForm\FormElementFileMultiple',
126
            'datetime'          => '\Anax\HTMLForm\FormElementDatetime',
127
            'datetime-local'    => '\Anax\HTMLForm\FormElementDatetimeLocal',
128
            'month'             => '\Anax\HTMLForm\FormElementMonth',
129
            'time'              => '\Anax\HTMLForm\FormElementTime',
130
            'week'              => '\Anax\HTMLForm\FormElementWeek',
131
132
            // Custom
133
            'search-widget'     => '\Anax\HTMLForm\FormElementSearchWidget',
134
            'checkbox-multiple' => '\Anax\HTMLForm\FormElementCheckboxMultiple',
135
            // Address
136
        ];
137
138
        // $attributes['type'] must contain a valid type creating an object to succeed.
139
        $type = isset($attributes['type']) ? $attributes['type'] : null;
140
141
        if ($type && isset($types[$type])) {
142
            return new $types[$type]($name, $attributes);
143
        } else {
144
            throw new Exception("Form element does not exists and can not be created: $name - $type");
145
        }
146
    }
147
148
149
150
    /**
151
     * Get id of an element.
152
     *
153
     * @return HTML code for the element.
154
     */
155
    public function getElementId()
156
    {
157
        return ($this['id'] = isset($this['id']) ? $this['id'] : 'form-element-' . $this['name']);
158
    }
159
160
161
162
    /**
163
     * Get alll validation messages.
164
     *
165
     * @return HTML code for the element.
166
     */
167
    public function getValidationMessages()
168
    {
169
        $messages = null;
170
        if (isset($this['validation-messages'])) {
171
            
172
            $message = null;
173
            foreach ($this['validation-messages'] as $val) {
174
                $message .= "<li>{$val}</li>\n";
175
            }
176
            $messages = "<ul class='validation-message'>\n{$message}</ul>\n";
177
        }
178
        return $messages;
179
    }
180
181
182
183
    /**
184
     * Get details for a HTML element, prepare for creating HTML code for it.
185
     *
186
     * @return HTML code for the element.
187
     */
188
    public function getHTMLDetails()
189
    {
190
        // Add disabled to be able to disable a form element
191
        // Add maxlength
192
        $id =  $this->GetElementId();
193
194
        $class = isset($this['class'])
195
            ? "{$this['class']}"
196
            : null;
197
198
        $validates = (isset($this['validation-pass']) && $this['validation-pass'] === false)
199
            ? ' validation-failed'
200
            : null;
201
            
202
        $class = (isset($class) || isset($validates))
203
            ? " class='{$class}{$validates}'"
204
            : null;
205
            
206
        $name = " name='{$this['name']}'";
207
208
        $label = isset($this['label'])
209
            ? ($this['label'] . (isset($this['required']) && $this['required']
210
                ? "<span class='form-element-required'>*</span>"
211
                : null))
212
            : null;
213
            
214
        $autofocus = isset($this['autofocus']) && $this['autofocus']
215
            ? " autofocus='autofocus'"
216
            : null;
217
            
218
        $required = isset($this['required']) && $this['required']
219
            ? " required='required'"
220
            : null;
221
            
222
        $readonly = isset($this['readonly']) && $this['readonly']
223
            ? " readonly='readonly'"
224
            : null;
225
            
226
        $placeholder = isset($this['placeholder']) && $this['placeholder']
227
            ? " placeholder='{$this['placeholder']}'"
228
            : null;
229
            
230
        $multiple = isset($this['multiple']) && $this['multiple']
231
            ? " multiple"
232
            : null;
233
            
234
        $max = isset($this['max'])
235
            ? " max='{$this['max']}'"
236
            : null;
237
            
238
        $min = isset($this['min'])
239
            ? " min='{$this['min']}'"
240
            : null;
241
            
242
        $low = isset($this['low'])
243
            ? " low='{$this['low']}'"
244
            : null;
245
            
246
        $high = isset($this['high'])
247
            ? " high='{$this['high']}'"
248
            : null;
249
            
250
        $optimum = isset($this['optimum'])
251
            ? " optimum='{$this['optimum']}'"
252
            : null;
253
            
254
        $step = isset($this['step'])
255
            ? " step='{$this['step']}'"
256
            : null;
257
            
258
        $size = isset($this['size'])
259
            ? " size='{$this['size']}'"
260
            : null;
261
            
262
        $text = isset($this['text'])
263
            ? htmlentities($this['text'], ENT_QUOTES, $this->characterEncoding)
264
            : null;
265
            
266
        $checked = isset($this['checked']) && $this['checked']
267
            ? " checked='checked'"
268
            : null;
269
            
270
        $type = isset($this['type'])
271
            ? " type='{$this['type']}'"
272
            : null;
273
            
274
        $title = isset($this['title'])
275
            ? " title='{$this['title']}'"
276
            : null;
277
            
278
        $pattern = isset($this['pattern'])
279
            ? " pattern='{$this['pattern']}'"
280
            : null;
281
            
282
        $description = isset($this['description'])
283
            ? $this['description']
284
            : null;
285
286
        $novalidate = isset($this['formnovalidate'])
287
            ? " formnovalidate='formnovalidate'"
288
            : null;
289
290
        $onlyValue = isset($this['value'])
291
            ? htmlentities($this['value'], ENT_QUOTES, $this->characterEncoding)
292
            : null;
293
            
294
        $value = isset($this['value'])
295
            ? " value='{$onlyValue}'"
296
            : null;
297
298
        $messages = $this->getValidationMessages();
299
        
300
        return [
301
            'id'            => $id,
302
            'class'         => $class,
303
            'name'          => $name,
304
            'label'         => $label,
305
            'autofocus'     => $autofocus,
306
            'required'      => $required,
307
            'readonly'      => $readonly,
308
            'placeholder'   => $placeholder,
309
            'multiple'      => $multiple,
310
            'min'           => $min,
311
            'max'           => $max,
312
            'low'           => $low,
313
            'high'          => $high,
314
            'step'          => $step,
315
            'optimum'       => $optimum,
316
            'size'          => $size,
317
            'text'          => $text,
318
            'checked'       => $checked,
319
            'type'          => $type,
320
            'title'         => $title,
321
            'pattern'       => $pattern,
322
            'description'   => $description,
323
            'novalidate'    => $novalidate,
324
            'onlyValue'     => $onlyValue,
325
            'value'         => $value,
326
            'messages'      => $messages,
327
        ];
328
    }
329
330
331
332
    /**
333
     * Get HTML code for a element.
334
     *
335
     * @return HTML code for the element.
336
     */
337
    public function getHTML()
338
    {
339
        $details = $this->getHTMLDetails();
340
        extract($details);
341
        
342
        // Create HTML for the element
343
        if (in_array($this['type'], ['submit', 'reset', 'button'])) {
344
 
345
            // type=submit || reset || button
346
            return <<<EOD
347
<span>
348
<input id='$id'{$type}{$class}{$name}{$value}{$autofocus}{$readonly}{$novalidate}{$title} />
349
</span>
350
EOD;
351
 
352
        } elseif ($this['type'] == 'search-widget') {
353
354
            // custom search-widget with type=search and type=submit
355
            $label = isset($this['label']) ? " value='{$this['label']}'" : null;
356
            $classSubmit = isset($this['class-submit']) ? " class='{$this['class-submit']}'" : null;
357
          
358
            return <<<EOD
359
<p>
360
<input id='$id' type='search'{$class}{$name}{$value}{$autofocus}{$required}{$readonly}{$placeholder}/>
361
<input id='do-{$id}' type='submit'{$classSubmit}{$label}{$readonly}{$title}/>
362
</p>
363
<p class='cf-desc'>{$description}</p>
364
EOD;
365
366
        } elseif ($this['type'] == 'textarea') {
367
368
            // textarea
369
            return <<<EOD
370
<p>
371
<label for='$id'>$label</label><br/>
372
<textarea id='$id'{$class}{$name}{$autofocus}{$required}{$readonly}{$placeholder}{$title}>{$onlyValue}</textarea>
373
</p>
374
<p class='cf-desc'>{$description}</p>
375
EOD;
376
377
        } elseif ($this['type'] == 'hidden') {
378
            
379
            // type=hidden
380
            return "<input id='$id'{$type}{$class}{$name}{$value} />\n";
381
        
382
        } elseif ($this['type'] == 'checkbox') {
383
384
            // checkbox
385
            return <<<EOD
386
<p>
387
<input id='$id'{$type}{$class}{$name}{$value}{$autofocus}{$required}{$readonly}{$checked}{$title} />
388
<label for='$id'>$label</label>
389
{$messages}
390
</p>
391
<p class='cf-desc'>{$description}</p>
392
EOD;
393
394
        } elseif ($this['type'] == 'radio') {
395
396
            // radio
397
            $ret = null;
398
            foreach ($this['values'] as $val) {
399
                $id .= $val;
400
                $item = $onlyValue  = htmlentities($val, ENT_QUOTES, $this->characterEncoding);
401
                $value = " value='{$onlyValue}'";
402
                $checked = isset($this['checked']) && $val === $this['checked']
403
                    ? " checked='checked'"
404
                    : null;
405
                $ret .= <<<EOD
406
<p>
407
<input id='$id'{$type}{$class}{$name}{$value}{$autofocus}{$readonly}{$checked}{$title} />
408
<label for='$id'>$item</label>
409
{$messages}
410
</p>
411
EOD;
412
            }
413
            return <<<EOD
414
<div>
415
<p class='cf-label'>{$label}</p>
416
{$ret}
417
<p class='cf-desc'>{$description}</p>
418
</div>
419
EOD;
420
421
        } elseif ($this['type'] == 'file-multiple') {
422
423
            // file-multiple
424
            // @codingStandardsIgnoreStart
425
            return <<<EOD
426
<p>
427
<label for='$id'>$label</label>
428
<br/>
429
<input id='$id' type='file' multiple{$class}{$name}{$value}{$autofocus}{$required}{$readonly}{$placeholder}{$title}{$multiple}{$pattern}{$max}{$min}{$step}/>
430
{$messages}
431
</p>
432
<p class='cf-desc'>{$description}</p>
433
EOD;
434
            // @codingStandardsIgnoreEnd
435
436
        } else {
437
438
            // Everything else
439
            // @codingStandardsIgnoreStart
440
            return <<<EOD
441
<p>
442
<label for='$id'>$label</label>
443
<br/>
444
<input id='$id'{$type}{$class}{$name}{$value}{$autofocus}{$required}{$readonly}{$placeholder}{$title}{$multiple}{$pattern}{$max}{$min}{$step}/>
445
{$messages}
446
</p>
447
<p class='cf-desc'>{$description}</p>
448
EOD;
449
            // @codingStandardsIgnoreEnd
450
451
        }
452
    }
453
454
455
456
    /**
457
     * Validate the form element value according a ruleset.
458
     *
459
     * @param array     $rules validation rules.
460
     * @param Form|null $form  the parent form.
461
     *
462
     * @return boolean true if all rules pass, else false.
463
     */
464
    public function validate($rules, $form = null)
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed.

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

Loading history...
465
    {
466
        $regExpEmailAddress = '/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i';
0 ignored issues
show
Unused Code introduced by
$regExpEmailAddress 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...
467
        $tests = [
468
            'fail' => [
469
                'message' => 'Will always fail.',
470
                'test' => 'return false;'
471
            ],
472
473
            'pass' => [
474
                'message' => 'Will always pass.',
475
                'test' => 'return true;'
476
            ],
477
478
            'not_empty' => [
479
                'message' => 'Can not be empty.',
480
                'test' => 'return $value != "";'
481
            ],
482
483
            'not_equal' => [
484
                'message' => 'Value not valid.',
485
                'test' => 'return $value != $arg;'
486
            ],
487
488
            'numeric' => [
489
                'message' => 'Must be numeric.',
490
                'test' => 'return is_numeric($value);'
491
            ],
492
493
            'email_adress' => [
494
                'message' => 'Must be an email adress.',
495
                'test' => function ($value) {
496
                    return preg_match('/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i', $value) === 1;
497
                }
498
            ],
499
500
            'match' => [
501
                'message' => 'The field does not match.',
502
                'test' => 'return $value == $form[$arg]["value"] ;'
503
            ],
504
              
505
            'must_accept' => [
506
                'message' => 'You must accept this.',
507
                'test' => 'return $checked;'
508
            ],
509
510
            'custom_test' => true,
511
        ];
512
513
        // max tecken, min tecken, datum, tid, datetime, mysql datetime
514
515
        $pass = true;
516
        $messages = array();
517
        $value = $this['value'];
518
        $checked = $this['checked'];
0 ignored issues
show
Unused Code introduced by
$checked 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...
519
520
        foreach ($rules as $key => $val) {
521
522
            $rule = is_numeric($key) ? $val : $key;
523
            if (!isset($tests[$rule])) {
524
                throw new \Exception("Validation of form element failed, no such validation rule exists: $rule");
525
            }
526
            $arg = is_numeric($key) ? null : $val;
527
528
            $test = ($rule == 'custom_test') ? $arg : $tests[$rule];
529
            $status = null;
0 ignored issues
show
Unused Code introduced by
$status 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...
530
            if (is_callable($test['test'])) {
531
                $status = $test['test']($value);
532
            } else {
533
                $status = eval($test['test']);
534
            }
535
536
            if ($status === false) {
537
                $messages[] = $test['message'];
538
                $pass = false;
539
            }
540
        }
541
542
        if (!empty($messages)) {
543
            $this['validation-messages'] = $messages;
544
        }
545
        return $pass;
546
    }
547
548
549
550
    /**
551
     * Use the element name as label if label is not set.
552
     *
553
     * @param string $append a colon as default to the end of the label.
554
     *
555
     * @return void
556
     */
557
    public function useNameAsDefaultLabel($append = ':')
558
    {
559 View Code Duplication
        if (!isset($this['label'])) {
0 ignored issues
show
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...
560
            $this['label'] = ucfirst(strtolower(str_replace(array('-','_'), ' ', $this['name']))).$append;
561
        }
562
    }
563
564
565
566
    /**
567
     * Use the element name as value if value is not set.
568
     *
569
     * @return void
570
     */
571
    public function useNameAsDefaultValue()
572
    {
573 View Code Duplication
        if (!isset($this['value'])) {
0 ignored issues
show
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...
574
            $this['value'] = ucfirst(strtolower(str_replace(array('-','_'), ' ', $this['name'])));
575
        }
576
    }
577
578
579
580
    /**
581
     * Get the value of the form element.
582
     *
583
     * @return mixed the value of the form element.
584
     */
585
    public function getValue()
586
    {
587
        return $this['value'];
588
    }
589
590
591
592
    /**
593
     * Get the value of the form element.
594
     *
595
     * @return mixed the value of the form element.
596
     */
597
    public function value()
598
    {
599
        return $this['value'];
600
    }
601
602
603
604
    /**
605
     * Get the value of the form element, if value is empty return null.
606
     *
607
     * @return mixed the value of the form element. Null if the value is empty.
608
     */
609
    public function getValueNullIfEmpty()
610
    {
611
        return empty($this['value']) ? null : $this['value'];
612
    }
613
}
614