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

UserFormFieldEditorExtension::updateCMSFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
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...
4
use SilverStripe\Forms\Tab;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Tab.

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\View\Requirements;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Requirements.

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\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...
7
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...
8
use SilverStripe\Forms\GridField\GridFieldEditButton;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, GridFieldEditButton.

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\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...
10
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...
11
use SilverStripe\Forms\GridField\GridFieldDetailForm;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, GridFieldDetailForm.

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\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...
13
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...
14
use SilverStripe\ORM\DataExtension;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DataExtension.

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
16
/**
17
 * @package userforms
18
 */
19
class UserFormFieldEditorExtension extends DataExtension
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...
20
{
21
22
    /**
23
     * @var array
24
     */
25
    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...
26
        'Fields' => 'EditableFormField'
27
    );
28
29
    private static $owns = array(
0 ignored issues
show
Unused Code introduced by
The property $owns 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...
30
        'Fields',
31
    );
32
33
    /**
34
     * Adds the field editor to the page.
35
     *
36
     * @return FieldList
37
     */
38
    public function updateCMSFields(FieldList $fields)
39
    {
40
        $fieldEditor = $this->getFieldEditorGrid();
41
42
        $fields->insertAfter(new Tab('FormFields', _t('UserFormFieldEditorExtension.FORMFIELDS', 'Form Fields')), 'Main');
43
        $fields->addFieldToTab('Root.FormFields', $fieldEditor);
44
45
        return $fields;
46
    }
47
48
    /**
49
     * Gets the field editor, for adding and removing EditableFormFields.
50
     *
51
     * @return GridField
52
     */
53
    public function getFieldEditorGrid()
54
    {
55
        Requirements::javascript(USERFORMS_DIR . '/javascript/FieldEditor.js');
56
57
        $fields = $this->owner->Fields();
58
59
        $this->createInitialFormStep(true);
60
61
        $editableColumns = new GridFieldEditableColumns();
62
        $fieldClasses = singleton('EditableFormField')->getEditableFieldClasses();
63
        $editableColumns->setDisplayFields(array(
64
            'ClassName' => function ($record, $column, $grid) use ($fieldClasses) {
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...
65
                if ($record instanceof EditableFormField) {
66
                    return $record->getInlineClassnameField($column, $fieldClasses);
67
                }
68
            },
69
            'Title' => 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...
70
                if ($record instanceof EditableFormField) {
71
                    return $record->getInlineTitleField($column);
72
                }
73
            }
74
        ));
75
76
        $config = GridFieldConfig::create()
77
            ->addComponents(
78
                $editableColumns,
79
                new GridFieldButtonRow(),
80
                GridFieldAddClassesButton::create('EditableTextField')
81
                    ->setButtonName(_t('UserFormFieldEditorExtension.ADD_FIELD', 'Add Field'))
82
                    ->setButtonClass('ss-ui-action-constructive'),
83
                GridFieldAddClassesButton::create('EditableFormStep')
84
                    ->setButtonName(_t('UserFormFieldEditorExtension.ADD_PAGE_BREAK', 'Add Page Break')),
85
                GridFieldAddClassesButton::create(array('EditableFieldGroup', 'EditableFieldGroupEnd'))
86
                    ->setButtonName(_t('UserFormFieldEditorExtension.ADD_FIELD_GROUP', 'Add Field Group')),
87
                new GridFieldEditButton(),
88
                new GridFieldDeleteAction(),
89
                new GridFieldToolbarHeader(),
90
                new GridFieldOrderableRows('Sort'),
91
                new GridFieldDetailForm()
92
            );
93
94
        $fieldEditor = GridField::create(
95
            'Fields',
96
            _t('UserDefinedForm.FIELDS', 'Fields'),
97
            $fields,
98
            $config
99
        )->addExtraClass('uf-field-editor');
100
101
        return $fieldEditor;
102
    }
103
104
    /**
105
     * A UserForm must have at least one step.
106
     * If no steps exist, create an initial step, and put all fields inside it.
107
     *
108
     * @param bool $force
109
     * @return void
110
     */
111
    public function createInitialFormStep($force = false)
112
    {
113
        // Only invoke once saved
114
        if (!$this->owner->exists()) {
115
            return;
116
        }
117
118
        // Check if first field is a step
119
        $fields = $this->owner->Fields();
120
        $firstField = $fields->first();
121
        if ($firstField instanceof EditableFormStep) {
122
            return;
123
        }
124
125
        // Don't create steps on write if there are no formfields, as this
126
        // can create duplicate first steps during publish of new records
127
        if (!$force && !$firstField) {
128
            return;
129
        }
130
131
        // Re-apply sort to each field starting at 2
132
        $next = 2;
133
        foreach ($fields as $field) {
134
            $field->Sort = $next++;
135
            $field->write();
136
        }
137
138
        // Add step
139
        $step = EditableFormStep::create();
140
        $step->Title = _t('EditableFormStep.TITLE_FIRST', 'First Page');
141
        $step->Sort = 1;
142
        $step->write();
143
        $fields->add($step);
144
    }
145
146
    /**
147
     * Ensure that at least one page exists at the start
148
     */
149
    public function onAfterWrite()
150
    {
151
        $this->createInitialFormStep();
152
    }
153
154
    /**
155
     * @see SiteTree::doPublish
156
     * @param Page $original
0 ignored issues
show
Bug introduced by
There is no parameter named $original. 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...
157
     *
158
     * @return void
159
     */
160
    public function onAfterPublish()
161
    {
162
        // Remove fields on the live table which could have been orphaned.
163
        $live = Versioned::get_by_stage("EditableFormField", "Live")
164
            ->filter('ParentID', $this->owner->ID);
165
166
        if ($live) {
167
            foreach ($live as $field) {
168
                $field->doDeleteFromStage('Live');
169
            }
170
        }
171
172
        foreach ($this->owner->Fields() as $field) {
173
            $field->doPublish('Stage', 'Live');
174
        }
175
    }
176
177
    /**
178
     * @see SiteTree::doUnpublish
179
     * @param Page $page
0 ignored issues
show
Bug introduced by
There is no parameter named $page. 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...
180
     *
181
     * @return void
182
     */
183
    public function onAfterUnpublish()
184
    {
185
        foreach ($this->owner->Fields() as $field) {
186
            $field->doDeleteFromStage('Live');
187
        }
188
    }
189
190
    /**
191
     * @see SiteTree::duplicate
192
     * @param DataObject $newPage
0 ignored issues
show
Bug introduced by
There is no parameter named $newPage. 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...
193
     *
194
     * @return DataObject
195
     */
196
    public function onAfterDuplicate($oldPage)
197
    {
198
        $newPage = $this->owner;
199
200
        // List of EditableFieldGroups, where the
201
        // key of the array is the ID of the old end group
202
        $fieldGroups = array();
203
        foreach ($oldPage->Fields() as $field) {
204
            $newField = $field->duplicate(false);
205
            $newField->ParentID = $newPage->ID;
206
            $newField->ParentClass = $newPage->ClassName;
207
            $newField->Version = 0;
208
            $newField->write();
209
210
            // If we encounter a group start, record it for later use
211
            if ($field instanceof EditableFieldGroup) {
212
                $fieldGroups[$field->EndID] = $newField;
213
            }
214
215
            // If we encounter an end group, link it back to the group start
216
            if ($field instanceof EditableFieldGroupEnd && isset($fieldGroups[$field->ID])) {
217
                $groupStart = $fieldGroups[$field->ID];
218
                $groupStart->EndID = $newField->ID;
219
                $groupStart->write();
220
            }
221
222 View Code Duplication
            foreach ($field->DisplayRules() as $customRule) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
223
                $newRule = $customRule->duplicate(false);
224
                $newRule->ParentID = $newField->ID;
225
                $newRule->Version = 0;
226
                $newRule->write();
227
            }
228
        }
229
230
        return $newPage;
231
    }
232
233
    /**
234
     * @see SiteTree::getIsModifiedOnStage
235
     * @param boolean $isModified
236
     *
237
     * @return boolean
238
     */
239
    public function getIsModifiedOnStage($isModified)
240
    {
241
        if (!$isModified) {
242
            foreach ($this->owner->Fields() as $field) {
243
                if ($field->getIsModifiedOnStage()) {
244
                    $isModified = true;
245
                    break;
246
                }
247
            }
248
        }
249
250
        return $isModified;
251
    }
252
253
    /**
254
     * @see SiteTree::doRevertToLive
255
     * @param Page $page
0 ignored issues
show
Bug introduced by
There is no parameter named $page. 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...
256
     *
257
     * @return void
258
     */
259
    public function onAfterRevertToLive()
260
    {
261
        foreach ($this->owner->Fields() as $field) {
262
            $field->publish('Live', 'Stage', false);
263
            $field->writeWithoutVersion();
264
        }
265
    }
266
}
267