Completed
Push — master ( 55ac81...18168a )
by Richard
25s queued 20s
created

Element::themeDecorateElement()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 41
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 6.027

Importance

Changes 0
Metric Value
cc 6
eloc 10
nc 5
nop 0
dl 0
loc 41
rs 9.2222
c 0
b 0
f 0
ccs 10
cts 11
cp 0.9091
crap 6.027

1 Method

Rating   Name   Duplication   Size   Complexity  
A Element::setWithDefaults() 0 8 4
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
13
namespace Xoops\Form;
14
15
use Xoops\Html\Attributes;
16
17
/**
18
 * Element - Abstract base class for form elements
19
 *
20
 * @category  Xoops\Form\Element
21
 * @package   Xoops\Form
22
 * @author    trabis <[email protected]>
23
 * @copyright 2012-2016 XOOPS Project (http://xoops.org)
24
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
25
 * @link      http://xoops.org
26
 */
27
abstract class Element extends Attributes
28
{
29
    /**
30
     * @var string[] list of attributes to NOT render
31
     */
32
    protected $suppressList = ['caption', 'datalist', 'description', 'option'];
33
34
    /**
35
     * Javascript performing additional validation of this element data
36
     *
37
     * This property contains a list of Javascript snippets that will be sent to
38
     * \Xoops\Form\Form::renderValidationJS().
39
     * NB: All elements are added to the output one after the other, so don't forget
40
     * to add a ";" after each to ensure no Javascript syntax error is generated.
41
     *
42
     * @var array ()
43
     */
44
    public $customValidationCode = array();
45
46
    /**
47
     * extra attributes to go in the tag
48
     *
49
     * @var array
50
     */
51
    protected $extra = array();
52
53
    /**
54
     * __construct
55
     *
56
     * @param array $attributes array of attribute name => value pairs
57
     *                           Control attributes:
58
     *                               ElementFactory::FORM_KEY optional form or tray to hold this element
59
     */
60 134
    public function __construct($attributes = array())
61
    {
62 134
        parent::__construct($attributes);
63 134
        if ($this->has(ElementFactory::FORM_KEY)
64 134
            && $this->get(ElementFactory::FORM_KEY) instanceof ContainerInterface) {
65 4
            $this->get(ElementFactory::FORM_KEY)->addElement($this);
66
        }
67 134
    }
68
	
69
	 /**
70
     * defaultRender - Generates default output for the element.
71
     *
72
     * This method is abstract and must be overwritten by the child classes.
73
     *
74
     * @return    string
75
     */
76
    abstract public function defaultRender();
77
78
    /**
79
     * render - Generates output for the element.
80
     *
81
     * @return    string
82
     */
83 57
    public function render(){
84
		$xoops = \Xoops::getInstance();
85 57
		return $xoops->theme()->renderer($this);
86
	}
87
88 57
    /**
89 55
     * render attributes as a string to include in HTML output
90
     *
91
     * @return string
92 57
     */
93 49
    public function renderAttributeString()
94 49
    {
95 1
        $this->suppressRender($this->suppressList);
96
97 49
        // title attribute needs to be generated if not already set
98
        if (!$this->has('title')) {
99 57
            $this->set('title', $this->getTitle());
100
        }
101
        // generate id from name if not already set
102
        if (!$this->has('id')) {
103
            $id = $this->get('name');
104
            if (substr($id, -2) === '[]') {
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type false; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
            if (substr(/** @scrutinizer ignore-type */ $id, -2) === '[]') {
Loading history...
105
                $id = substr($id, 0, strlen($id)-2);
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type false; however, parameter $string of strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

105
                $id = substr($id, 0, strlen(/** @scrutinizer ignore-type */ $id)-2);
Loading history...
106
            }
107
            $this->set('id', $id);
108
        }
109 40
        return parent::renderAttributeString();
110
    }
111 40
112 40
    /**
113 1
     * getValue - Get an array of pre-selected values
114 1
     *
115 1
     * @param boolean $encode True to encode special characters
116
     *
117 1
     * @return mixed
118
     */
119 40
    public function getValue($encode = false)
120
    {
121
        $values = $this->get('value', '');
122
        if (is_array($values)) {
123
            $ret = array();
124
            foreach ($values as $value) {
125
                $ret[] = $encode ? htmlspecialchars($value, ENT_QUOTES) : $value;
126
            }
127
            return $ret;
128
        }
129 18
        return $encode ? htmlspecialchars($values, ENT_QUOTES) : $values;
130
    }
131 18
132 18
    /**
133
     * setValue - Set pre-selected values
134
     *
135
     * @param mixed $value value to assign to this element
136
     *
137
     * @return void
138
     */
139
    public function setValue($value)
140
    {
141 33
        $this->set('value', $value);
142
    }
143 33
144 33
    /**
145
     * setName - set the "name" attribute for the element
146
     *
147
     * @param string $name "name" attribute for the element
148
     *
149
     * @return void
150
     */
151 27
    public function setName($name)
152
    {
153 27
        $this->set('name', $name);
154
    }
155
156
    /**
157
     * getName - get the "name" attribute for the element
158
     *
159
     * @return string
160
     */
161
    public function getName()
162
    {
163 3
        return (string) $this->get('name');
164
    }
165 3
166 3
    /**
167
     * setAccessKey - set the access key attribute for the element
168
     *
169
     * @param string $key "accesskey" attribute for the element
170
     *
171
     * @return void
172
     */
173 2
    public function setAccessKey($key)
174
    {
175 2
        $this->set('accesskey', $key);
176
    }
177
178
    /**
179
     * getAccessKey - get the access key attribute for the element
180
     *
181
     * @return string "accesskey" attribute value
182
     */
183
    public function getAccessKey()
184
    {
185 1
        return (string) $this->get('accesskey');
186
    }
187 1
188 1
    /**
189 1
     * getAccessString - If the access key is found in the specified string, underline it
190 1
     *
191 1
     * @param string $str string to add access key highlight to
192 1
     *
193
     * @return string Enhanced string with the 1st occurrence of "accesskey underlined
194 1
     */
195
    public function getAccessString($str)
196
    {
197
        $access = $this->getAccessKey();
198
        if (!empty($access) && (false !== ($pos = strpos($str, $access)))) {
199
            return htmlspecialchars(substr($str, 0, $pos), ENT_QUOTES)
200
                . '<span style="text-decoration: underline;">'
201
                . htmlspecialchars(substr($str, $pos, 1), ENT_QUOTES) . '</span>'
202
                . htmlspecialchars(substr($str, $pos + 1), ENT_QUOTES);
203
        }
204 4
        return htmlspecialchars($str, ENT_QUOTES);
205
    }
206 4
207 4
    /**
208
     * setClass - set the "class" attribute for the element
209
     *
210
     * @param string $class class attribute for the element
211
     *
212
     * @return void
213
     */
214 3
    public function setClass($class)
215
    {
216 3
        $this->add('class', (string) $class);
217 3
    }
218 1
219
    /**
220 3
     * getClass - get the "class" attribute for the element
221
     *
222
     * @return string "class" attribute value
223
     */
224
    public function getClass()
225
    {
226
        $class = $this->get('class', false);
227
        if ($class === false) {
228
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
229
        }
230
        return htmlspecialchars(implode(' ', $class), ENT_QUOTES);
231 5
    }
232
233 5
    /**
234 5
     * setPattern - set the "pattern" attribute for the element
235 5
     *
236
     * @param string $pattern            pattern attribute for the element
237
     * @param string $patternDescription pattern description
238
     *
239
     * @return void
240
     */
241
    public function setPattern($pattern, $patternDescription = '')
242 1
    {
243
        $this->set('pattern', $pattern);
244 1
        $this->set(':pattern_description', $patternDescription);
245
    }
246
247
    /**
248
     * getPattern - get the "pattern" attribute for the element
249
     *
250
     * @return string "pattern"
251
     */
252 4
    public function getPattern()
253
    {
254 4
        return (string) $this->get('pattern', '');
255
    }
256
257
    /**
258
     * getPatternDescription - get the "pattern_description"
259
     *
260
     * @return string "pattern_description"
261
     */
262
    public function getPatternDescription()
263
    {
264 4
        return (string) $this->get(':pattern_description', '');
265
    }
266 4
267 4
    /**
268
     * setDatalist - set the datalist attribute for the element
269
     *
270
     * @param string[]|string $datalist datalist attribute for the element
271
     *
272
     * @return void
273
     */
274 2
    public function setDatalist($datalist)
275
    {
276 2
        $this->add('datalist', $datalist);
277 2
    }
278
279 2
    /**
280 2
     * renderDatalist - get the datalist attribute for the element
281 2
     *
282
     * @return string "datalist" attribute value
283 2
     */
284 2
    public function renderDatalist()
285
    {
286
        if (!$this->isDatalist()) {
287
            return '';
288
        }
289
        $ret = "\n" . '<datalist id="list_' . $this->getName() . '">' . "\n";
290
        foreach ($this->get('datalist') as $datalist) {
291
            $ret .= '<option value="' . htmlspecialchars($datalist, ENT_QUOTES) . '">' . "\n";
292 12
        }
293
        $ret .= '</datalist>' . "\n";
294 12
        return $ret;
295
    }
296
297
    /**
298
     * isDatalist - is there a datalist for the element?
299
     *
300
     * @return boolean true if element has a non-empty datalist
301
     */
302
    public function isDatalist()
303
    {
304 33
        return $this->has('datalist');
305
    }
306 33
307 33
    /**
308
     * setCaption - set the caption for the element
309
     *
310
     * @param string $caption caption for element
311
     *
312
     * @return void
313
     */
314 14
    public function setCaption($caption)
315
    {
316 14
        $this->set('caption', $caption);
317
    }
318
319
    /**
320
     * getCaption - get the caption for the element
321
     *
322
     * @return string
323
     */
324
    public function getCaption()
325
    {
326
        return $this->get('caption', '');
327 2
        //return htmlspecialchars($this->caption, ENT_QUOTES);
328
    }
329 2
330 2
    /**
331
     * setTitle - set the title for the element
332
     *
333
     * @param string $title title for element
334
     *
335
     * @return void
336
     */
337 56
    public function setTitle($title)
338
    {
339 56
        $this->set('title', $title);
340 1
    }
341
342 56
    /**
343 4
     * getTitle - get the title for the element
344 4
     *
345 4
     * @return string
346
     */
347
    public function getTitle()
348 54
    {
349
        if ($this->has('title')) {
350
            return $this->get('title');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->get('title') could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
351
        } else {
352
            if ($this->has(':pattern_description')) {
353
                return htmlspecialchars(
354
                    strip_tags($this->get('caption') . ' - ' . $this->get(':pattern_description')),
0 ignored issues
show
Bug introduced by
Are you sure $this->get('caption') of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

354
                    strip_tags(/** @scrutinizer ignore-type */ $this->get('caption') . ' - ' . $this->get(':pattern_description')),
Loading history...
Bug introduced by
Are you sure $this->get(':pattern_description') of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

354
                    strip_tags($this->get('caption') . ' - ' . /** @scrutinizer ignore-type */ $this->get(':pattern_description')),
Loading history...
355
                    ENT_QUOTES
356
                );
357
            } else {
358
                return htmlspecialchars(strip_tags($this->get('caption')), ENT_QUOTES);
0 ignored issues
show
Bug introduced by
It seems like $this->get('caption') can also be of type false; however, parameter $str of strip_tags() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

358
                return htmlspecialchars(strip_tags(/** @scrutinizer ignore-type */ $this->get('caption')), ENT_QUOTES);
Loading history...
359
            }
360 2
        }
361
    }
362 2
363 2
    /**
364
     * setDescription - set the element's description
365
     *
366
     * @param string $description description
367
     *
368
     * @return void
369
     */
370
    public function setDescription($description)
371
    {
372 5
        $this->set('description', $description);
373
    }
374 5
375 5
    /**
376
     * getDescription - get the element's description
377
     *
378
     * @param boolean $encode True to encode special characters
379
     *
380
     * @return string
381
     */
382
    public function getDescription($encode = false)
383 17
    {
384
        $description = $this->get('description', '');
385 17
        return $encode ? htmlspecialchars($description, ENT_QUOTES) : $description;
386 17
    }
387
388
    /**
389
     * setHidden - flag the element as "hidden"
390
     *
391
     * @return void
392
     */
393 12
    public function setHidden()
394
    {
395 12
        $this->set('hidden');
396
    }
397
398
    /**
399
     * isHidden - is this a hidden element?
400
     *
401
     * @return boolean true if hidden
402
     */
403
    public function isHidden()
404
    {
405 11
        return $this->has('hidden');
406
    }
407 11
408 11
    /**
409
     * setRequired - set entry required
410 11
     *
411
     * @param boolean $bool true to set required entry for this element
412
     *
413
     * @return void
414
     */
415
    public function setRequired($bool = true)
416
    {
417 15
        if ($bool) {
418
            $this->set('required');
419 15
        }
420
    }
421
422
    /**
423
     * isRequired - is entry required for this element?
424
     *
425
     * @return boolean true if entry is required
426
     */
427
    public function isRequired()
428
    {
429
        return $this->has('required');
430
    }
431
432
    /**
433
     * setExtra - Add extra attributes to the element.
434
     *
435
     * This string will be inserted verbatim and unvalidated in the
436 1
     * element's tag. Know what you are doing!
437
     *
438 1
     * @param string  $extra   extra raw text to insert into form
439 1
     * @param boolean $replace If true, passed string will replace current
440
     *                         content, otherwise it will be appended to it
441 1
     *
442
     * @return string[] New content of the extra string
443 1
     *
444
     * @deprecated please use attributes for event scripting
445
     */
446
    public function setExtra($extra, $replace = false)
447
    {
448
        if ($replace) {
449
            $this->extra = array(trim($extra));
450
        } else {
451
            $this->extra[] = trim($extra);
452
        }
453
        return $this->extra;
454
    }
455 55
456
    /**
457 55
     * getExtra - Get the extra attributes for the element
458 55
     *
459
     * @param boolean $encode True to encode special characters
460 1
     *
461 1
     * @return string
462 1
     *
463
     * @see setExtra() this is going to disappear
464 1
     */
465
    public function getExtra($encode = false)
466
    {
467
        if (!$encode) {
468
            return implode(' ', $this->extra);
469
        }
470
        $value = array();
471
        foreach ($this->extra as $val) {
472
            $value[] = str_replace('>', '&gt;', str_replace('<', '&lt;', $val));
473
        }
474
        return empty($value) ? '' : implode(' ', $value);
475
    }
476
477
    /**
478
     * addCustomValidationCode - Add custom validation javascript
479 1
     *
480
     * This string will be inserted verbatim and unvalidated in the page.
481 1
     * Know what you are doing!
482 1
     *
483
     * @param string  $code    javascript code  to insert into form
484 1
     * @param boolean $replace If true, passed string will replace current code,
485
     *                          otherwise it will be appended to it
486 1
     *
487
     * @return void
488
     */
489
    public function addCustomValidationCode($code, $replace = false)
490
    {
491
        if ($replace) {
492
            $this->customValidationCode = [$code];
493 3
        } else {
494
            $this->customValidationCode[] = $code;
495
        }
496 3
    }
497 1
498
    /**
499
     * renderValidationJS - Render custom javascript validation code
500 3
     *
501
     * @return string|false
502 1
     */
503 1
    public function renderValidationJS()
504 1
    {
505 1
        // render custom validation code if any
506 1
        if (!empty($this->customValidationCode)) {
507 1
            return implode("\n", $this->customValidationCode);
508 1
            // generate validation code if required
509
        } else {
510 1
            if ($this->isRequired() && $eltname = $this->getName()) {
511 1
                // $eltname    = $this->getName();
512
                $eltcaption = $this->getCaption();
513
                $eltmsg = empty($eltcaption)
514 3
                    ? sprintf(\XoopsLocale::F_ENTER, $eltname)
515
                    : sprintf(\XoopsLocale::F_ENTER, $eltcaption);
516
                $eltmsg = str_replace(array(':', '?', '%'), '', $eltmsg);
517
                $eltmsg = str_replace('"', '\"', stripslashes($eltmsg));
518
                $eltmsg = strip_tags($eltmsg);
519
                return "\n"
520
                    . "if ( myform.{$eltname}.value == \"\" ) { window.alert(\"{$eltmsg}\");"
521
                    . " myform.{$eltname}.focus(); return false; }\n";
522
            }
523
        }
524 38
        return false;
525
    }
526 38
527 38
    /**
528 6
     * Test if a class that starts with the pattern string is set
529 6
     *
530 6
     * @param string $pattern 'starts with' to match
531 6
     *
532
     * @return integer|false false if no match, or index of matching class
533
     */
534
    public function hasClassLike($pattern)
535 38
    {
536
        $class = $this->get('class');
537
        if ($class) {
538
            $length = strlen($pattern);
539
            foreach ((array) $class as $i => $value) {
540
                if (0 === strncmp($value, $pattern, $length)) {
541
                    return $i;
542
                }
543
            }
544
        }
545 37
        return false;
546
    }
547 37
548 37
    /**
549 5
     * Convenience method to assist with setting attributes when using BC Element syntax
550 1
     *
551
     * Set attribute $name to $value, replacing $value with $default if $value is empty, or if the
552 5
     * value is not one of the values specified in the (optional) $enum array
553 32
     *
554
     * @param string $name    attribute name
555 32
     * @param mixed  $value   attribute value
556 4
     * @param mixed  $default default value
557
     * @param array  $enum    optional list of valid values
558
     *
559
     * @return void
560
     */
561
    public function setWithDefaults($name, $value, $default = null, $enum = null)
562
    {
563
        if (empty($value)) {
564
            $value = $default;
565
        } elseif (null !== $enum && !in_array($value, $enum)) {
566
            $value = $default;
567
        }
568
        $this->set($name, $value);
569
    }
570
571
    /**
572
     * Convenience method to assist with setting attributes when using BC Element syntax
573
     *
574
     * Set attribute $name to $value, replacing $value with $default if $value is empty, or if the
575
     * value is not one of the values specified in the (optional) $enum array
576
     *
577
     * @param string $name  attribute name
578
     * @param mixed  $value attribute value
579
     *
580
     * @return void
581
     */
582
    public function setIfNotEmpty($name, $value)
583
    {
584
        // don't overwrite
585 37
        if (!$this->has($name) && !empty($value)) {
586 37
            $this->set($name, $value);
587
        }
588
    }
589
590
    /**
591
     * Convenience method to assist with setting attributes
592
     *
593
     * Set attribute $name to $value, replacing $value with $default if $value is empty, or if the
594
     * value is not one of the values specified in the (optional) $enum array
595
     *
596
     * @param string $name  attribute name
597
     * @param mixed  $value attribute value
598
     *
599
     * @return void
600
     */
601 92
    public function setIfNotSet($name, $value)
602
    {
603 92
        // don't overwrite
604 31
        if (!$this->has($name)) {
605 85
            $this->set($name, $value);
606 1
        }
607
    }
608
}
609