Completed
Pull Request — master (#417)
by
unknown
33:00
created

EditableFormField::canView()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 7
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
use SilverStripe\Forms\SegmentField;
4
5
/**
6
 * Represents the base class of a editable form field
7
 * object like {@link EditableTextField}.
8
 *
9
 * @package userforms
10
 *
11
 * @property string Name
12
 *
13
 * @method DataList DisplayRules() List of EditableCustomRule objects
14
 */
15
class EditableFormField extends DataObject {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
16
17
	/**
18
	 * Set to true to hide from class selector
19
	 *
20
	 * @config
21
	 * @var bool
22
	 */
23
	private static $hidden = false;
0 ignored issues
show
Unused Code introduced by
The property $hidden is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
24
25
	/**
26
	 * Define this field as abstract (not inherited)
27
	 *
28
	 * @config
29
	 * @var bool
30
	 */
31
	private static $abstract = true;
0 ignored issues
show
Unused Code introduced by
The property $abstract is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
32
33
	/**
34
	 * Flag this field type as non-data (e.g. literal, header, html)
35
	 *
36
	 * @config
37
	 * @var bool
38
	 */
39
	private static $literal = false;
0 ignored issues
show
Unused Code introduced by
The property $literal is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
40
41
	/**
42
	 * Default sort order
43
	 *
44
	 * @config
45
	 * @var string
46
	 */
47
	private static $default_sort = '"Sort"';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $default_sort is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
48
49
	/**
50
	 * A list of CSS classes that can be added
51
	 *
52
	 * @var array
53
	 */
54
	public static $allowed_css = array();
55
56
	/**
57
	 * @config
58
	 * @var array
59
	 */
60
	private static $summary_fields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $summary_fields is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
61
		'Title'
62
	);
63
64
	/**
65
	 * @config
66
	 * @var array
67
	 */
68
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
69
		"Name" => "Varchar",
70
		"Title" => "Varchar(255)",
71
		"Default" => "Varchar(255)",
72
		"Sort" => "Int",
73
		"Required" => "Boolean",
74
		"CustomErrorMessage" => "Varchar(255)",
75
76
		"CustomRules" => "Text", // @deprecated from 2.0
77
		"CustomSettings" => "Text", // @deprecated from 2.0
78
		"Migrated" => "Boolean", // set to true when migrated
79
80
		"ExtraClass" => "Text", // from CustomSettings
81
		"RightTitle" => "Varchar(255)", // from CustomSettings
82
		"ShowOnLoad" => "Boolean(1)", // from CustomSettings
83
	);
84
85
	/**
86
	 * @config
87
	 * @var array
88
	 */
89
	private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
90
		"Parent" => "UserDefinedForm",
91
	);
92
93
	/**
94
	 * Built in extensions required
95
	 *
96
	 * @config
97
	 * @var array
98
	 */
99
	private static $extensions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $extensions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
100
		"Versioned('Stage', 'Live')"
101
	);
102
103
	/**
104
	 * @config
105
	 * @var array
106
	 */
107
	private static $has_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $has_many is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
108
		"DisplayRules" => "EditableCustomRule.Parent" // from CustomRules
109
	);
110
111
	/**
112
	 * @var bool
113
	 */
114
	protected $readonly;
115
116
	/**
117
	 * Set the visibility of an individual form field
118
	 *
119
	 * @param bool
120
	 */
121
	public function setReadonly($readonly = true) {
122
		$this->readonly = $readonly;
123
	}
124
125
	/**
126
	 * Returns whether this field is readonly
127
	 *
128
	 * @return bool
129
	 */
130
	private function isReadonly() {
131
		return $this->readonly;
132
	}
133
134
	/**
135
	 * @return FieldList
136
	 */
137
	public function getCMSFields() {
138
		$fields = new FieldList(new TabSet('Root'));
139
140
		// Main tab
141
		$fields->addFieldsToTab(
142
			'Root.Main',
143
			array(
144
				ReadonlyField::create(
145
					'Type',
146
					_t('EditableFormField.TYPE', 'Type'),
147
					$this->i18n_singular_name()
148
				),
149
				LiteralField::create(
150
					'MergeField',
151
					_t(
152
						'EditableFormField.MERGEFIELDNAME',
153
						'<div class="field readonly">' .
154
							'<label class="left">Merge field</label>' .
155
							'<div class="middleColumn">' .
156
								'<span class="readonly">$' . $this->Name . '</span>' .
157
							'</div>' .
158
						'</div>'
159
					)
160
				),
161
				TextField::create('Title'),
162
				TextField::create('Default', _t('EditableFormField.DEFAULT', 'Default value')),
163
				TextField::create('RightTitle', _t('EditableFormField.RIGHTTITLE', 'Right title')),
164
				SegmentField::create('Name')->setModifiers(array(
165
					UnderscoreSegmentFieldModifier::create()->setDefault('FieldName'),
166
					DisambiguationSegmentFieldModifier::create(),
167
				))->setPreview($this->Name)
168
			)
169
		);
170
171
		// Custom settings
172
		if (!empty(self::$allowed_css)) {
173
			$cssList = array();
174
			foreach(self::$allowed_css as $k => $v) {
175
				if (!is_array($v)) {
176
					$cssList[$k]=$v;
177
				} elseif ($k === $this->ClassName) {
178
					$cssList = array_merge($cssList, $v);
179
				}
180
			}
181
182
			$fields->addFieldToTab('Root.Main',
183
				DropdownField::create(
184
					'ExtraClass',
185
					_t('EditableFormField.EXTRACLASS_TITLE', 'Extra Styling/Layout'),
186
					$cssList
187
				)->setDescription(_t(
188
					'EditableFormField.EXTRACLASS_SELECT',
189
					'Select from the list of allowed styles'
190
				))
191
			);
192
		} else {
193
			$fields->addFieldToTab('Root.Main',
194
				TextField::create(
195
					'ExtraClass',
196
					_t('EditableFormField.EXTRACLASS_Title', 'Extra CSS classes')
197
				)->setDescription(_t(
198
					'EditableFormField.EXTRACLASS_MULTIPLE',
199
					'Separate each CSS class with a single space'
200
				))
201
			);
202
		}
203
204
		// Validation
205
		$validationFields = $this->getFieldValidationOptions();
206
		if($validationFields) {
207
			$fields->addFieldsToTab(
208
				'Root.Validation',
209
				$this->getFieldValidationOptions()
0 ignored issues
show
Documentation introduced by
$this->getFieldValidationOptions() is of type object<FieldList>, 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...
210
			);
211
		}
212
		$allowedClasses = array_keys($this->getEditableFieldClasses(false));
213
		$self = $this;
214
		$editableColumns = new GridFieldEditableColumns();
215
		$editableColumns->setDisplayFields(array(
216
			'Display' => '',
217
			'ConditionFieldID' => function($record, $column, $grid) use ($allowedClasses, $self) {
0 ignored issues
show
Unused Code introduced by
The parameter $grid 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...
218
				return DropdownField::create(
219
					$column,
220
					'',
221
					EditableFormField::get()
222
						->filter(array(
223
							'ParentID' => $self->ParentID,
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<EditableFormField>. 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...
224
							'ClassName' => $allowedClasses
225
						))
226
						->exclude(array(
227
							'ID' => $self->ID
228
						))
229
						->map('ID', 'Title')
230
					);
231
			},
232
			'ConditionOption' => function($record, $column, $grid) {
0 ignored issues
show
Unused Code introduced by
The parameter $grid 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...
233
				$options = Config::inst()->get('EditableCustomRule', 'condition_options');
234
				return DropdownField::create($column, '', $options);
235
			},
236
			'FieldValue' => function($record, $column, $grid) {
0 ignored issues
show
Unused Code introduced by
The parameter $grid 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...
237
				return TextField::create($column);
238
			},
239
			'ParentID' => function($record, $column, $grid) use ($self) {
0 ignored issues
show
Unused Code introduced by
The parameter $grid 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...
240
				return HiddenField::create($column, '', $self->ID);
241
			}
242
		));
243
244
		// Custom rules
245
		$customRulesConfig = GridFieldConfig::create()
246
			->addComponents(
247
				$editableColumns,
248
				new GridFieldButtonRow(),
249
				new GridFieldToolbarHeader(),
250
				new GridFieldAddNewInlineButton(),
251
				new GridFieldDeleteAction()
252
			);
253
254
		$fields->addFieldsToTab('Root.DisplayRules', array(
255
			CheckboxField::create('ShowOnLoad')
256
				->setDescription(_t(
257
					'EditableFormField.SHOWONLOAD',
258
					'Initial visibility before processing these rules'
259
				)),
260
			GridField::create(
261
				'DisplayRules',
262
				_t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
263
				$this->DisplayRules(),
264
				$customRulesConfig
265
			)
266
		));
267
268
		$this->extend('updateCMSFields', $fields);
269
270
		return $fields;
271
	}
272
273
	/**
274
	 * @return void
275
	 */
276
	public function onBeforeWrite() {
277
		parent::onBeforeWrite();
278
279
		// Set a field name.
280
		if(!$this->Name) {
281
			// New random name
282
			$this->Name = $this->generateName();
283
284
		} elseif($this->Name === 'Field') {
285
			throw new ValidationException('Field name cannot be "Field"');
286
		}
287
288
		if(!$this->Sort && $this->ParentID) {
0 ignored issues
show
Documentation introduced by
The property Sort does not exist on object<EditableFormField>. 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...
Documentation introduced by
The property ParentID does not exist on object<EditableFormField>. 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...
289
			$parentID = $this->ParentID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<EditableFormField>. 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...
290
			$this->Sort = EditableFormField::get()
0 ignored issues
show
Documentation introduced by
The property Sort does not exist on object<EditableFormField>. 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...
291
				->filter('ParentID', $parentID)
292
				->max('Sort') + 1;
293
		}
294
	}
295
296
	/**
297
	 * Generate a new non-conflicting Name value
298
	 *
299
	 * @return string
300
	 */
301
	protected function generateName() {
302
		do {
303
			// Generate a new random name after this class
304
			$class = get_class($this);
305
			$entropy = substr(sha1(uniqid()), 0, 5);
306
			$name = "{$class}_{$entropy}";
307
308
			// Check if it conflicts
309
			$exists = EditableFormField::get()->filter('Name', $name)->count() > 0;
310
		} while($exists);
311
		return $name;
312
	}
313
314
	/**
315
	 * Flag indicating that this field will set its own error message via data-msg='' attributes
316
	 *
317
	 * @return bool
318
	 */
319
	public function getSetsOwnError() {
320
		return false;
321
	}
322
323
	/**
324
	 * Return whether a user can delete this form field
325
	 * based on whether they can edit the page
326
	 *
327
	 * @return bool
328
	 */
329
	public function canDelete($member = null) {
330
		return $this->canEdit($member);
331
	}
332
333
	/**
334
	 * Return whether a user can edit this form field
335
	 * based on whether they can edit the page
336
	 *
337
	 * @return bool
338
	 */
339
	public function canEdit($member = null) {
340
		if($this->Parent()) {
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on EditableFormField. Did you maybe mean parentClass()?

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...
341
			return $this->Parent()->canEdit($member) && !$this->isReadonly();
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on EditableFormField. Did you maybe mean parentClass()?

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...
342
		}
343
344
		return true;
345
	}
346
347
	/**
348
	 * Return whether a user can view this form field
349
	 * based on whether they can view the page, regardless of the ReadOnly status of the field
350
	 *
351
	 * @return bool
352
	 */
353
	public function canView($member = null) {
354
		if($this->Parent()) {
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on EditableFormField. Did you maybe mean parentClass()?

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...
355
			return $this->Parent()->canView($member);
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on EditableFormField. Did you maybe mean parentClass()?

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...
356
		}
357
358
		return true;
359
	}
360
361
	/**
362
	 * Return whether a user can create this form field
363
	 * based on whether they can edit the page
364
	 *
365
	 * @return bool
366
	 */
367
	public function canCreate($member = null, $context = array()) {
368
		$controller = Controller::curr();
369
		$parent = null;
370
371
		// get the parent from context or from the controller stack
372
		if(isset($context['Parent'])) {
373
			$parent = $context['Parent'];
374
		} elseif($controller instanceof LeftAndMain && ($parentID = $controller->currentPageID())) {
375
			$parent = SiteTree::get()->byId($parentID);
376
		}
377
378
		// check if parent is editable
379
		if($parent) {
380
			return $parent->canEdit($member);
381
		}
382
383
		// otherwise
384
		return Permission::checkMember($member, 'SITETREE_EDIT_ALL');
0 ignored issues
show
Bug Compatibility introduced by
The expression \Permission::checkMember..., 'SITETREE_EDIT_ALL'); of type boolean|string|null adds the type string to the return on line 384 which is incompatible with the return type documented by EditableFormField::canCreate of type boolean.
Loading history...
385
	}
386
387
	/**
388
	 * Publish this Form Field to the live site
389
	 *
390
	 * Wrapper for the {@link Versioned} publish function
391
	 */
392
	public function doPublish($fromStage, $toStage, $createNewVersion = false) {
393
		$this->publish($fromStage, $toStage, $createNewVersion);
0 ignored issues
show
Bug introduced by
The method publish() does not exist on EditableFormField. Did you maybe mean doPublish()?

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...
394
395
		// Don't forget to publish the related custom rules...
396
		foreach ($this->DisplayRules() as $rule) {
397
			$rule->doPublish($fromStage, $toStage, $createNewVersion);
398
		}
399
	}
400
401
	/**
402
	 * Delete this field from a given stage
403
	 *
404
	 * Wrapper for the {@link Versioned} deleteFromStage function
405
	 */
406
	public function doDeleteFromStage($stage) {
407
		// Remove custom rules in this stage
408
		$rules = Versioned::get_by_stage('EditableCustomRule', $stage)
409
			->filter('ParentID', $this->ID);
410
		foreach ($rules as $rule) {
411
			$rule->deleteFromStage($stage);
412
		}
413
414
		// Remove record
415
		$this->deleteFromStage($stage);
0 ignored issues
show
Bug introduced by
The method deleteFromStage() does not exist on EditableFormField. Did you maybe mean doDeleteFromStage()?

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...
416
	}
417
418
	/**
419
	 * checks wether record is new, copied from Sitetree
420
	 */
421
	function isNew() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
422
		if(empty($this->ID)) return true;
423
424
		if(is_numeric($this->ID)) return false;
425
426
		return stripos($this->ID, 'new') === 0;
427
	}
428
429
	/**
430
	 * checks if records is changed on stage
431
	 * @return boolean
432
	 */
433
	public function getIsModifiedOnStage() {
434
		// new unsaved fields could be never be published
435
		if($this->isNew()) return false;
436
437
		$stageVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Stage', $this->ID);
438
		$liveVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Live', $this->ID);
439
440
		return ($stageVersion && $stageVersion != $liveVersion);
441
	}
442
443
	/**
444
	 * @deprecated since version 4.0
445
	 */
446
	public function getSettings() {
447
		Deprecation::notice('4.0', 'getSettings is deprecated');
448
		return (!empty($this->CustomSettings)) ? unserialize($this->CustomSettings) : array();
0 ignored issues
show
Documentation introduced by
The property CustomSettings does not exist on object<EditableFormField>. 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...
449
	}
450
451
	/**
452
	 * @deprecated since version 4.0
453
	 */
454
	public function setSettings($settings = array()) {
455
		Deprecation::notice('4.0', 'setSettings is deprecated');
456
		$this->CustomSettings = serialize($settings);
0 ignored issues
show
Documentation introduced by
The property CustomSettings does not exist on object<EditableFormField>. 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...
457
	}
458
459
	/**
460
	 * @deprecated since version 4.0
461
	 */
462
	public function setSetting($key, $value) {
463
		Deprecation::notice('4.0', "setSetting({$key}) is deprecated");
464
		$settings = $this->getSettings();
0 ignored issues
show
Deprecated Code introduced by
The method EditableFormField::getSettings() has been deprecated with message: since version 4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
465
		$settings[$key] = $value;
466
467
		$this->setSettings($settings);
0 ignored issues
show
Deprecated Code introduced by
The method EditableFormField::setSettings() has been deprecated with message: since version 4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
468
	}
469
470
	/**
471
	 * Set the allowed css classes for the extraClass custom setting
472
	 *
473
	 * @param array The permissible CSS classes to add
474
	 */
475
	public function setAllowedCss(array $allowed) {
476
		if (is_array($allowed)) {
477
			foreach ($allowed as $k => $v) {
478
				self::$allowed_css[$k] = (!is_null($v)) ? $v : $k;
479
			}
480
		}
481
	}
482
483
	/**
484
	 * @deprecated since version 4.0
485
	 */
486
	public function getSetting($setting) {
487
		Deprecation::notice("4.0", "getSetting({$setting}) is deprecated");
488
489
		$settings = $this->getSettings();
0 ignored issues
show
Deprecated Code introduced by
The method EditableFormField::getSettings() has been deprecated with message: since version 4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
490
		if(isset($settings) && count($settings) > 0) {
491
			if(isset($settings[$setting])) {
492
				return $settings[$setting];
493
			}
494
		}
495
		return '';
496
	}
497
498
	/**
499
	 * Get the path to the icon for this field type, relative to the site root.
500
	 *
501
	 * @return string
502
	 */
503
	public function getIcon() {
504
		return USERFORMS_DIR . '/images/' . strtolower($this->class) . '.png';
505
	}
506
507
	/**
508
	 * Return whether or not this field has addable options
509
	 * such as a dropdown field or radio set
510
	 *
511
	 * @return bool
512
	 */
513
	public function getHasAddableOptions() {
514
		return false;
515
	}
516
517
	/**
518
	 * Return whether or not this field needs to show the extra
519
	 * options dropdown list
520
	 *
521
	 * @return bool
522
	 */
523
	public function showExtraOptions() {
524
		return true;
525
	}
526
527
	/**
528
	 * Returns the Title for rendering in the front-end (with XML values escaped)
529
	 *
530
	 * @return string
531
	 */
532
	public function getEscapedTitle() {
533
		return Convert::raw2xml($this->Title);
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<EditableFormField>. 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...
534
	}
535
536
	/**
537
	 * Find the numeric indicator (1.1.2) that represents it's nesting value
538
	 *
539
	 * Only useful for fields attached to a current page, and that contain other fields such as pages
540
	 * or groups
541
	 *
542
	 * @return string
543
	 */
544
	public function getFieldNumber() {
545
		// Check if exists
546
		if(!$this->exists()) {
547
			return null;
548
		}
549
		// Check parent
550
		$form = $this->Parent();
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on EditableFormField. Did you maybe mean parentClass()?

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...
551
		if(!$form || !$form->exists() || !($fields = $form->Fields())) {
552
			return null;
553
		}
554
555
		$prior = 0; // Number of prior group at this level
556
		$stack = array(); // Current stack of nested groups, where the top level = the page
557
		foreach($fields->map('ID', 'ClassName') as $id => $className) {
558
			if($className === 'EditableFormStep') {
559
				$priorPage = empty($stack) ? $prior : $stack[0];
560
				$stack = array($priorPage + 1);
561
				$prior = 0;
562
			} elseif($className === 'EditableFieldGroup') {
563
				$stack[] = $prior + 1;
564
				$prior = 0;
565
			} elseif($className === 'EditableFieldGroupEnd') {
566
				$prior = array_pop($stack);
567
			}
568
			if($id == $this->ID) {
569
				return implode('.', $stack);
570
			}
571
		}
572
		return null;
573
	}
574
575
	public function getCMSTitle() {
576
		return $this->i18n_singular_name() . ' (' . $this->Title . ')';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<EditableFormField>. 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...
577
	}
578
579
	/**
580
	 * @deprecated since version 4.0
581
	 */
582
	public function getFieldName($field = false) {
583
		Deprecation::notice('4.0', "getFieldName({$field}) is deprecated");
584
		return ($field) ? "Fields[".$this->ID."][".$field."]" : "Fields[".$this->ID."]";
585
	}
586
587
	/**
588
	 * @deprecated since version 4.0
589
	 */
590
	public function getSettingName($field) {
591
		Deprecation::notice('4.0', "getSettingName({$field}) is deprecated");
592
		$name = $this->getFieldName('CustomSettings');
0 ignored issues
show
Documentation introduced by
'CustomSettings' is of type string, but the function expects a boolean.

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...
Deprecated Code introduced by
The method EditableFormField::getFieldName() has been deprecated with message: since version 4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
593
594
		return $name . '[' . $field .']';
595
	}
596
597
	/**
598
	 * Append custom validation fields to the default 'Validation'
599
	 * section in the editable options view
600
	 *
601
	 * @return FieldList
602
	 */
603
	public function getFieldValidationOptions() {
604
		$fields = new FieldList(
605
			CheckboxField::create('Required', _t('EditableFormField.REQUIRED', 'Is this field Required?'))
606
				->setDescription(_t('EditableFormField.REQUIRED_DESCRIPTION', 'Please note that conditional fields can\'t be required')),
607
			TextField::create('CustomErrorMessage', _t('EditableFormField.CUSTOMERROR','Custom Error Message'))
608
		);
609
610
		$this->extend('updateFieldValidationOptions', $fields);
611
612
		return $fields;
613
	}
614
615
	/**
616
	 * Return a FormField to appear on the front end. Implement on
617
	 * your subclass.
618
	 *
619
	 * @return FormField
620
	 */
621
	public function getFormField() {
622
		user_error("Please implement a getFormField() on your EditableFormClass ". $this->ClassName, E_USER_ERROR);
623
	}
624
625
	/**
626
	 * Updates a formfield with extensions
627
	 *
628
	 * @param FormField $field
629
	 */
630
	public function doUpdateFormField($field) {
631
		$this->extend('beforeUpdateFormField', $field);
632
		$this->updateFormField($field);
633
		$this->extend('afterUpdateFormField', $field);
634
	}
635
636
	/**
637
	 * Updates a formfield with the additional metadata specified by this field
638
	 *
639
	 * @param FormField $field
640
	 */
641
	protected function updateFormField($field) {
642
		// set the error / formatting messages
643
		$field->setCustomValidationMessage($this->getErrorMessage());
644
645
		// set the right title on this field
646
		if($this->RightTitle) {
0 ignored issues
show
Documentation introduced by
The property RightTitle does not exist on object<EditableFormField>. 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...
647
			// Since this field expects raw html, safely escape the user data prior
648
			$field->setRightTitle(Convert::raw2xml($this->RightTitle));
0 ignored issues
show
Documentation introduced by
The property RightTitle does not exist on object<EditableFormField>. 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...
Bug introduced by
It seems like \Convert::raw2xml($this->RightTitle) targeting Convert::raw2xml() can also be of type array; however, FormField::setRightTitle() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
649
		}
650
651
		// if this field is required add some
652
		if($this->Required) {
0 ignored issues
show
Documentation introduced by
The property Required does not exist on object<EditableFormField>. 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...
653
			// Required validation can conflict so add the Required validation messages as input attributes
654
			$errorMessage = $this->getErrorMessage()->HTML();
655
			$field->addExtraClass('requiredField');
656
			$field->setAttribute('data-rule-required', 'true');
657
			$field->setAttribute('data-msg-required', $errorMessage);
0 ignored issues
show
Bug introduced by
It seems like $errorMessage defined by $this->getErrorMessage()->HTML() on line 654 can also be of type array; however, FormField::setAttribute() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
658
659
			if($identifier = UserDefinedForm::config()->required_identifier) {
660
				$title = $field->Title() . " <span class='required-identifier'>". $identifier . "</span>";
661
				$field->setTitle($title);
662
			}
663
		}
664
665
		// if this field has an extra class
666
		if($this->ExtraClass) {
0 ignored issues
show
Documentation introduced by
The property ExtraClass does not exist on object<EditableFormField>. 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...
667
			$field->addExtraClass($this->ExtraClass);
0 ignored issues
show
Documentation introduced by
The property ExtraClass does not exist on object<EditableFormField>. 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...
668
		}
669
	}
670
671
	/**
672
	 * Return the instance of the submission field class
673
	 *
674
	 * @return SubmittedFormField
675
	 */
676
	public function getSubmittedFormField() {
677
		return new SubmittedFormField();
678
	}
679
680
681
	/**
682
	 * Show this form field (and its related value) in the reports and in emails.
683
	 *
684
	 * @return bool
685
	 */
686
	public function showInReports() {
687
		return true;
688
	}
689
690
	/**
691
	 * Return the error message for this field. Either uses the custom
692
	 * one (if provided) or the default SilverStripe message
693
	 *
694
	 * @return Varchar
695
	 */
696
	public function getErrorMessage() {
697
		$title = strip_tags("'". ($this->Title ? $this->Title : $this->Name) . "'");
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<EditableFormField>. 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...
698
		$standard = sprintf(_t('Form.FIELDISREQUIRED', '%s is required').'.', $title);
699
700
		// only use CustomErrorMessage if it has a non empty value
701
		$errorMessage = (!empty($this->CustomErrorMessage)) ? $this->CustomErrorMessage : $standard;
0 ignored issues
show
Documentation introduced by
The property CustomErrorMessage does not exist on object<EditableFormField>. 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...
702
703
		return DBField::create_field('Varchar', $errorMessage);
704
	}
705
706
	/**
707
	 * Validate the field taking into account its custom rules.
708
	 *
709
	 * @param Array $data
710
	 * @param UserForm $form
711
	 *
712
	 * @return boolean
713
	 */
714
	public function validateField($data, $form) {
715
		if($this->Required && $this->DisplayRules()->Count() == 0) {
0 ignored issues
show
Documentation introduced by
The property Required does not exist on object<EditableFormField>. 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...
716
			$formField = $this->getFormField();
717
718
			if(isset($data[$this->Name])) {
719
				$formField->setValue($data[$this->Name]);
720
			}
721
722
			if(
723
				!isset($data[$this->Name]) ||
724
				!$data[$this->Name] ||
725
				!$formField->validate($form->getValidator())
0 ignored issues
show
Bug introduced by
It seems like $form->getValidator() can be null; however, validate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
726
			) {
727
				$form->addErrorMessage($this->Name, $this->getErrorMessage()->HTML(), 'error', false);
0 ignored issues
show
Bug introduced by
It seems like $this->getErrorMessage()->HTML() targeting DBField::HTML() can also be of type array; however, Form::addErrorMessage() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
728
			}
729
		}
730
731
		return true;
732
	}
733
734
	/**
735
	 * Invoked by UserFormUpgradeService to migrate settings specific to this field from CustomSettings
736
	 * to the field proper
737
	 *
738
	 * @param array $data Unserialised data
739
	 */
740
	public function migrateSettings($data) {
741
		// Map 'Show' / 'Hide' to boolean
742
		if(isset($data['ShowOnLoad'])) {
743
			$this->ShowOnLoad = $data['ShowOnLoad'] === '' || ($data['ShowOnLoad'] && $data['ShowOnLoad'] !== 'Hide');
0 ignored issues
show
Documentation introduced by
The property ShowOnLoad does not exist on object<EditableFormField>. 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...
744
			unset($data['ShowOnLoad']);
745
		}
746
747
		// Migrate all other settings
748
		foreach($data as $key => $value) {
749
			if($this->hasField($key)) {
750
				$this->setField($key, $value);
751
			}
752
		}
753
	}
754
755
	/**
756
	 * Get the formfield to use when editing this inline in gridfield
757
	 *
758
	 * @param string $column name of column
759
	 * @param array $fieldClasses List of allowed classnames if this formfield has a selectable class
760
	 * @return FormField
761
	 */
762
	public function getInlineClassnameField($column, $fieldClasses) {
763
		return DropdownField::create($column, false, $fieldClasses);
764
	}
765
766
	/**
767
	 * Get the formfield to use when editing the title inline
768
	 *
769
	 * @param string $column
770
	 * @return FormField
771
	 */
772
	public function getInlineTitleField($column) {
773
		return TextField::create($column, false)
774
			->setAttribute('placeholder', _t('EditableFormField.TITLE', 'Title'))
775
			->setAttribute('data-placeholder', _t('EditableFormField.TITLE', 'Title'));
776
	}
777
778
	/**
779
	 * Get the JS expression for selecting the holder for this field
780
	 *
781
	 * @return string
782
	 */
783
	public function getSelectorHolder() {
784
		return "$(\"#{$this->Name}\")";
785
	}
786
787
	/**
788
	 * Gets the JS expression for selecting the value for this field
789
	 *
790
	 * @param EditableCustomRule $rule Custom rule this selector will be used with
791
	 * @param bool $forOnLoad Set to true if this will be invoked on load
792
	 */
793
	public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false) {
794
		return "$(\"input[name='{$this->Name}']\")";
795
	}
796
797
798
	/**
799
	 * Get the list of classes that can be selected and used as data-values
800
	 *
801
	 * @param $includeLiterals Set to false to exclude non-data fields
802
	 * @return array
803
	 */
804
	public function getEditableFieldClasses($includeLiterals = true) {
805
		$classes = ClassInfo::getValidSubClasses('EditableFormField');
806
807
		// Remove classes we don't want to display in the dropdown.
808
		$editableFieldClasses = array();
809
		foreach ($classes as $class) {
810
			// Skip abstract / hidden classes
811
			if(Config::inst()->get($class, 'abstract', Config::UNINHERITED) || Config::inst()->get($class, 'hidden')
812
			) {
813
				continue;
814
			}
815
816
			if(!$includeLiterals && Config::inst()->get($class, 'literal')) {
817
				continue;
818
			}
819
820
			$singleton = singleton($class);
821
			if(!$singleton->canCreate()) {
822
				continue;
823
			}
824
825
			$editableFieldClasses[$class] = $singleton->i18n_singular_name();
826
		}
827
828
		asort($editableFieldClasses);
829
		return $editableFieldClasses;
830
	}
831
832
	/**
833
	 * @return EditableFormFieldValidator
834
	 */
835
	public function getCMSValidator() {
836
		return EditableFormFieldValidator::create()
837
			->setRecord($this);
838
	}
839
}
840