Field   F
last analyzed

Complexity

Total Complexity 79

Size/Duplication

Total Lines 811
Duplicated Lines 0 %

Test Coverage

Coverage 56.12%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 186
dl 0
loc 811
ccs 110
cts 196
cp 0.5612
rs 2.08
c 1
b 0
f 1
wmc 79

50 Methods

Rating   Name   Duplication   Size   Complexity  
A getHintHtml() 0 4 1
A setLabel() 0 4 1
A getPropertiesToSave() 0 5 1
A getForm() 0 7 2
A getClientOptions() 0 9 1
A setComponentName() 0 4 1
A getClassLabel() 0 3 1
A getDataKey() 0 5 2
A setValueFromDb() 0 6 1
A getPlaceholder() 0 3 1
A isForm() 0 3 1
A sanitiseInput() 0 9 2
A getComponentName() 0 5 2
A registerScripts() 0 2 1
A getOptions() 0 3 1
A setClassLabel() 0 4 1
A run() 0 4 1
A fields() 0 3 1
A purifyInput() 0 9 2
A setOptions() 0 11 2
A init() 0 2 1
A getOption() 0 3 2
A getProperties() 0 7 1
A getValue() 0 6 2
A setValue() 0 6 1
A setDataKey() 0 4 1
A getFieldHtml() 0 3 1
A setPlaceholder() 0 4 1
A __construct() 0 28 5
A getClass() 0 3 1
A getLabelHtml() 0 3 2
A getUnsafeValue() 0 3 1
A getLabel() 0 3 1
A setHint() 0 4 1
A getData() 0 3 1
A getErrorHtml() 0 9 3
A preInitCheck() 0 5 2
A getHint() 0 3 1
A processAsFilter() 0 7 2
A ddsSaveDefinition() 0 3 1
A exportDefinition() 0 18 1
A getDdsName() 0 3 1
A getValueDisplay() 0 3 1
A getFilterField() 0 4 1
A getIsInput() 0 3 1
A extractChoices() 0 3 1
A getComponentDetails() 0 8 2
A extractLinkClass() 0 3 1
A reset() 0 5 1
C validate() 0 41 12

How to fix   Complexity   

Complex Class

Complex classes like Field 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.

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 Field, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @link http://www.newicon.net/neon
4
 * @copyright Copyright (c) 2016 Newicon Ltd
5
 * @license http://www.newicon.net/neon/license
6
 */
7
8
namespace neon\core\form\fields;
9
10
11
use InvalidArgumentException;
12
use Neon;
13
use neon\core\form\Deprecated;
14
use neon\core\form\exceptions\InvalidNameFormat;
15
use neon\core\form\Form;
16
use neon\core\form\FormField;
17
use neon\core\form\interfaces\IField;
18
use neon\core\form\Model;
0 ignored issues
show
Bug introduced by
The type neon\core\form\Model was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use neon\core\grid\query\IQuery;
20
use neon\core\helpers\Arr;
21
use neon\core\helpers\Html;
22
use neon\core\traits\PropertiesTrait;
23
use yii\base\NotSupportedException;
24
use yii\base\UnknownPropertyException;
25
26
/**
27
 * Class Field
28
 * @package neon\core\forms
29
 * @property string $name
30
 * @property Model $model
31
 * @property array $options
32
 * @property string $hint
33
 * @property string $label
34
 * @property string $value
35
 * @property Form $form
36
 */
37
class Field extends FormField implements IField
38
{
39
	use PropertiesTrait;
40
41
	/**
42
	 * @var array the default options for the input tags. The parameter passed to individual input methods
43
	 * (e.g. [[textInput()]]) will be merged with this property when rendering the input tag.
44
	 *
45
	 * If you set a custom `id` for the input element, you may need to adjust the [[$selectors]] accordingly.
46
	 *
47
	 * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
48
	 */
49
	public $inputOptions = [];
50
51
	public $readOnly = false;
52
53
	public $printOnly = false;
54
55
	public $mapField = false;
56
57
	public $showIf = [];
58
59
	public $placeholderLabel = false;
60
61
	/**
62
	 * Get the parent form that this item belongs to
63
	 * @return Form
64
	 */
65 36
	public function getForm()
66
	{
67 36
		$form = parent::getForm();
68 36
		if ($form === null) {
69
			throw new InvalidArgumentException('The field must have a form object defined. This happens when the field is added to a form object');
70
		}
71 36
		return $form;
72
	}
73
74
	/**
75
	 * @var array the default options for the error tags. The parameter passed to [[error()]] will be
76
	 * merged with this property when rendering the error tag.
77
	 * The following special options are recognized:
78
	 *
79
	 * - tag: the tag name of the container element. Defaults to "div".
80
	 * - encode: whether to encode the error output. Defaults to true.
81
	 *
82
	 * If you set a custom `id` for the error element, you may need to adjust the [[$selectors]] accordingly.
83
	 *
84
	 * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
85
	 */
86
	public $errorOptions = ['class' => 'help-block', 'tag' => 'span'];
87
	/**
88
	 * @var array the default options for the label tags. The parameter passed to [[label()]] will be
89
	 * merged with this property when rendering the label tag.
90
	 * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
91
	 */
92
	public $labelAttributes = ['class' => 'control-label from-group__label'];
93
	/**
94
	 * @var array the default options for the hint tags. The parameter passed to [[hint()]] will be
95
	 * merged with this property when rendering the hint tag.
96
	 * The following special options are recognized:
97
	 *
98
	 * - tag: the tag name of the container element. Defaults to "div".
99
	 *
100
	 * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
101
	 */
102
	public $hintOptions = ['class' => 'hint-block hint-top'];
103
	/**
104
	 * @var bool whether to enable client-side data validation.
105
	 * If not set, it will take the value of [[ActiveForm::enableClientValidation]].
106
	 */
107
	public $enableClientValidation;
108
	/**
109
	 * @var bool whether to enable AJAX-based data validation.
110
	 * If not set, it will take the value of [[ActiveForm::enableAjaxValidation]].
111
	 */
112
	public $enableAjaxValidation;
113
	/**
114
	 * @var bool whether to enable AJAX-based form submission
115
	 */
116
	public $enableAjaxSubmission;
117
	/**
118
	 * @var bool whether to perform validation when the value of the input field is changed.
119
	 * If not set, it will take the value of [[ActiveForm::validateOnChange]].
120
	 */
121
	public $validateOnChange;
122
	/**
123
	 * @var bool whether to perform validation when the input field loses focus.
124
	 * If not set, it will take the value of [[ActiveForm::validateOnBlur]].
125
	 */
126
	public $validateOnBlur;
127
	/**
128
	 * @var bool whether to perform validation while the user is typing in the input field.
129
	 * If not set, it will take the value of [[ActiveForm::validateOnType]].
130
	 * @see validationDelay
131
	 */
132
	public $validateOnType;
133
	/**
134
	 * @var int number of milliseconds that the validation should be delayed when the user types in the field
135
	 * and [[validateOnType]] is set true.
136
	 * If not set, it will take the value of [[ActiveForm::validationDelay]].
137
	 */
138
	public $validationDelay;
139
	/**
140
	 * @var array the jQuery selectors for selecting the container, input and error tags.
141
	 * The array keys should be "container", "input", and/or "error", and the array values
142
	 * are the corresponding selectors. For example, `['input' => '#my-input']`.
143
	 *
144
	 * The container selector is used under the context of the form, while the input and the error
145
	 * selectors are used under the context of the container.
146
	 *
147
	 * You normally do not need to set this property as the default selectors should work well for most cases.
148
	 */
149
	public $selectors = [];
150
	/**
151
	 * @var array different parts of the field (e.g. input, label). This will be used together with
152
	 * [[template]] to generate the final field HTML code. The keys are the token names in [[template]],
153
	 * while the values are the corresponding HTML code. Valid tokens include `{input}`, `{label}` and `{error}`.
154
	 * Note that you normally don't need to access this property directly as
155
	 * it is maintained by various methods of this class.
156
	 */
157
	public $parts = [];
158
159
	protected $_value = null;
160
	protected $_sanitisedValue = null;
161
	protected $_name;
162
	protected $_hint;
163
	protected $_label = null;
164
	protected $_classLabel;
165
166
	/**
167
	 * By default the form fields will strip tags before setting the fields value
168
	 * you can override this property in child Field classes to allow specific tags
169
	 *
170
	 * @var string|null - default null will remove all tags
171
	 * specify allowed tags for example set this variable to be "<br><a><strong>" to allow all br, a and strong tags
172
	 * ```php
173
	 * protected $allowableTags = "<br><a><strong>"
174
	 * ```
175
	 */
176
	protected $allowableTags = '<br><em><i><u><b><s><mark><strong>';
177
178
	/**
179
	 * @var string the key to use when outputting the fields data
180
	 */
181
	protected $_dataKey;
182
183
	/**
184
	 * Whether this field is required
185
	 * @var bool
186
	 */
187
	protected $_required = false;
188
189
	public $attributes = [];
190
191
	/**
192
	 * Field constructor.
193
	 * @param array|string $name
194
	 * @param array $config
195
	 * @throws InvalidNameFormat
196
	 */
197 114
	public function __construct($name=[], array $config=[])
198
	{
199
		// The $name field can also be a configuration array
200 114
		if (is_array($name)) {
201 40
			$config = $name;
202
		}
203
		// if a name has been specified then add this to the config
204 74
		elseif (is_string($name)) {
0 ignored issues
show
introduced by
The condition is_string($name) is always true.
Loading history...
205 74
			$config['name'] = $name;
206
		}
207
		// -----
208
		// By this point $config should be the required minimum config
209
		// i.e. has a `name` property
210
		// -----
211 114
		if (isset($config['name']))
212 114
			$this->setName($config['name']);
213
214
		// Configure the field - the name property must be set by this point.
215
		// as many configuration options such as adding Validators and attaching
216
		// the file to the form use the name as an index
217 106
		if (!empty($config)) {
218 106
			Neon::configure($this, $config);
219
		}
220
221
		// check the Field has a sensible configuration
222 106
		$this->preInitCheck();
223
224 106
		$this->init();
225 106
	}
226
227
	/**
228
	 * Check the configuration and throw exceptions
229
	 * @throws InvalidArgumentException
230
	 */
231 106
	public function preInitCheck()
232
	{
233
		// check the Field has a sensible configuration
234 106
		if ($this->_name == null) {
235
			throw new InvalidArgumentException('You must set a name property for a form field');
236
		}
237 106
	}
238
239
	/**
240
	 * @inheritdoc
241
	 */
242 100
	public function init()
243 100
	{}
244
245
	/**
246
	 * @inheritdoc
247
	 * @return string
248
	 */
249
	public function run()
250
	{
251
		$this->registerScripts($this->getView());
252
		return Html::tag($this->getComponentName(), '', ['v-bind' => $this->toJson()]);
253
	}
254
255
	/**
256
	 * This function is old - before the form rendering was handled by vue
257
	 * The idea is that is returns just the input field allowing you within a template file
258
	 * to place labels and errors your self.
259
	 * Really you can do this by simply hiding elements in css rather than changing the forms
260
	 * output html.  Therefore this function could apply a class or have an option instructing vue
261
	 * to hide the labels and errors etc.
262
	 */
263
	public function getFieldHtml()
264
	{
265
		return $this->run();
266
	}
267
268
	/**
269
	 * Set the js/html component name
270
	 * defaults to the class name with dashes instead of backslashes
271
	 * @param string $value
272
	 * @return $this
273
	 */
274
	public function setComponentName($value)
275
	{
276
		$this->_componentName = $value;
277
		return $this;
278
	}
279
280
	/**
281
	 * Get the js/html component name for this field
282
	 * @return mixed|null
283
	 */
284
	public function getComponentName()
285
	{
286
		if ($this->_componentName === null)
287
			$this->_componentName = str_replace('\\', '-', get_class($this));
288
		return $this->_componentName;
289
	}
290
291
	/**
292
	 * @var string - component name
293
	 * @see setComponentName
294
	 * @see getComponentName
295
	 */
296
	protected $_componentName = null;
297
298
	/**
299
	 * @inheritdoc
300
	 */
301
	public function registerScripts($view)
302
	{
303
	}
304
305
	/**
306
	 * Used when outputting form data via the getData method. Sets the key in the output array for this fields data
307
	 * If not specified will return the fields name as the key for the data
308
	 * @see \neon\core\form\Form::getData()
309
	 * @return mixed
310
	 */
311 58
	public function getDataKey()
312
	{
313 58
		if ($this->_dataKey === null)
314 58
			return $this->getName();
315 4
		return $this->_dataKey;
316
	}
317
318
	/**
319
	 * Set the data key
320
	 *
321
	 * @param string $key
322
	 *
323
	 * @return $this is a chainable method
324
	 */
325 4
	public function setDataKey($key)
326
	{
327 4
		$this->_dataKey = $key;
328 4
		return $this;
329
	}
330
331
	/**
332
	 * This function represents the formatted data of the fields value
333
	 * the getValue represents the field value in the context of the input control and may have different formatting to
334
	 * the data wished to be returned by the form.
335
	 * Override this function in children Field type classes to change the output
336
	 * This function is called when the parent forms getData function is called
337
	 *
338
	 * @return mixed
339
	 */
340 30
	public function getData()
341
	{
342 30
		return $this->getValue();
343
	}
344
345
	/**
346
	 * @inheritdoc
347
	 */
348 98
	public function getValue()
349
	{
350
		// return sanitised data only
351 98
		if ($this->_sanitisedValue === null)
352 98
			$this->_sanitisedValue = $this->sanitiseInput($this->getUnsafeValue());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getUnsafeValue() targeting neon\core\form\fields\Field::getUnsafeValue() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
353 98
		return $this->_sanitisedValue;
354
	}
355
356
	/**
357
	 * Gets the raw, unsanitised value as posted by the user input
358
	 * @return null
359
	 */
360 98
	protected function getUnsafeValue()
361
	{
362 98
		return $this->_value;
363
	}
364
365
	/**
366
	 * @inheritdoc
367
	 */
368 88
	public function setValue($value)
369
	{
370 88
		$this->_value = $value;
371
		// note that data needs to be sanitised if we are going to use it
372 88
		$this->_sanitisedValue = null;
373 88
		return $this;
374
	}
375
376
	/**
377
	 * @inheritdoc
378
	 */
379 4
	public function setValueFromDb($value)
380
	{
381 4
		$this->setValue($value);
382
		// database data should have already been sanitised
383 4
		$this->_sanitisedValue = $value;
384 4
		return $this;
385
	}
386
387
	/**
388
	 * Sanitise the value
389
	 * @param string $value
390
	 * @return string sanitised
391
	 */
392 98
	protected function sanitiseInput($value)
393
	{
394 98
		if (empty($value))
395 26
			return $value;
396
397 78
		profile_begin('form sanitise');
398 78
		$sanitise = Html::sanitise($value, $this->allowableTags);
399 78
		profile_end('form sanitise');
400 78
		return $sanitise;
401
	}
402
403
	/**
404
	 * Purify the value - it is run through HTMLPurifier and then strip tags
405
	 * @param string $value
406
	 * @return string sanitised
407
	 */
408
	protected function purifyInput($value)
409
	{
410
		if (empty($value))
411
			return $value;
412
413
		profile_begin('form purify');
414
		$sanitise = Html::purify($value, $this->allowableTags);
415
		profile_end('form purify');
416
		return $sanitise;
417
	}
418
419
	/**
420
	 * @inheritdoc
421
	 */
422 12
	public function getHint()
423
	{
424 12
		return $this->_hint;
425
	}
426
427
	/**
428
	 * @inheritdoc
429
	 */
430 4
	public function setHint($hint)
431
	{
432 4
		$this->_hint = $hint;
433 4
		return $this;
434
	}
435
436
	/**
437
	 * Set the placeholder text for the field
438
	 *
439
	 * @param $placeholder
440
	 *
441
	 * @return $this
442
	 */
443 4
	public function setPlaceholder($placeholder)
444
	{
445 4
		$this->_placeholder = $placeholder;
446 4
		return $this;
447
	}
448
449
	protected $_placeholder = '';
450
451
	/**
452
	 * Get the string placeholder
453
	 * @return string
454
	 */
455 12
	public function getPlaceholder()
456
	{
457 12
		return $this->_placeholder;
458
	}
459
460
	/**
461
	 * Get an option from the internal options array
462
	 *
463
	 * @param string $name the option key to look up
464
	 * @param mixed  $default value to return if there is no options with the key of $name
465
	 *
466
	 * @return mixed
467
	 */
468
	public function getOption($name, $default = '')
469
	{
470
		return array_key_exists($name, $this->inputOptions) ? $this->inputOptions[$name] : $default;
471
	}
472
473
	/**
474
	 * @inheritdoc
475
	 */
476 2
	public function isForm()
477
	{
478 2
		return false;
479
	}
480
481
	/**
482
	 * @inheritdoc
483
	 */
484 14
	public function getLabel()
485
	{
486 14
		return $this->_label;
487
	}
488
489
	/**
490
	 * @inheritdoc
491
	 */
492 6
	public function setLabel($label)
493
	{
494 6
		$this->_label = $label;
495 6
		return $this;
496
	}
497
498
	/**
499
	 * @inheritdoc
500
	 */
501 12
	public function getClassLabel()
502
	{
503 12
		return $this->_classLabel;
504
	}
505
506
	/**
507
	 * @inheritdoc
508
	 */
509 4
	public function setClassLabel($label)
510
	{
511 4
		$this->_classLabel = $label;
512 4
		return $this;
513
	}
514
515
	/**
516
	 * Get the html for the field label
517
	 *
518
	 * @return string will return an empty string if no label is specified
519
	 */
520
	public function getLabelHtml()
521
	{
522
		return $this->getLabel() ? Html::activeLabel($this->getForm(), $this->getName(), $this->labelAttributes ) : '';
0 ignored issues
show
Bug introduced by
$this->getForm() of type neon\core\form\Form is incompatible with the type yii\base\Model expected by parameter $model of yii\helpers\BaseHtml::activeLabel(). ( Ignorable by Annotation )

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

522
		return $this->getLabel() ? Html::activeLabel(/** @scrutinizer ignore-type */ $this->getForm(), $this->getName(), $this->labelAttributes ) : '';
Loading history...
523
	}
524
525
	/**
526
	 * Render the hint HTML
527
	 *
528
	 * @return string html
529
	 */
530
	public function getHintHtml()
531
	{
532
		$tag = Arr::remove($this->hintOptions, 'tag', 'div');
533
		return Html::tag($tag, $this->getHint(), $this->hintOptions);
534
	}
535
536
	/**
537
	 * @return string html representing the error
538
	 */
539
	public function getErrorHtml()
540
	{
541
		$error = $this->getFirstError();
542
		if ($error === '')
543
			return '';
544
		$options = $this->errorOptions;
545
		$tag = Arr::remove($options, 'tag', 'div');
546
		$encode = Arr::remove($options, 'encode', true);
547
		return Html::tag($tag, $encode ? Html::encode($error) : $error, $options);
548
	}
549
550
	/**
551
	 * @return array of options for the field, this is usually piped into the html render functions within the Html
552
	 * helper class which typically calle \neon\core\helpers\Html::renderTagAttributes()
553
	 */
554
	public function getOptions()
555
	{
556
		return $this->inputOptions;
557
	}
558
559
	/**
560
	 * set options for the field - will merge by the default options
561
	 *
562
	 * @param array   $options
563
	 * @param bool $replace by default options are merged if you wish to overwrite all options set this to true
564
	 *
565
	 * @return $this - is chainable method
566
	 */
567
	public function setOptions($options, $replace = false)
568
	{
569
		if (!$replace) {
570
			$options = Arr::merge($this->inputOptions, $options);
571
		}
572
		// TODO - consolidate on inputOptions or attributes?
573
		// inputOptions came before, but
574
		// attributes is the terminology used in Form.php
575
		$this->inputOptions = $options;
576
		$this->attributes = $options;
577
		return $this;
578
	}
579
580
	/**
581
	 * Returns the JS options for the field.
582
	 * Ugly Yii function
583
	 *
584
	 * @return array the JS options
585
	 */
586
	public function getClientOptions()
587
	{
588
		$options = [];
589
		// only get the options that are different from the default ones (set in yii.activeForm.js)
590
		return array_diff_assoc($options, [
591
			'validateOnChange' => true,
592
			'validateOnBlur' => true,
593
			'encodeError' => true,
594
			'error' => '.help-block',
595
		]);
596
	}
597
598
	/**
599
	 * @inheritdoc
600
	 */
601 36
	public function validate()
602
	{
603 36
		$validators = $this->getValidators();
604 36
		if (count($validators)==0)
605
			return true;
606
607 36
		$isEmpty = empty($this->getValue());
608 36
		$hasErrors = $this->hasError();
609 36
		$form = $this->getForm();
610 36
		$attribute = $this->getName();
611 36
		$unsafeValue = $this->getUnsafeValue();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $unsafeValue is correct as $this->getUnsafeValue() targeting neon\core\form\fields\Field::getUnsafeValue() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
612
613 36
		foreach ($validators as $validator) {
614
			// see if we can skip this validator
615 36
			if (($validator->skipOnEmpty && $isEmpty) || ($validator->skipOnError && $hasErrors)) {
616 2
				continue;
617
			}
618
619
			// ok - now apply the validator
620
			try {
621 36
				if ($validator->when == null || call_user_func($validator->when, $form, $attribute)) {
622 36
					if (!$validator->validate($unsafeValue, $error)) {
623 36
						$this->addError($error);
624
					}
625
				}
626
			} catch (NotSupportedException $e) {
627
				try {
628
					// in this case we need to try validateAttribute which will set
629
					// the error back on this field via the form addError method
630
					$validator->validateAttribute($form, $attribute);
0 ignored issues
show
Bug introduced by
$form of type neon\core\form\Form is incompatible with the type yii\base\Model expected by parameter $model of yii\validators\Validator::validateAttribute(). ( Ignorable by Annotation )

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

630
					$validator->validateAttribute(/** @scrutinizer ignore-type */ $form, $attribute);
Loading history...
631
				} catch (UnknownPropertyException $e) {
632
					throw new UnknownPropertyException(
633
						'You are using a validator ' . get_class($validator) . ' that has a when clause or needs to use validateAttribute. '
634
						. 'This requires you to have <br><br>'
635
						. 'public function get' . ucfirst($attribute) . "<br>{ <br>&nbsp;&nbsp;return \$this->getField(&quot;$attribute&quot;)->getValue()); <br>}"
636
						. '<br><br>on the form. You may also need the equivalent set' . ucfirst($attribute) . ' method. <br>Error was ' . $e->getMessage());
637
				}
638
			}
639
		}
640
641 36
		return !$this->hasError();
642
	}
643
644
	/**
645
	 * @return array
646
	 * @deprecated use getProperties()
647
	 * @alias getProperties
648
	 */
649
	public function fields()
650
	{
651
		return $this->getProperties();
652
	}
653
654
	/**
655
	 * Return a list of properties that are serializable
656
	 * Each property should be accessible via $object->{propertyName}
657
	 * @return array
658
	 */
659 12
	public function getProperties()
660
	{
661
		return [
662 12
			'class', 'classLabel', 'id', 'name', 'label', 'hint', 'value',
663
			'required', 'dataKey', 'validators', 'placeholder', 'deleted',
664
			'order', 'mapField', 'errors', 'visible', 'inline', 'readOnly',
665
			'attributes', 'printOnly', 'showIf', 'placeholderLabel', 'enableClientValidation'
666
		];
667
	}
668
669
	/**
670
	 * @return array
671
	 */
672
	public function getPropertiesToSave()
673
	{
674
		$props = $this->toArray();
675
		Arr::remove($props, 'id');
676
		return $props;
677
	}
678
679
	/**
680
	 * Get the full class name
681
	 * @return string
682
	 */
683 12
	public function getClass()
684
	{
685 12
		return get_class($this);
686
	}
687
688
	/* ============================================================================================
689
	 * Phoebe and Daedalus specific functions
690
	 * ============================================================================================
691
	 */
692
693
	/**
694
	 * The DDS data type to store the value of the field
695
	 * @var string
696
	 */
697
	public $ddsDataType = 'textshort';
698
699
	/**
700
	 * Get the definition of a field for external storage
701
	 * Override this to remove anything that shouldn't make it
702
	 * as part of the definition
703
	 * @return array [
704
	 *   name - the field name
705
	 *   dataType - the daedalus data type
706
	 *   label - a label for the field
707
	 *   description - a user facing description for the field
708
	 *   choices - the set of associated choice (if any)
709
	 *   linkClass - the type of class linked to (if any)
710
	 *   mapField - whether or not this is a field used in maps
711
	 *   widget - a serialised definition of the widget
712
	 * ]
713
	 */
714 6
	public function exportDefinition()
715
	{
716
		$fieldDefinition = [
717 6
			'memberRef' => $this->getName(),
718 6
			'name' => $this->getName(),
719 6
			'dataType' => $this->ddsDataType,
720 6
			'label' => $this->getLabel(),
721 6
			'description' => $this->getHint(),
722 6
			'choices' => $this->extractChoices(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->extractChoices() targeting neon\core\form\fields\Field::extractChoices() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
723 6
			'linkClass' => $this->extractLinkClass(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->extractLinkClass() targeting neon\core\form\fields\Field::extractLinkClass() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
724 6
			'mapField' => $this->mapField,
725 6
			'deleted' => $this->deleted,
726
			// we must ensure that fields used for form state between requests 
727
			// are not permanently stored in the definition
728 6
			'definition' => $this->toArray(['errors'])
729
		];
730
731 6
		return $fieldDefinition;
732
	}
733
734
	/**
735
	 * extract the choice for a particular field.
736
	 * Override this if you need to provide that functionality
737
	 * @return null|array  an array of [key=>value] pairs
738
	 */
739 6
	protected function extractChoices()
740
	{
741 6
		return null;
742
	}
743
744
	/**
745
	 * extract the link class for a particular field
746
	 * Override this if you need to provide that functionality
747
	 * @return null|string  the link class
748
	 */
749 6
	protected function extractLinkClass()
750
	{
751 6
		return null;
752
	}
753
754
	// TODO: remove the need for this function!
755
	public function getDdsName()
756
	{
757
		return preg_replace('/[^a-z0-9_]/', '', strtolower(preg_replace('/ +/', '_', $this->getName())));
758
	}
759
760
// endregion
761
762
	/**
763
	 * Get a displayable representation of the fields value to be output to html
764
	 * @return string
765
	 */
766
	public function getValueDisplay($context='')
767
	{
768
		return Html::encode($this->getValue());
769
	}
770
771
// region: Filter Field
772
// ============================================================================
773
774
	/**
775
	 * @inheritdoc
776
	 */
777
	public function getFilterField()
778
	{
779
		$field = $this->toArray();
780
		return Arr::except($field, ['name', 'label', 'hint', 'placeholderLabel']);
781
	}
782
783
	/**
784
	 * @inheritdoc
785
	 */
786
	public function processAsFilter(IQuery $query, $searchData=null)
787
	{
788
		$searchData = ($searchData === null) ? $this->getValue() : $searchData;
789
		// Note: we can not use empty here
790
		// empty will return true for '0' meaning filtering for booleans
791
		// false passed over request (particularly for checkboxes) becomes '0'
792
		$query->where($this->getDataKey(), '=', $searchData);
793
	}
794
// endregion
795
796
	/**
797
	 * Whether this field represents a valid input field and will appear in data output
798
	 * Headings and section fields will not be inputs and therefore not clutter up data output
799
	 * @return bool
800
	 */
801 48
	public function getIsInput()
802
	{
803 48
		return !($this->ddsDataType === null);
804
	}
805
806
	/**
807
	 * Reset the form field's value
808
	 * @return $this;
809
	 */
810
	public function reset()
811
	{
812
		$this->_value = null;
813
		$this->_sanitisedValue = null;
814
		return $this;
815
	}
816
817
	/**
818
	 * @inheritdoc
819
	 */
820
	public function getComponentDetails()
821
	{
822
		if (get_class() == get_called_class()) {
823
			return false;
824
		}
825
		return [
826
			'icon' => 'fa fa-cubes',
827
			'order' => 1000
828
		];
829
	}
830
831
832
	/**
833
	 * !!!!!!!!!!!!!!!!!!
834
	 * !!! DEPRECATED !!!
835
	 * !!!!!!!!!!!!!!!!!!
836
	 *
837
	 * Saves the current field object as a member of the DDS class
838
	 * The DDS class can be specified by the $classType param,
839
	 * if not defined it will use the parent form's' name as the classType
840
	 *
841
	 * @param string|null $classType
842
	 * @param array|null $ddsMembers if not specified it will look up the members of the classType
843
	 * @deprecated
844
	 */
845
	public function ddsSaveDefinition($classType=null, $ddsMembers=null)
846
	{
847
		Deprecated::ddsSaveDefinitionField($this, $classType, $ddsMembers);
0 ignored issues
show
Deprecated Code introduced by
The function neon\core\form\Deprecate...dsSaveDefinitionField() has been deprecated. ( Ignorable by Annotation )

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

847
		/** @scrutinizer ignore-deprecated */ Deprecated::ddsSaveDefinitionField($this, $classType, $ddsMembers);
Loading history...
848
	}
849
}
850