Completed
Pull Request — master (#518)
by Sam
34:41
created

EditableFormField::getErrorMessage()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 2
nop 0
1
<?php
2
3
use SilverStripe\Forms\SegmentField;
4
use SilverStripe\Forms\TabSet;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, TabSet.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
5
use SilverStripe\Forms\FieldList;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, FieldList.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use SilverStripe\Forms\ReadonlyField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, ReadonlyField.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use SilverStripe\Forms\LiteralField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, LiteralField.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
8
use SilverStripe\Forms\TextField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, TextField.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
9
use SilverStripe\Forms\DropdownField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DropdownField.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
use SilverStripe\Forms\LabelField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, LabelField.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
11
use SilverStripe\Core\Config\Config;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Config.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
12
use SilverStripe\Forms\HiddenField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, HiddenField.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
13
use SilverStripe\Forms\GridField\GridFieldConfig;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, GridFieldConfig.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
14
use SilverStripe\Forms\GridField\GridFieldButtonRow;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, GridFieldButtonRow.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
15
use SilverStripe\Forms\GridField\GridFieldToolbarHeader;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, GridFieldToolbarHeader.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
16
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, GridFieldDeleteAction.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
17
use SilverStripe\Forms\CheckboxField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, CheckboxField.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
18
use SilverStripe\Forms\GridField\GridField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, GridField.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
19
use SilverStripe\ORM\ValidationException;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, ValidationException.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
20
use SilverStripe\Control\Controller;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Controller.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
21
use SilverStripe\CMS\Controllers\CMSPageEditController;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, CMSPageEditController.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
22
use SilverStripe\CMS\Controllers\CMSMain;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, CMSMain.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
23
use SilverStripe\ORM\Versioning\Versioned;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Versioned.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
24
use SilverStripe\Dev\Deprecation;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Deprecation.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
25
use SilverStripe\Core\Convert;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Convert.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
26
use SilverStripe\ORM\FieldType\DBField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DBField.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
27
use SilverStripe\Core\ClassInfo;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, ClassInfo.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
28
use SilverStripe\ORM\ArrayList;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, ArrayList.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
29
use SilverStripe\ORM\DataObject;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DataObject.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
30
31
32
/**
33
 * Represents the base class of a editable form field
34
 * object like {@link EditableTextField}.
35
 *
36
 * @package userforms
37
 *
38
 * @property string $Name
39
 * @property string $Title
40
 * @property string $Default
41
 * @property int $Sort
42
 * @property bool $Required
43
 * @property string $CustomErrorMessage
44
 * @method UserDefinedForm Parent() Parent page
45
 * @method DataList DisplayRules() List of EditableCustomRule objects
46
 */
47
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...
48
{
49
50
    /**
51
     * Set to true to hide from class selector
52
     *
53
     * @config
54
     * @var bool
55
     */
56
    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...
57
58
    /**
59
     * Define this field as abstract (not inherited)
60
     *
61
     * @config
62
     * @var bool
63
     */
64
    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...
65
66
    /**
67
     * Flag this field type as non-data (e.g. literal, header, html)
68
     *
69
     * @config
70
     * @var bool
71
     */
72
    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...
73
74
    /**
75
     * Default sort order
76
     *
77
     * @config
78
     * @var string
79
     */
80
    private static $default_sort = '"Sort"';
0 ignored issues
show
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...
81
82
    /**
83
     * A list of CSS classes that can be added
84
     *
85
     * @var array
86
     */
87
    public static $allowed_css = array();
88
89
    /**
90
     * @config
91
     * @var array
92
     */
93
    private static $summary_fields = array(
0 ignored issues
show
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...
94
        'Title'
95
    );
96
97
    /**
98
     * @config
99
     * @var array
100
     */
101
    private static $db = array(
0 ignored issues
show
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...
102
        "Name" => "Varchar",
103
        "Title" => "Varchar(255)",
104
        "Default" => "Varchar(255)",
105
        "Sort" => "Int",
106
        "Required" => "Boolean",
107
        "CustomErrorMessage" => "Varchar(255)",
108
109
        "CustomRules" => "Text", // @deprecated from 2.0
110
        "CustomSettings" => "Text", // @deprecated from 2.0
111
        "Migrated" => "Boolean", // set to true when migrated
112
113
        "ExtraClass" => "Text", // from CustomSettings
114
        "RightTitle" => "Varchar(255)", // from CustomSettings
115
        "ShowOnLoad" => "Boolean(1)", // from CustomSettings
116
    );
117
118
    private static $defaults = array(
0 ignored issues
show
Unused Code introduced by
The property $defaults 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...
119
        'ShowOnLoad' => true,
120
    );
121
122
123
    /**
124
     * @config
125
     * @var array
126
     */
127
    private static $has_one = array(
0 ignored issues
show
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...
128
        "Parent" => "UserDefinedForm",
129
    );
130
131
    /**
132
     * Built in extensions required
133
     *
134
     * @config
135
     * @var array
136
     */
137
    private static $extensions = array(
0 ignored issues
show
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...
138
        "SilverStripe\\ORM\\Versioning\\Versioned('Stage', 'Live')"
139
    );
140
141
    /**
142
     * @config
143
     * @var array
144
     */
145
    private static $has_many = array(
0 ignored issues
show
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...
146
        "DisplayRules" => "EditableCustomRule.Parent" // from CustomRules
147
    );
148
149
    /**
150
     * @var bool
151
     */
152
    protected $readonly;
153
154
    /**
155
     * Set the visibility of an individual form field
156
     *
157
     * @param bool
158
     */
159
    public function setReadonly($readonly = true)
160
    {
161
        $this->readonly = $readonly;
162
    }
163
164
    /**
165
     * Returns whether this field is readonly
166
     *
167
     * @return bool
168
     */
169
    private function isReadonly()
170
    {
171
        return $this->readonly;
172
    }
173
174
    /**
175
     * @return FieldList
176
     */
177
    public function getCMSFields()
178
    {
179
        $fields = new FieldList(new TabSet('Root'));
180
181
        // Main tab
182
        $fields->addFieldsToTab(
183
            'Root.Main',
184
            array(
185
                ReadonlyField::create(
186
                    'Type',
187
                    _t('EditableFormField.TYPE', 'Type'),
188
                    $this->i18n_singular_name()
189
                ),
190
                LiteralField::create(
191
                    'MergeField',
192
                    _t(
193
                        'EditableFormField.MERGEFIELDNAME',
194
                        '<div class="field readonly">' .
195
                            '<label class="left">Merge field</label>' .
196
                            '<div class="middleColumn">' .
197
                                '<span class="readonly">$' . $this->Name . '</span>' .
198
                            '</div>' .
199
                        '</div>'
200
                    )
201
                ),
202
                TextField::create('Title'),
203
                TextField::create('Default', _t('EditableFormField.DEFAULT', 'Default value')),
204
                TextField::create('RightTitle', _t('EditableFormField.RIGHTTITLE', 'Right title')),
205
                SegmentField::create('Name')->setModifiers(array(
206
                    UnderscoreSegmentFieldModifier::create()->setDefault('FieldName'),
207
                    DisambiguationSegmentFieldModifier::create(),
208
                ))->setPreview($this->Name)
209
            )
210
        );
211
212
        // Custom settings
213
        if (!empty(self::$allowed_css)) {
214
            $cssList = array();
215
            foreach (self::$allowed_css as $k => $v) {
216
                if (!is_array($v)) {
217
                    $cssList[$k]=$v;
218
                } elseif ($k === $this->ClassName) {
219
                    $cssList = array_merge($cssList, $v);
220
                }
221
            }
222
223
            $fields->addFieldToTab('Root.Main',
224
                DropdownField::create(
225
                    'ExtraClass',
226
                    _t('EditableFormField.EXTRACLASS_TITLE', 'Extra Styling/Layout'),
227
                    $cssList
228
                )->setDescription(_t(
229
                    'EditableFormField.EXTRACLASS_SELECT',
230
                    'Select from the list of allowed styles'
231
                ))
232
            );
233
        } else {
234
            $fields->addFieldToTab('Root.Main',
235
                TextField::create(
236
                    'ExtraClass',
237
                    _t('EditableFormField.EXTRACLASS_Title', 'Extra CSS classes')
238
                )->setDescription(_t(
239
                    'EditableFormField.EXTRACLASS_MULTIPLE',
240
                    'Separate each CSS class with a single space'
241
                ))
242
            );
243
        }
244
245
        // Validation
246
        $validationFields = $this->getFieldValidationOptions();
247
        if ($validationFields && $validationFields->count()) {
248
            $fields->addFieldsToTab('Root.Validation', $validationFields);
249
        }
250
251
        // Add display rule fields
252
        $displayFields = $this->getDisplayRuleFields();
253
        if ($displayFields && $displayFields->count()) {
254
            $fields->addFieldsToTab('Root.DisplayRules', $displayFields);
255
        }
256
257
        $this->extend('updateCMSFields', $fields);
258
259
        return $fields;
260
    }
261
262
    /**
263
     * Return fields to display on the 'Display Rules' tab
264
     *
265
     * @return FieldList
266
     */
267
    protected function getDisplayRuleFields()
268
    {
269
        // Check display rules
270
        if ($this->Required) {
271
            return new FieldList(
272
                LabelField::create(_t(
273
                    'EditableFormField.DISPLAY_RULES_DISABLED',
274
                    'Display rules are not enabled for required fields. ' .
275
                    'Please uncheck "Is this field Required?" under "Validation" to re-enable.'
276
                ))->addExtraClass('message warning')
277
            );
278
        }
279
        $self = $this;
280
        $allowedClasses = array_keys($this->getEditableFieldClasses(false));
281
        $editableColumns = new GridFieldEditableColumns();
282
        $editableColumns->setDisplayFields(array(
283
            'Display' => '',
284
            '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...
285
                return DropdownField::create(
286
                    $column,
287
                    '',
288
                    EditableFormField::get()
289
                        ->filter(array(
290
                            'ParentID' => $self->ParentID,
291
                            'ClassName' => $allowedClasses
292
                        ))
293
                        ->exclude(array(
294
                            'ID' => $self->ID
295
                        ))
296
                        ->map('ID', 'Title')
297
                    );
298
            },
299
            '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...
300
                $options = Config::inst()->get('EditableCustomRule', 'condition_options');
301
                return DropdownField::create($column, '', $options);
302
            },
303
            '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...
304
                return TextField::create($column);
305
            },
306
            '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...
307
                return HiddenField::create($column, '', $self->ID);
308
            }
309
        ));
310
311
        // Custom rules
312
        $customRulesConfig = GridFieldConfig::create()
313
            ->addComponents(
314
                $editableColumns,
315
                new GridFieldButtonRow(),
316
                new GridFieldToolbarHeader(),
317
                new GridFieldAddNewInlineButton(),
318
                new GridFieldDeleteAction()
319
            );
320
321
        return new FieldList(
322
            CheckboxField::create('ShowOnLoad')
323
                ->setDescription(_t(
324
                    'EditableFormField.SHOWONLOAD',
325
                    'Initial visibility before processing these rules'
326
                )),
327
            GridField::create(
328
                'DisplayRules',
329
                _t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
330
                $this->DisplayRules(),
331
                $customRulesConfig
332
            )
333
        );
334
    }
335
336
    public function onBeforeWrite()
337
    {
338
        parent::onBeforeWrite();
339
340
        // Set a field name.
341
        if (!$this->Name) {
342
            // New random name
343
            $this->Name = $this->generateName();
344
        } elseif ($this->Name === 'Field') {
345
            throw new ValidationException('Field name cannot be "Field"');
346
        }
347
348
        if (!$this->Sort && $this->ParentID) {
349
            $parentID = $this->ParentID;
350
            $this->Sort = EditableFormField::get()
351
                ->filter('ParentID', $parentID)
352
                ->max('Sort') + 1;
353
        }
354
    }
355
356
    /**
357
     * Generate a new non-conflicting Name value
358
     *
359
     * @return string
360
     */
361
    protected function generateName()
362
    {
363
        do {
364
            // Generate a new random name after this class
365
            $class = get_class($this);
366
            $entropy = substr(sha1(uniqid()), 0, 5);
367
            $name = "{$class}_{$entropy}";
368
369
            // Check if it conflicts
370
            $exists = EditableFormField::get()->filter('Name', $name)->count() > 0;
371
        } while ($exists);
372
        return $name;
373
    }
374
375
    /**
376
     * Flag indicating that this field will set its own error message via data-msg='' attributes
377
     *
378
     * @return bool
379
     */
380
    public function getSetsOwnError()
381
    {
382
        return false;
383
    }
384
385
    /**
386
     * Return whether a user can delete this form field
387
     * based on whether they can edit the page
388
     *
389
     * @param Member $member
390
     * @return bool
391
     */
392
    public function canDelete($member = null)
393
    {
394
        return $this->canEdit($member);
395
    }
396
397
    /**
398
     * Return whether a user can edit this form field
399
     * based on whether they can edit the page
400
     *
401
     * @param Member $member
402
     * @return bool
403
     */
404
    public function canEdit($member = null)
405
    {
406
        $parent = $this->Parent();
407
        if ($parent && $parent->exists()) {
408
            return $parent->canEdit($member) && !$this->isReadonly();
409
        } elseif (!$this->exists() && Controller::has_curr()) {
410
            // This is for GridFieldOrderableRows support as it checks edit permissions on
411
            // singleton of the class. Allows editing of User Defined Form pages by
412
            // 'Content Authors' and those with permission to edit the UDF page. (ie. CanEditType/EditorGroups)
413
            // This is to restore User Forms 2.x backwards compatibility.
414
            $controller = Controller::curr();
415
            if ($controller && $controller instanceof CMSPageEditController) {
0 ignored issues
show
Bug introduced by
The class SilverStripe\CMS\Controllers\CMSPageEditController does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

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

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

2. Missing use statement

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

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

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

Loading history...
416
                $parent = $controller->getRecord($controller->currentPageID());
417
                // Only allow this behaviour on pages using UserFormFieldEditorExtension, such
418
                // as UserDefinedForm page type.
419
                if ($parent && $parent->hasExtension('UserFormFieldEditorExtension')) {
420
                    return $parent->canEdit($member);
421
                }
422
            }
423
        }
424
425
        // Fallback to secure admin permissions
426
        return parent::canEdit($member);
427
    }
428
429
    /**
430
     * Return whether a user can view this form field
431
     * based on whether they can view the page, regardless of the ReadOnly status of the field
432
     *
433
     * @param Member $member
434
     * @return bool
435
     */
436
    public function canView($member = null)
437
    {
438
        $parent = $this->Parent();
439
        if ($parent && $parent->exists()) {
440
            return $parent->canView($member);
441
        }
442
443
        return true;
444
    }
445
446
    /**
447
     * Return whether a user can create an object of this type
448
     *
449
     * @param Member $member
450
     * @param array $context Virtual parameter to allow context to be passed in to check
451
     * @return bool
452
     */
453 View Code Duplication
    public function canCreate($member = null, $context = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
454
    {
455
        // Check parent page
456
        $parent = $this->getCanCreateContext($context);
457
        if ($parent) {
458
            return $parent->canEdit($member);
459
        }
460
461
        // Fall back to secure admin permissions
462
        return parent::canCreate($member);
463
    }
464
465
    /**
466
     * Helper method to check the parent for this object
467
     *
468
     * @param array $args List of arguments passed to canCreate
0 ignored issues
show
Bug introduced by
There is no parameter named $args. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
469
     * @return SiteTree Parent page instance
470
     */
471 View Code Duplication
    protected function getCanCreateContext($context)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
472
    {
473
        // Inspect second parameter to canCreate for a 'Parent' context
474
        if (isset($context['Parent'])) {
475
            return $context['Parent'];
476
        }
477
        // Hack in currently edited page if context is missing
478
        if (Controller::has_curr() && Controller::curr() instanceof CMSMain) {
0 ignored issues
show
Bug introduced by
The class SilverStripe\CMS\Controllers\CMSMain does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

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

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

2. Missing use statement

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

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

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

Loading history...
479
            return Controller::curr()->currentPage();
480
        }
481
482
        // No page being edited
483
        return null;
484
    }
485
486
    /**
487
     * Check if can publish
488
     *
489
     * @param Member $member
490
     * @return bool
491
     */
492
    public function canPublish($member = null)
493
    {
494
        return $this->canEdit($member);
495
    }
496
497
    /**
498
     * Check if can unpublish
499
     *
500
     * @param Member $member
501
     * @return bool
502
     */
503
    public function canUnpublish($member = null)
504
    {
505
        return $this->canDelete($member);
506
    }
507
508
    /**
509
     * Publish this Form Field to the live site
510
     *
511
     * Wrapper for the {@link Versioned} publish function
512
     */
513
    public function doPublish($fromStage, $toStage, $createNewVersion = false)
514
    {
515
        $this->publish($fromStage, $toStage, $createNewVersion);
516
517
        // Don't forget to publish the related custom rules...
518
        foreach ($this->DisplayRules() as $rule) {
519
            $rule->doPublish($fromStage, $toStage, $createNewVersion);
520
        }
521
    }
522
523
    /**
524
     * Delete this field from a given stage
525
     *
526
     * Wrapper for the {@link Versioned} deleteFromStage function
527
     */
528
    public function doDeleteFromStage($stage)
529
    {
530
        // Remove custom rules in this stage
531
        $rules = Versioned::get_by_stage('EditableCustomRule', $stage)
532
            ->filter('ParentID', $this->ID);
533
        foreach ($rules as $rule) {
534
            $rule->deleteFromStage($stage);
535
        }
536
537
        // Remove record
538
        $this->deleteFromStage($stage);
539
    }
540
541
    /**
542
     * checks wether record is new, copied from Sitetree
543
     */
544
    public function isNew()
545
    {
546
        if (empty($this->ID)) {
547
            return true;
548
        }
549
550
        if (is_numeric($this->ID)) {
551
            return false;
552
        }
553
554
        return stripos($this->ID, 'new') === 0;
555
    }
556
557
    /**
558
     * checks if records is changed on stage
559
     * @return boolean
560
     */
561
    public function getIsModifiedOnStage()
562
    {
563
        // new unsaved fields could be never be published
564
        if ($this->isNew()) {
565
            return false;
566
        }
567
568
        $stageVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Stage', $this->ID);
569
        $liveVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Live', $this->ID);
570
571
        return ($stageVersion && $stageVersion != $liveVersion);
572
    }
573
574
    /**
575
     * @deprecated since version 4.0
576
     */
577
    public function getSettings()
578
    {
579
        Deprecation::notice('4.0', 'getSettings is deprecated');
580
        return (!empty($this->CustomSettings)) ? unserialize($this->CustomSettings) : array();
581
    }
582
583
    /**
584
     * @deprecated since version 4.0
585
     */
586
    public function setSettings($settings = array())
587
    {
588
        Deprecation::notice('4.0', 'setSettings is deprecated');
589
        $this->CustomSettings = serialize($settings);
590
    }
591
592
    /**
593
     * @deprecated since version 4.0
594
     */
595
    public function setSetting($key, $value)
596
    {
597
        Deprecation::notice('4.0', "setSetting({$key}) is deprecated");
598
        $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...
599
        $settings[$key] = $value;
600
601
        $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...
602
    }
603
604
    /**
605
     * Set the allowed css classes for the extraClass custom setting
606
     *
607
     * @param array The permissible CSS classes to add
608
     */
609
    public function setAllowedCss(array $allowed)
610
    {
611
        if (is_array($allowed)) {
612
            foreach ($allowed as $k => $v) {
613
                self::$allowed_css[$k] = (!is_null($v)) ? $v : $k;
614
            }
615
        }
616
    }
617
618
    /**
619
     * @deprecated since version 4.0
620
     */
621
    public function getSetting($setting)
622
    {
623
        Deprecation::notice("4.0", "getSetting({$setting}) is deprecated");
624
625
        $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...
626
        if (isset($settings) && count($settings) > 0) {
627
            if (isset($settings[$setting])) {
628
                return $settings[$setting];
629
            }
630
        }
631
        return '';
632
    }
633
634
    /**
635
     * Get the path to the icon for this field type, relative to the site root.
636
     *
637
     * @return string
638
     */
639
    public function getIcon()
640
    {
641
        return USERFORMS_DIR . '/images/' . strtolower($this->class) . '.png';
642
    }
643
644
    /**
645
     * Return whether or not this field has addable options
646
     * such as a dropdown field or radio set
647
     *
648
     * @return bool
649
     */
650
    public function getHasAddableOptions()
651
    {
652
        return false;
653
    }
654
655
    /**
656
     * Return whether or not this field needs to show the extra
657
     * options dropdown list
658
     *
659
     * @return bool
660
     */
661
    public function showExtraOptions()
662
    {
663
        return true;
664
    }
665
666
    /**
667
     * Returns the Title for rendering in the front-end (with XML values escaped)
668
     *
669
     * @return string
670
     */
671
    public function getEscapedTitle()
672
    {
673
        return Convert::raw2xml($this->Title);
674
    }
675
676
    /**
677
     * Find the numeric indicator (1.1.2) that represents it's nesting value
678
     *
679
     * Only useful for fields attached to a current page, and that contain other fields such as pages
680
     * or groups
681
     *
682
     * @return string
683
     */
684
    public function getFieldNumber()
685
    {
686
        // Check if exists
687
        if (!$this->exists()) {
688
            return null;
689
        }
690
        // Check parent
691
        $form = $this->Parent();
692
        if (!$form || !$form->exists() || !($fields = $form->Fields())) {
693
            return null;
694
        }
695
696
        $prior = 0; // Number of prior group at this level
697
        $stack = array(); // Current stack of nested groups, where the top level = the page
698
        foreach ($fields->map('ID', 'ClassName') as $id => $className) {
699
            if ($className === 'EditableFormStep') {
700
                $priorPage = empty($stack) ? $prior : $stack[0];
701
                $stack = array($priorPage + 1);
702
                $prior = 0;
703
            } elseif ($className === 'EditableFieldGroup') {
704
                $stack[] = $prior + 1;
705
                $prior = 0;
706
            } elseif ($className === 'EditableFieldGroupEnd') {
707
                $prior = array_pop($stack);
708
            }
709
            if ($id == $this->ID) {
710
                return implode('.', $stack);
711
            }
712
        }
713
        return null;
714
    }
715
716
    public function getCMSTitle()
717
    {
718
        return $this->i18n_singular_name() . ' (' . $this->Title . ')';
719
    }
720
721
    /**
722
     * @deprecated since version 4.0
723
     */
724
    public function getFieldName($field = false)
725
    {
726
        Deprecation::notice('4.0', "getFieldName({$field}) is deprecated");
727
        return ($field) ? "Fields[".$this->ID."][".$field."]" : "Fields[".$this->ID."]";
728
    }
729
730
    /**
731
     * @deprecated since version 4.0
732
     */
733
    public function getSettingName($field)
734
    {
735
        Deprecation::notice('4.0', "getSettingName({$field}) is deprecated");
736
        $name = $this->getFieldName('CustomSettings');
0 ignored issues
show
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...
737
738
        return $name . '[' . $field .']';
739
    }
740
741
    /**
742
     * Append custom validation fields to the default 'Validation'
743
     * section in the editable options view
744
     *
745
     * @return FieldList
746
     */
747
    public function getFieldValidationOptions()
748
    {
749
        $fields = new FieldList(
750
            CheckboxField::create('Required', _t('EditableFormField.REQUIRED', 'Is this field Required?'))
751
                ->setDescription(_t('EditableFormField.REQUIRED_DESCRIPTION', 'Please note that conditional fields can\'t be required')),
752
            TextField::create('CustomErrorMessage', _t('EditableFormField.CUSTOMERROR', 'Custom Error Message'))
753
        );
754
755
        $this->extend('updateFieldValidationOptions', $fields);
756
757
        return $fields;
758
    }
759
760
    /**
761
     * Return a FormField to appear on the front end. Implement on
762
     * your subclass.
763
     *
764
     * @return FormField
765
     */
766
    public function getFormField()
767
    {
768
        user_error("Please implement a getFormField() on your EditableFormClass ". $this->ClassName, E_USER_ERROR);
769
    }
770
771
    /**
772
     * Updates a formfield with extensions
773
     *
774
     * @param FormField $field
775
     */
776
    public function doUpdateFormField($field)
777
    {
778
        $this->extend('beforeUpdateFormField', $field);
779
        $this->updateFormField($field);
780
        $this->extend('afterUpdateFormField', $field);
781
    }
782
783
    /**
784
     * Updates a formfield with the additional metadata specified by this field
785
     *
786
     * @param FormField $field
787
     */
788
    protected function updateFormField($field)
789
    {
790
        // set the error / formatting messages
791
        $field->setCustomValidationMessage($this->getErrorMessage()->RAW());
792
793
        // set the right title on this field
794
        if ($this->RightTitle) {
795
            // Since this field expects raw html, safely escape the user data prior
796
            $field->setRightTitle(Convert::raw2xml($this->RightTitle));
797
        }
798
799
        // if this field is required add some
800
        if ($this->Required) {
801
            // Required validation can conflict so add the Required validation messages as input attributes
802
            $errorMessage = $this->getErrorMessage()->HTML();
803
            $field->addExtraClass('requiredField');
804
            $field->setAttribute('data-rule-required', 'true');
805
            $field->setAttribute('data-msg-required', $errorMessage);
0 ignored issues
show
Bug introduced by
It seems like $errorMessage defined by $this->getErrorMessage()->HTML() on line 802 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...
806
807
            if ($identifier = UserDefinedForm::config()->required_identifier) {
808
                $title = $field->Title() . " <span class='required-identifier'>". $identifier . "</span>";
809
                $field->setTitle($title);
810
            }
811
        }
812
813
        // if this field has an extra class
814
        if ($this->ExtraClass) {
815
            $field->addExtraClass($this->ExtraClass);
816
        }
817
    }
818
819
    /**
820
     * Return the instance of the submission field class
821
     *
822
     * @return SubmittedFormField
823
     */
824
    public function getSubmittedFormField()
825
    {
826
        return new SubmittedFormField();
827
    }
828
829
830
    /**
831
     * Show this form field (and its related value) in the reports and in emails.
832
     *
833
     * @return bool
834
     */
835
    public function showInReports()
836
    {
837
        return true;
838
    }
839
840
    /**
841
     * Return the error message for this field. Either uses the custom
842
     * one (if provided) or the default SilverStripe message
843
     *
844
     * @return Varchar
845
     */
846
    public function getErrorMessage()
847
    {
848
        $title = strip_tags("'". ($this->Title ? $this->Title : $this->Name) . "'");
849
        $standard = sprintf(_t('Form.FIELDISREQUIRED', '%s is required').'.', $title);
850
851
        // only use CustomErrorMessage if it has a non empty value
852
        $errorMessage = (!empty($this->CustomErrorMessage)) ? $this->CustomErrorMessage : $standard;
853
854
        return DBField::create_field('Varchar', $errorMessage);
855
    }
856
857
    /**
858
     * Invoked by UserFormUpgradeService to migrate settings specific to this field from CustomSettings
859
     * to the field proper
860
     *
861
     * @param array $data Unserialised data
862
     */
863
    public function migrateSettings($data)
864
    {
865
        // Map 'Show' / 'Hide' to boolean
866
        if (isset($data['ShowOnLoad'])) {
867
            $this->ShowOnLoad = $data['ShowOnLoad'] === '' || ($data['ShowOnLoad'] && $data['ShowOnLoad'] !== 'Hide');
868
            unset($data['ShowOnLoad']);
869
        }
870
871
        // Migrate all other settings
872
        foreach ($data as $key => $value) {
873
            if ($this->hasField($key)) {
874
                $this->setField($key, $value);
875
            }
876
        }
877
    }
878
879
    /**
880
     * Get the formfield to use when editing this inline in gridfield
881
     *
882
     * @param string $column name of column
883
     * @param array $fieldClasses List of allowed classnames if this formfield has a selectable class
884
     * @return FormField
885
     */
886
    public function getInlineClassnameField($column, $fieldClasses)
887
    {
888
        return DropdownField::create($column, false, $fieldClasses);
889
    }
890
891
    /**
892
     * Get the formfield to use when editing the title inline
893
     *
894
     * @param string $column
895
     * @return FormField
896
     */
897
    public function getInlineTitleField($column)
898
    {
899
        return TextField::create($column, false)
900
            ->setAttribute('placeholder', _t('EditableFormField.TITLE', 'Title'))
901
            ->setAttribute('data-placeholder', _t('EditableFormField.TITLE', 'Title'));
902
    }
903
904
    /**
905
     * Get the JS expression for selecting the holder for this field
906
     *
907
     * @return string
908
     */
909
    public function getSelectorHolder()
910
    {
911
        return "$(\"#{$this->Name}\")";
912
    }
913
914
    /**
915
     * Gets the JS expression for selecting the value for this field
916
     *
917
     * @param EditableCustomRule $rule Custom rule this selector will be used with
918
     * @param bool $forOnLoad Set to true if this will be invoked on load
919
     */
920
    public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false)
921
    {
922
        return "$(\"input[name='{$this->Name}']\")";
923
    }
924
925
926
    /**
927
     * Get the list of classes that can be selected and used as data-values
928
     *
929
     * @param $includeLiterals Set to false to exclude non-data fields
930
     * @return array
931
     */
932
    public function getEditableFieldClasses($includeLiterals = true)
933
    {
934
        $classes = ClassInfo::getValidSubClasses('EditableFormField');
935
936
        // Remove classes we don't want to display in the dropdown.
937
        $editableFieldClasses = array();
938
        foreach ($classes as $class) {
939
            // Skip abstract / hidden classes
940
            if (Config::inst()->get($class, 'abstract', Config::UNINHERITED) || Config::inst()->get($class, 'hidden')
941
            ) {
942
                continue;
943
            }
944
945
            if (!$includeLiterals && Config::inst()->get($class, 'literal')) {
946
                continue;
947
            }
948
949
            $singleton = singleton($class);
950
            if (!$singleton->canCreate()) {
951
                continue;
952
            }
953
954
            $editableFieldClasses[$class] = $singleton->i18n_singular_name();
955
        }
956
957
        asort($editableFieldClasses);
958
        return $editableFieldClasses;
959
    }
960
961
    /**
962
     * @return EditableFormFieldValidator
963
     */
964
    public function getCMSValidator()
965
    {
966
        return EditableFormFieldValidator::create()
967
            ->setRecord($this);
968
    }
969
970
    /**
971
     * Determine effective display rules for this field.
972
     *
973
     * @return SS_List
974
     */
975
    public function EffectiveDisplayRules()
976
    {
977
        if ($this->Required) {
978
            return new ArrayList();
979
        }
980
        return $this->DisplayRules();
981
    }
982
}
983