Completed
Pull Request — master (#518)
by Daniel
35:40
created

EditableFormField::getSetsOwnError()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1.037

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 3
cp 0.6667
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1.037
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
        "ShowInSummary" => "Boolean",
117
    );
118
119
    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...
120
        'ShowOnLoad' => true,
121
    );
122
123
124
    /**
125
     * @config
126
     * @var array
127
     */
128
    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...
129
        "Parent" => "UserDefinedForm",
130
    );
131
132
    /**
133 1
     * Built in extensions required
134
     *
135 1
     * @config
136 1
     * @var array
137
     */
138
    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...
139
        "SilverStripe\\ORM\\Versioning\\Versioned('Stage', 'Live')"
140
    );
141
142
    /**
143 1
     * @config
144
     * @var array
145 1
     */
146
    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...
147
        "DisplayRules" => "EditableCustomRule.Parent" // from CustomRules
148
    );
149
150
    /**
151 10
     * @var bool
152
     */
153 10
    protected $readonly;
154
155
    /**
156
     * Set the visibility of an individual form field
157 1
     *
158
     * @param bool
159
     */
160 10
    public function setReadonly($readonly = true)
161
    {
162
        $this->readonly = $readonly;
163
    }
164 10
165
    /**
166
     * Returns whether this field is readonly
167
     *
168
     * @return bool
169
     */
170
    private function isReadonly()
171
    {
172
        return $this->readonly;
173
    }
174
175
    /**
176
     * @return FieldList
177
     */
178
    public function getCMSFields()
179
    {
180
        $fields = new FieldList(new TabSet('Root'));
181
182
        // Main tab
183
        $fields->addFieldsToTab(
184
            'Root.Main',
185
            array(
186
                ReadonlyField::create(
187
                    'Type',
188
                    _t('EditableFormField.TYPE', 'Type'),
189
                    $this->i18n_singular_name()
190
                ),
191
                CheckboxField::create('ShowInSummary', _t('EditableFormField.SHOWINSUMMARY', 'Show in summary gridfield')),
192
                LiteralField::create(
193
                    'MergeField',
194
                    _t(
195
                        'EditableFormField.MERGEFIELDNAME',
196
                        '<div class="field readonly">' .
197
                            '<label class="left">Merge field</label>' .
198
                            '<div class="middleColumn">' .
199
                                '<span class="readonly">$' . $this->Name . '</span>' .
200
                            '</div>' .
201
                        '</div>'
202
                    )
203
                ),
204
                TextField::create('Title'),
205
                TextField::create('Default', _t('EditableFormField.DEFAULT', 'Default value')),
206
                TextField::create('RightTitle', _t('EditableFormField.RIGHTTITLE', 'Right title')),
207
                SegmentField::create('Name')->setModifiers(array(
208
                    UnderscoreSegmentFieldModifier::create()->setDefault('FieldName'),
209
                    DisambiguationSegmentFieldModifier::create(),
210
                ))->setPreview($this->Name)
211
            )
212
        );
213
214
        // Custom settings
215
        if (!empty(self::$allowed_css)) {
216
            $cssList = array();
217
            foreach (self::$allowed_css as $k => $v) {
218
                if (!is_array($v)) {
219
                    $cssList[$k]=$v;
220
                } elseif ($k === $this->ClassName) {
221
                    $cssList = array_merge($cssList, $v);
222
                }
223
            }
224
225
            $fields->addFieldToTab('Root.Main',
226
                DropdownField::create(
227
                    'ExtraClass',
228
                    _t('EditableFormField.EXTRACLASS_TITLE', 'Extra Styling/Layout'),
229
                    $cssList
230
                )->setDescription(_t(
231
                    'EditableFormField.EXTRACLASS_SELECT',
232
                    'Select from the list of allowed styles'
233
                ))
234
            );
235
        } else {
236
            $fields->addFieldToTab('Root.Main',
237
                TextField::create(
238
                    'ExtraClass',
239
                    _t('EditableFormField.EXTRACLASS_Title', 'Extra CSS classes')
240
                )->setDescription(_t(
241
                    'EditableFormField.EXTRACLASS_MULTIPLE',
242
                    'Separate each CSS class with a single space'
243
                ))
244
            );
245
        }
246
247
        // Validation
248
        $validationFields = $this->getFieldValidationOptions();
249
        if ($validationFields && $validationFields->count()) {
250
            $fields->addFieldsToTab('Root.Validation', $validationFields);
251
        }
252
253
        // Add display rule fields
254
        $displayFields = $this->getDisplayRuleFields();
255
        if ($displayFields && $displayFields->count()) {
256
            $fields->addFieldsToTab('Root.DisplayRules', $displayFields);
257
        }
258
259
        $this->extend('updateCMSFields', $fields);
260
261
        return $fields;
262
    }
263
264
    /**
265
     * Return fields to display on the 'Display Rules' tab
266
     *
267
     * @return FieldList
268
     */
269
    protected function getDisplayRuleFields()
270
    {
271
        // Check display rules
272
        if ($this->Required) {
273
            return new FieldList(
274
                LabelField::create(_t(
275
                    'EditableFormField.DISPLAY_RULES_DISABLED',
276
                    'Display rules are not enabled for required fields. ' .
277
                    'Please uncheck "Is this field Required?" under "Validation" to re-enable.'
278
                ))->addExtraClass('message warning')
279
            );
280
        }
281
        $self = $this;
282
        $allowedClasses = array_keys($this->getEditableFieldClasses(false));
283
        $editableColumns = new GridFieldEditableColumns();
284
        $editableColumns->setDisplayFields(array(
285
            'Display' => '',
286
            '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...
287
                return DropdownField::create(
288
                    $column,
289
                    '',
290
                    EditableFormField::get()
291
                        ->filter(array(
292
                            'ParentID' => $self->ParentID,
293
                            'ClassName' => $allowedClasses
294
                        ))
295
                        ->exclude(array(
296
                            'ID' => $self->ID
297
                        ))
298
                        ->map('ID', 'Title')
299
                    );
300
            },
301
            '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...
302
                $options = Config::inst()->get('EditableCustomRule', 'condition_options');
303
                return DropdownField::create($column, '', $options);
304
            },
305
            '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...
306
                return TextField::create($column);
307
            },
308
            '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...
309
                return HiddenField::create($column, '', $self->ID);
310
            }
311 39
        ));
312
313 39
        // Custom rules
314
        $customRulesConfig = GridFieldConfig::create()
315
            ->addComponents(
316 39
                $editableColumns,
317
                new GridFieldButtonRow(),
318 25
                new GridFieldToolbarHeader(),
319 39
                new GridFieldAddNewInlineButton(),
320
                new GridFieldDeleteAction()
321
            );
322
323 39
        return new FieldList(
324 39
            CheckboxField::create('ShowOnLoad')
325 39
                ->setDescription(_t(
326 39
                    'EditableFormField.SHOWONLOAD',
327 39
                    'Initial visibility before processing these rules'
328 39
                )),
329 39
            GridField::create(
330
                'DisplayRules',
331
                _t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
332
                $this->DisplayRules(),
333
                $customRulesConfig
334
            )
335
        );
336 25
    }
337
338
    public function onBeforeWrite()
339
    {
340 25
        parent::onBeforeWrite();
341 25
342 25
        // Set a field name.
343
        if (!$this->Name) {
344
            // New random name
345 25
            $this->Name = $this->generateName();
346 25
        } elseif ($this->Name === 'Field') {
347 25
            throw new ValidationException('Field name cannot be "Field"');
348
        }
349
350
        if (!$this->Sort && $this->ParentID) {
351
            $parentID = $this->ParentID;
352
            $this->Sort = EditableFormField::get()
353
                ->filter('ParentID', $parentID)
354
                ->max('Sort') + 1;
355
        }
356
    }
357
358
    /**
359
     * Generate a new non-conflicting Name value
360
     *
361
     * @return string
362
     */
363
    protected function generateName()
364
    {
365
        do {
366
            // Generate a new random name after this class
367 1
            $class = get_class($this);
368
            $entropy = substr(sha1(uniqid()), 0, 5);
369 1
            $name = "{$class}_{$entropy}";
370
371
            // Check if it conflicts
372
            $exists = EditableFormField::get()->filter('Name', $name)->count() > 0;
373
        } while ($exists);
374
        return $name;
375
    }
376
377
    /**
378
     * Flag indicating that this field will set its own error message via data-msg='' attributes
379 1
     *
380
     * @return bool
381 1
     */
382 1
    public function getSetsOwnError()
383 1
    {
384
        return false;
385
    }
386
387
    /**
388
     * Return whether a user can delete this form field
389
     * based on whether they can edit the page
390
     *
391
     * @param Member $member
392
     * @return bool
393
     */
394
    public function canDelete($member = null)
395
    {
396
        return $this->canEdit($member);
397
    }
398
399
    /**
400
     * Return whether a user can edit this form field
401
     * based on whether they can edit the page
402
     *
403
     * @param Member $member
404
     * @return bool
405
     */
406
    public function canEdit($member = null)
407
    {
408
        $parent = $this->Parent();
409
        if ($parent && $parent->exists()) {
410
            return $parent->canEdit($member) && !$this->isReadonly();
411 1
        } elseif (!$this->exists() && Controller::has_curr()) {
412
            // This is for GridFieldOrderableRows support as it checks edit permissions on
413 1
            // singleton of the class. Allows editing of User Defined Form pages by
414 1
            // 'Content Authors' and those with permission to edit the UDF page. (ie. CanEditType/EditorGroups)
415 1
            // This is to restore User Forms 2.x backwards compatibility.
416
            $controller = Controller::curr();
417
            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...
418
                $parent = $controller->getRecord($controller->currentPageID());
419
                // Only allow this behaviour on pages using UserFormFieldEditorExtension, such
420
                // as UserDefinedForm page type.
421
                if ($parent && $parent->hasExtension('UserFormFieldEditorExtension')) {
422
                    return $parent->canEdit($member);
423
                }
424
            }
425
        }
426
427
        // Fallback to secure admin permissions
428 3
        return parent::canEdit($member);
429
    }
430
431 3
    /**
432 3
     * Return whether a user can view this form field
433
     * based on whether they can view the page, regardless of the ReadOnly status of the field
434
     *
435
     * @param Member $member
436
     * @return bool
437 3
     */
438
    public function canView($member = null)
439
    {
440
        $parent = $this->Parent();
441
        if ($parent && $parent->exists()) {
442
            return $parent->canView($member);
443
        }
444
445
        return true;
446 3
    }
447
448
    /**
449 3
     * Return whether a user can create an object of this type
450
     *
451
     * @param Member $member
452
     * @param array $context Virtual parameter to allow context to be passed in to check
453 3
     * @return bool
454
     */
455 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...
456
    {
457
        // Check parent page
458 3
        $parent = $this->getCanCreateContext($context);
459
        if ($parent) {
460
            return $parent->canEdit($member);
461
        }
462
463
        // Fall back to secure admin permissions
464
        return parent::canCreate($member);
465
    }
466
467
    /**
468
     * Helper method to check the parent for this object
469
     *
470
     * @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...
471
     * @return SiteTree Parent page instance
472
     */
473 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...
474
    {
475
        // Inspect second parameter to canCreate for a 'Parent' context
476
        if (isset($context['Parent'])) {
477
            return $context['Parent'];
478
        }
479
        // Hack in currently edited page if context is missing
480
        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...
481
            return Controller::curr()->currentPage();
482
        }
483
484
        // No page being edited
485
        return null;
486
    }
487
488 9
    /**
489
     * Check if can publish
490 9
     *
491
     * @param Member $member
492
     * @return bool
493 9
     */
494 1
    public function canPublish($member = null)
495 9
    {
496 9
        return $this->canEdit($member);
497
    }
498
499
    /**
500
     * Check if can unpublish
501
     *
502
     * @param Member $member
503 2
     * @return bool
504
     */
505
    public function canUnpublish($member = null)
506 2
    {
507 2
        return $this->canDelete($member);
508 2
    }
509 1
510 2
    /**
511
     * Publish this Form Field to the live site
512
     *
513 2
     * Wrapper for the {@link Versioned} publish function
514 2
     */
515
    public function doPublish($fromStage, $toStage, $createNewVersion = false)
516
    {
517
        $this->publish($fromStage, $toStage, $createNewVersion);
518
519
        // Don't forget to publish the related custom rules...
520
        foreach ($this->DisplayRules() as $rule) {
521
            $rule->doPublish($fromStage, $toStage, $createNewVersion);
522
        }
523
    }
524
525
    /**
526
     * Delete this field from a given stage
527
     *
528
     * Wrapper for the {@link Versioned} deleteFromStage function
529
     */
530
    public function doDeleteFromStage($stage)
531
    {
532
        // Remove custom rules in this stage
533
        $rules = Versioned::get_by_stage('EditableCustomRule', $stage)
534
            ->filter('ParentID', $this->ID);
535
        foreach ($rules as $rule) {
536
            $rule->deleteFromStage($stage);
537
        }
538
539
        // Remove record
540
        $this->deleteFromStage($stage);
541
    }
542
543
    /**
544
     * checks wether record is new, copied from Sitetree
545
     */
546
    public function isNew()
547
    {
548
        if (empty($this->ID)) {
549
            return true;
550
        }
551
552
        if (is_numeric($this->ID)) {
553
            return false;
554
        }
555
556
        return stripos($this->ID, 'new') === 0;
557
    }
558
559
    /**
560
     * checks if records is changed on stage
561
     * @return boolean
562
     */
563
    public function getIsModifiedOnStage()
564
    {
565
        // new unsaved fields could be never be published
566
        if ($this->isNew()) {
567
            return false;
568
        }
569
570
        $stageVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Stage', $this->ID);
571
        $liveVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Live', $this->ID);
572
573
        return ($stageVersion && $stageVersion != $liveVersion);
574
    }
575
576
    /**
577
     * @deprecated since version 4.0
578
     */
579
    public function getSettings()
580
    {
581
        Deprecation::notice('4.0', 'getSettings is deprecated');
582
        return (!empty($this->CustomSettings)) ? unserialize($this->CustomSettings) : array();
583
    }
584
585
    /**
586
     * @deprecated since version 4.0
587
     */
588
    public function setSettings($settings = array())
589
    {
590
        Deprecation::notice('4.0', 'setSettings is deprecated');
591
        $this->CustomSettings = serialize($settings);
592
    }
593
594
    /**
595
     * @deprecated since version 4.0
596
     */
597
    public function setSetting($key, $value)
598
    {
599
        Deprecation::notice('4.0', "setSetting({$key}) is deprecated");
600
        $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...
601
        $settings[$key] = $value;
602
603
        $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...
604
    }
605
606
    /**
607
     * Set the allowed css classes for the extraClass custom setting
608
     *
609
     * @param array The permissible CSS classes to add
610
     */
611
    public function setAllowedCss(array $allowed)
612
    {
613
        if (is_array($allowed)) {
614
            foreach ($allowed as $k => $v) {
615
                self::$allowed_css[$k] = (!is_null($v)) ? $v : $k;
616
            }
617
        }
618
    }
619
620
    /**
621
     * @deprecated since version 4.0
622
     */
623
    public function getSetting($setting)
624
    {
625
        Deprecation::notice("4.0", "getSetting({$setting}) is deprecated");
626
627
        $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...
628
        if (isset($settings) && count($settings) > 0) {
629
            if (isset($settings[$setting])) {
630
                return $settings[$setting];
631
            }
632
        }
633
        return '';
634
    }
635
636
    /**
637
     * Get the path to the icon for this field type, relative to the site root.
638
     *
639
     * @return string
640
     */
641
    public function getIcon()
642
    {
643
        return USERFORMS_DIR . '/images/' . strtolower($this->class) . '.png';
644
    }
645
646 18
    /**
647
     * Return whether or not this field has addable options
648 18
     * such as a dropdown field or radio set
649
     *
650
     * @return bool
651
     */
652
    public function getHasAddableOptions()
653
    {
654
        return false;
655
    }
656
657
    /**
658
     * Return whether or not this field needs to show the extra
659
     * options dropdown list
660
     *
661
     * @return bool
662
     */
663
    public function showExtraOptions()
664
    {
665
        return true;
666
    }
667
668
    /**
669
     * Returns the Title for rendering in the front-end (with XML values escaped)
670
     *
671
     * @return string
672
     */
673
    public function getEscapedTitle()
674
    {
675
        return Convert::raw2xml($this->Title);
676
    }
677
678
    /**
679
     * Find the numeric indicator (1.1.2) that represents it's nesting value
680
     *
681
     * Only useful for fields attached to a current page, and that contain other fields such as pages
682
     * or groups
683
     *
684
     * @return string
685
     */
686
    public function getFieldNumber()
687
    {
688
        // Check if exists
689
        if (!$this->exists()) {
690
            return null;
691
        }
692
        // Check parent
693
        $form = $this->Parent();
694
        if (!$form || !$form->exists() || !($fields = $form->Fields())) {
695
            return null;
696
        }
697
698
        $prior = 0; // Number of prior group at this level
699
        $stack = array(); // Current stack of nested groups, where the top level = the page
700
        foreach ($fields->map('ID', 'ClassName') as $id => $className) {
701
            if ($className === 'EditableFormStep') {
702
                $priorPage = empty($stack) ? $prior : $stack[0];
703
                $stack = array($priorPage + 1);
704
                $prior = 0;
705
            } elseif ($className === 'EditableFieldGroup') {
706
                $stack[] = $prior + 1;
707
                $prior = 0;
708
            } elseif ($className === 'EditableFieldGroupEnd') {
709
                $prior = array_pop($stack);
710
            }
711
            if ($id == $this->ID) {
712
                return implode('.', $stack);
713
            }
714
        }
715
        return null;
716
    }
717
718
    public function getCMSTitle()
719
    {
720
        return $this->i18n_singular_name() . ' (' . $this->Title . ')';
721
    }
722
723
    /**
724
     * @deprecated since version 4.0
725
     */
726
    public function getFieldName($field = false)
727
    {
728
        Deprecation::notice('4.0', "getFieldName({$field}) is deprecated");
729
        return ($field) ? "Fields[".$this->ID."][".$field."]" : "Fields[".$this->ID."]";
730
    }
731
732
    /**
733
     * @deprecated since version 4.0
734
     */
735
    public function getSettingName($field)
736
    {
737
        Deprecation::notice('4.0', "getSettingName({$field}) is deprecated");
738
        $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...
739
740
        return $name . '[' . $field .']';
741
    }
742
743
    /**
744
     * Append custom validation fields to the default 'Validation'
745
     * section in the editable options view
746
     *
747
     * @return FieldList
748
     */
749
    public function getFieldValidationOptions()
750
    {
751 17
        $fields = new FieldList(
752
            CheckboxField::create('Required', _t('EditableFormField.REQUIRED', 'Is this field Required?'))
753 17
                ->setDescription(_t('EditableFormField.REQUIRED_DESCRIPTION', 'Please note that conditional fields can\'t be required')),
754 17
            TextField::create('CustomErrorMessage', _t('EditableFormField.CUSTOMERROR', 'Custom Error Message'))
755 17
        );
756 17
757
        $this->extend('updateFieldValidationOptions', $fields);
758
759
        return $fields;
760
    }
761
762
    /**
763 17
     * Return a FormField to appear on the front end. Implement on
764
     * your subclass.
765
     *
766 17
     * @return FormField
767
     */
768
    public function getFormField()
769 17
    {
770
        user_error("Please implement a getFormField() on your EditableFormClass ". $this->ClassName, E_USER_ERROR);
771 1
    }
772 1
773
    /**
774
     * Updates a formfield with extensions
775 17
     *
776
     * @param FormField $field
777 3
     */
778 3
    public function doUpdateFormField($field)
779 3
    {
780 3
        $this->extend('beforeUpdateFormField', $field);
781
        $this->updateFormField($field);
782 3
        $this->extend('afterUpdateFormField', $field);
783 1
    }
784 1
785 1
    /**
786 3
     * Updates a formfield with the additional metadata specified by this field
787
     *
788
     * @param FormField $field
789 17
     */
790
    protected function updateFormField($field)
791
    {
792 17
        // set the error / formatting messages
793
        $field->setCustomValidationMessage($this->getErrorMessage()->RAW());
794
795
        // set the right title on this field
796
        if ($this->RightTitle) {
797
            // Since this field expects raw html, safely escape the user data prior
798
            $field->setRightTitle(Convert::raw2xml($this->RightTitle));
799 2
        }
800
801 2
        // if this field is required add some
802
        if ($this->Required) {
803
            // Required validation can conflict so add the Required validation messages as input attributes
804
            $errorMessage = $this->getErrorMessage()->HTML();
805
            $field->addExtraClass('requiredField');
806
            $field->setAttribute('data-rule-required', 'true');
807
            $field->setAttribute('data-msg-required', $errorMessage);
0 ignored issues
show
Bug introduced by
It seems like $errorMessage defined by $this->getErrorMessage()->HTML() on line 804 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...
808
809
            if ($identifier = UserDefinedForm::config()->required_identifier) {
810 2
                $title = $field->Title() . " <span class='required-identifier'>". $identifier . "</span>";
811
                $field->setTitle($title);
812 2
            }
813
        }
814
815
        // if this field has an extra class
816
        if ($this->ExtraClass) {
817
            $field->addExtraClass($this->ExtraClass);
818
        }
819
    }
820
821 17
    /**
822
     * Return the instance of the submission field class
823 17
     *
824 17
     * @return SubmittedFormField
825
     */
826
    public function getSubmittedFormField()
827 17
    {
828
        return new SubmittedFormField();
829 17
    }
830
831
832
    /**
833
     * Show this form field (and its related value) in the reports and in emails.
834
     *
835
     * @return bool
836
     */
837
    public function showInReports()
838 2
    {
839
        return true;
840
    }
841 2
842 2
    /**
843 2
     * Return the error message for this field. Either uses the custom
844 2
     * one (if provided) or the default SilverStripe message
845
     *
846
     * @return Varchar
847 2
     */
848 2
    public function getErrorMessage()
849 2
    {
850 2
        $title = strip_tags("'". ($this->Title ? $this->Title : $this->Name) . "'");
851 2
        $standard = sprintf(_t('Form.FIELDISREQUIRED', '%s is required').'.', $title);
852 2
853
        // only use CustomErrorMessage if it has a non empty value
854
        $errorMessage = (!empty($this->CustomErrorMessage)) ? $this->CustomErrorMessage : $standard;
855
856
        return DBField::create_field('Varchar', $errorMessage);
857
    }
858
859
    /**
860
     * Invoked by UserFormUpgradeService to migrate settings specific to this field from CustomSettings
861
     * to the field proper
862
     *
863
     * @param array $data Unserialised data
864
     */
865
    public function migrateSettings($data)
866
    {
867
        // Map 'Show' / 'Hide' to boolean
868
        if (isset($data['ShowOnLoad'])) {
869
            $this->ShowOnLoad = $data['ShowOnLoad'] === '' || ($data['ShowOnLoad'] && $data['ShowOnLoad'] !== 'Hide');
870
            unset($data['ShowOnLoad']);
871
        }
872
873
        // Migrate all other settings
874
        foreach ($data as $key => $value) {
875
            if ($this->hasField($key)) {
876
                $this->setField($key, $value);
877
            }
878
        }
879
    }
880
881
    /**
882
     * Get the formfield to use when editing this inline in gridfield
883
     *
884 8
     * @param string $column name of column
885
     * @param array $fieldClasses List of allowed classnames if this formfield has a selectable class
886 8
     * @return FormField
887
     */
888
    public function getInlineClassnameField($column, $fieldClasses)
889
    {
890
        return DropdownField::create($column, false, $fieldClasses);
891
    }
892
893
    /**
894
     * Get the formfield to use when editing the title inline
895
     *
896
     * @param string $column
897
     * @return FormField
898
     */
899
    public function getInlineTitleField($column)
900
    {
901
        return TextField::create($column, false)
902
            ->setAttribute('placeholder', _t('EditableFormField.TITLE', 'Title'))
903
            ->setAttribute('data-placeholder', _t('EditableFormField.TITLE', 'Title'));
904
    }
905
906
    /**
907 2
     * Get the JS expression for selecting the holder for this field
908
     *
909 2
     * @return string
910
     */
911
    public function getSelectorHolder()
912 2
    {
913 2
        return "$(\"#{$this->Name}\")";
914
    }
915 2
916 2
    /**
917 2
     * Gets the JS expression for selecting the value for this field
918
     *
919
     * @param EditableCustomRule $rule Custom rule this selector will be used with
920 2
     * @param bool $forOnLoad Set to true if this will be invoked on load
921
     */
922
    public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false)
923
    {
924 2
        return "$(\"input[name='{$this->Name}']\")";
925 2
    }
926
927
928
    /**
929 2
     * Get the list of classes that can be selected and used as data-values
930 2
     *
931
     * @param $includeLiterals Set to false to exclude non-data fields
932 2
     * @return array
933 2
     */
934
    public function getEditableFieldClasses($includeLiterals = true)
935
    {
936
        $classes = ClassInfo::getValidSubClasses('EditableFormField');
937
938
        // Remove classes we don't want to display in the dropdown.
939
        $editableFieldClasses = array();
940
        foreach ($classes as $class) {
941
            // Skip abstract / hidden classes
942
            if (Config::inst()->get($class, 'abstract', Config::UNINHERITED) || Config::inst()->get($class, 'hidden')
943
            ) {
944
                continue;
945
            }
946
947
            if (!$includeLiterals && Config::inst()->get($class, 'literal')) {
948
                continue;
949
            }
950 10
951
            $singleton = singleton($class);
952 10
            if (!$singleton->canCreate()) {
953 4
                continue;
954
            }
955 10
956
            $editableFieldClasses[$class] = $singleton->i18n_singular_name();
957
        }
958 1
959
        asort($editableFieldClasses);
960
        return $editableFieldClasses;
961
    }
962
963
    /**
964
     * @return EditableFormFieldValidator
965
     */
966
    public function getCMSValidator()
967
    {
968
        return EditableFormFieldValidator::create()
969
            ->setRecord($this);
970
    }
971
972
    /**
973
     * Determine effective display rules for this field.
974
     *
975
     * @return SS_List
976
     */
977
    public function EffectiveDisplayRules()
978
    {
979
        if ($this->Required) {
980
            return new ArrayList();
981
        }
982
        return $this->DisplayRules();
983
    }
984
}
985