Completed
Push — master ( 016a0b...25fc98 )
by Franco
12s
created

createInitialFormStep()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 34
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 34
rs 8.439
c 0
b 0
f 0
cc 6
eloc 18
nc 5
nop 1
1
<?php
2
3
namespace SilverStripe\UserForms\Extension;
4
5
use SilverStripe\Core\Manifest\ModuleLoader;
6
use SilverStripe\Forms\FieldList;
7
use SilverStripe\Forms\Tab;
8
use SilverStripe\Forms\GridField\GridField;
9
use SilverStripe\Forms\GridField\GridFieldButtonRow;
10
use SilverStripe\Forms\GridField\GridFieldConfig;
11
use SilverStripe\Forms\GridField\GridFieldEditButton;
12
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
13
use SilverStripe\Forms\GridField\GridFieldDetailForm;
14
use SilverStripe\Forms\GridField\GridFieldToolbarHeader;
15
use SilverStripe\ORM\DataExtension;
16
use SilverStripe\UserForms\Form\GridFieldAddClassesButton;
17
use SilverStripe\UserForms\Model\EditableFormField;
18
use SilverStripe\UserForms\Model\EditableFormField\EditableFieldGroup;
19
use SilverStripe\UserForms\Model\EditableFormField\EditableFieldGroupEnd;
20
use SilverStripe\UserForms\Model\EditableFormField\EditableFormStep;
21
use SilverStripe\UserForms\Model\EditableFormField\EditableTextField;
22
use SilverStripe\Versioned\Versioned;
23
use SilverStripe\View\Requirements;
24
use Symbiote\GridFieldExtensions\GridFieldEditableColumns;
25
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;
26
27
/**
28
 * @package userforms
29
 */
30
class UserFormFieldEditorExtension extends DataExtension
31
{
32
    /**
33
     * @var array
34
     */
35
    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...
36
        'Fields' => EditableFormField::class
37
    );
38
39
    private static $owns = [
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...
40
        'Fields'
41
    ];
42
43
    private static $cascade_deletes = [
0 ignored issues
show
Unused Code introduced by
The property $cascade_deletes 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...
44
        'Fields'
45
    ];
46
47
    /**
48
     * Adds the field editor to the page.
49
     *
50
     * @return FieldList
51
     */
52
    public function updateCMSFields(FieldList $fields)
53
    {
54
        $fieldEditor = $this->getFieldEditorGrid();
55
56
        $fields->insertAfter(new Tab('FormFields', _t(__CLASS__.'.FORMFIELDS', 'Form Fields')), 'Main');
0 ignored issues
show
Documentation introduced by
'Main' is of type string, but the function expects a object<SilverStripe\Forms\FormField>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
57
        $fields->addFieldToTab('Root.FormFields', $fieldEditor);
58
59
        return $fields;
60
    }
61
62
    /**
63
     * Gets the field editor, for adding and removing EditableFormFields.
64
     *
65
     * @return GridField
66
     */
67
    public function getFieldEditorGrid()
68
    {
69
        $module = ModuleLoader::getModule('silverstripe/userforms');
70
        Requirements::javascript($module->getRelativeResourcePath('client/dist/js/userforms-cms.js'));
71
72
        $fields = $this->owner->Fields();
0 ignored issues
show
Bug introduced by
The method Fields() does not exist on SilverStripe\ORM\DataObject. Did you maybe mean beforeUpdateCMSFields()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
73
74
        $this->createInitialFormStep(true);
75
76
        $editableColumns = new GridFieldEditableColumns();
77
        $fieldClasses = singleton(EditableFormField::class)->getEditableFieldClasses();
78
        $editableColumns->setDisplayFields([
79
            '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...
80
                if ($record instanceof EditableFormField) {
81
                    return $record->getInlineClassnameField($column, $fieldClasses);
82
                }
83
            },
84
            '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...
85
                if ($record instanceof EditableFormField) {
86
                    return $record->getInlineTitleField($column);
87
                }
88
            }
89
        ]);
90
91
        $config = GridFieldConfig::create()
92
            ->addComponents(
93
                $editableColumns,
94
                new GridFieldButtonRow(),
95
                (new GridFieldAddClassesButton(EditableTextField::class))
96
                    ->setButtonName(_t(__CLASS__.'.ADD_FIELD', 'Add Field'))
97
                    ->setButtonClass('ss-ui-action-constructive'),
98
                (new GridFieldAddClassesButton(EditableFormStep::class))
99
                    ->setButtonName(_t(__CLASS__.'.ADD_PAGE_BREAK', 'Add Page Break')),
100
                (new GridFieldAddClassesButton([EditableFieldGroup::class, EditableFieldGroupEnd::class]))
101
                    ->setButtonName(_t(__CLASS__.'.ADD_FIELD_GROUP', 'Add Field Group')),
102
                new GridFieldEditButton(),
103
                new GridFieldDeleteAction(),
104
                new GridFieldToolbarHeader(),
105
                new GridFieldOrderableRows('Sort'),
106
                new GridFieldDetailForm()
107
            );
108
109
        $fieldEditor = GridField::create(
110
            'Fields',
111
            _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.FIELDS', 'Fields'),
112
            $fields,
113
            $config
114
        )->addExtraClass('uf-field-editor');
115
116
        return $fieldEditor;
117
    }
118
119
    /**
120
     * A UserForm must have at least one step.
121
     * If no steps exist, create an initial step, and put all fields inside it.
122
     *
123
     * @param bool $force
124
     * @return void
125
     */
126
    public function createInitialFormStep($force = false)
127
    {
128
        // Only invoke once saved
129
        if (!$this->owner->exists()) {
130
            return;
131
        }
132
133
        // Check if first field is a step
134
        $fields = $this->owner->Fields();
0 ignored issues
show
Bug introduced by
The method Fields() does not exist on SilverStripe\ORM\DataObject. Did you maybe mean beforeUpdateCMSFields()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
135
        $firstField = $fields->first();
136
        if ($firstField instanceof EditableFormStep) {
137
            return;
138
        }
139
140
        // Don't create steps on write if there are no formfields, as this
141
        // can create duplicate first steps during publish of new records
142
        if (!$force && !$firstField) {
143
            return;
144
        }
145
146
        // Re-apply sort to each field starting at 2
147
        $next = 2;
148
        foreach ($fields as $field) {
149
            $field->Sort = $next++;
150
            $field->write();
151
        }
152
153
        // Add step
154
        $step = EditableFormStep::create();
155
        $step->Title = _t('SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep.TITLE_FIRST', 'First Page');
156
        $step->Sort = 1;
157
        $step->write();
158
        $fields->add($step);
159
    }
160
161
    /**
162
     * Ensure that at least one page exists at the start
163
     */
164
    public function onAfterWrite()
165
    {
166
        $this->createInitialFormStep();
167
    }
168
169
    /**
170
     * Remove any orphaned child records on publish
171
     */
172
    public function onAfterPublish()
173
    {
174
        // store IDs of fields we've published
175
        $seenIDs = [];
176
        foreach ($this->owner->Fields() as $field) {
0 ignored issues
show
Bug introduced by
The method Fields() does not exist on SilverStripe\ORM\DataObject. Did you maybe mean beforeUpdateCMSFields()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
177
            // store any IDs of fields we publish so we don't unpublish them
178
            $seenIDs[] = $field->ID;
179
            $field->doPublish(Versioned::DRAFT, Versioned::LIVE);
180
            $field->destroy();
181
        }
182
183
        // fetch any orphaned live records
184
        $live = Versioned::get_by_stage(EditableFormField::class, Versioned::LIVE)
185
            ->filter([
186
                'ParentID' => $this->owner->ID,
187
            ]);
188
189
        if (!empty($seenIDs)) {
190
            $live = $live->exclude([
191
                'ID' => $seenIDs,
192
            ]);
193
        }
194
195
        // delete orphaned records
196
        foreach ($live as $field) {
197
            $field->deleteFromStage(Versioned::LIVE);
198
            $field->destroy();
199
        }
200
    }
201
202
    /**
203
     * Remove all fields from the live stage when unpublishing the page
204
     */
205
    public function onAfterUnpublish()
206
    {
207
        foreach ($this->owner->Fields() as $field) {
0 ignored issues
show
Bug introduced by
The method Fields() does not exist on SilverStripe\ORM\DataObject. Did you maybe mean beforeUpdateCMSFields()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
208
            $field->deleteFromStage(Versioned::LIVE);
209
        }
210
    }
211
212
    /**
213
     * When duplicating a UserDefinedForm, duplicate all of its fields and display rules
214
     *
215
     * @see \SilverStripe\ORM\DataObject::duplicate
216
     * @param \SilverStripe\ORM\DataObject $oldPage
217
     * @param bool $doWrite
218
     * @param string $manyMany
219
     * @return \SilverStripe\ORM\DataObject
220
     */
221
    public function onAfterDuplicate($oldPage, $doWrite, $manyMany)
0 ignored issues
show
Unused Code introduced by
The parameter $doWrite 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...
Unused Code introduced by
The parameter $manyMany 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...
222
    {
223
        // List of EditableFieldGroups, where the key of the array is the ID of the old end group
224
        $fieldGroups = [];
225
        foreach ($oldPage->Fields() as $field) {
0 ignored issues
show
Bug introduced by
The method Fields() does not exist on SilverStripe\ORM\DataObject. Did you maybe mean beforeUpdateCMSFields()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
226
            $newField = $field->duplicate(false);
227
            $newField->ParentID = $this->owner->ID;
228
            $newField->ParentClass = $this->owner->ClassName;
229
            $newField->Version = 0;
230
            $newField->write();
231
232
            // If we encounter a group start, record it for later use
233
            if ($field instanceof EditableFieldGroup) {
234
                $fieldGroups[$field->EndID] = $newField;
0 ignored issues
show
Documentation introduced by
The property EndID does not exist on object<SilverStripe\User...eld\EditableFieldGroup>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
235
            }
236
237
            // If we encounter an end group, link it back to the group start
238
            if ($field instanceof EditableFieldGroupEnd && isset($fieldGroups[$field->ID])) {
239
                $groupStart = $fieldGroups[$field->ID];
240
                $groupStart->EndID = $newField->ID;
241
                $groupStart->write();
242
            }
243
244 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...
245
                $newRule = $customRule->duplicate(false);
246
                $newRule->ParentID = $newField->ID;
247
                $newRule->Version = 0;
248
                $newRule->write();
249
            }
250
        }
251
    }
252
253
    /**
254
     * Checks child fields to see if any are modified in draft as well. The owner of this extension will still
255
     * use the Versioned method to determine its own status.
256
     *
257
     * @see Versioned::isModifiedOnDraft
258
     *
259
     * @return boolean|null
260
     */
261
    public function isModifiedOnDraft()
262
    {
263
        foreach ($this->owner->Fields() as $field) {
0 ignored issues
show
Bug introduced by
The method Fields() does not exist on SilverStripe\ORM\DataObject. Did you maybe mean beforeUpdateCMSFields()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
264
            if ($field->isModifiedOnDraft()) {
265
                return true;
266
            }
267
        }
268
    }
269
270
    /**
271
     * @see Versioned::doRevertToLive
272
     */
273
    public function onAfterRevertToLive()
274
    {
275
        foreach ($this->owner->Fields() as $field) {
0 ignored issues
show
Bug introduced by
The method Fields() does not exist on SilverStripe\ORM\DataObject. Did you maybe mean beforeUpdateCMSFields()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
276
            $field->copyVersionToStage(Versioned::LIVE, Versioned::DRAFT, false);
277
            $field->writeWithoutVersion();
278
        }
279
    }
280
}
281