Completed
Push — master ( c321ed...d72938 )
by Mohamed
04:04
created

ConfigurablePage   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 273
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 23
lcom 1
cbo 11
dl 0
loc 273
ccs 0
cts 109
cp 0
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getCMSFields() 0 17 1
B buildManageFieldsTab() 0 41 2
A buildPageFieldsTab() 0 11 2
B getFieldFromEditableField() 0 31 5
A getCMSValidator() 0 4 1
B Content() 0 26 3
B onAfterWrite() 0 32 6
B getEditableFields() 0 24 3
1
<?php
2
3
/**
4
 * ConfigurablePage is the page class for the module.
5
 *
6
 * @author  Mohamed Alsharaf <[email protected]>
7
 */
8
class ConfigurablePage extends Page
9
{
10
    private static $many_many = [
11
        'Fields' => 'Moo_EditableField',
12
    ];
13
    private static $many_many_extraFields = [
14
        'Fields' => [
15
            'Value' => 'Text',
16
            'Sort'  => 'Int',
17
            'Group' => 'Int',
18
        ],
19
    ];
20
    private static $has_one = [
21
        'EditableFieldGroup' => 'Moo_EditableFieldGroup',
22
    ];
23
    private static $singular_name = 'Configurable Page';
24
    private static $plural_name   = 'Configurable Pages';
25
    private static $description   = 'Create page with configurable fields';
26
    private static $icon          = 'configurablepage/images/icon.png';
27
28
    /**
29
     * An array of required field names.
30
     *
31
     * @var array
32
     */
33
    protected $requiredFields = [];
34
35
    /**
36
     * An instance of ManyManyList containing the current values from the configurable fields.
37
     *
38
     * @var ManyManyList
39
     */
40
    protected $editableFields;
41
42
    /**
43
     * List of allowed child page types.
44
     *
45
     * @var array
46
     */
47
    private static $allowed_children = ['ConfigurablePage', 'SiteTree'];
48
49
    /**
50
     * (non-PHPdoc).
51
     *
52
     * @see SiteTree::getCMSFields()
53
     */
54
    public function getCMSFields()
55
    {
56
        // Get the fields from the parent implementation
57
        $fields = parent::getCMSFields();
58
59
        // List of available fields in the page
60
        $groupFields = $this->EditableFieldGroup()->Fields();
61
        $list        = $this->Fields()->addMany($groupFields)->sort('Sort', 'ASC');
62
63
        // Add tab to edit fields values
64
        $this->buildPageFieldsTab($list, $fields);
65
66
        // Add tab to manage page fields
67
        $this->buildManageFieldsTab($list, $fields);
68
69
        return $fields;
70
    }
71
72
    /**
73
     * Create tab to manage page fields.
74
     *
75
     * @param FieldList $fields
76
     */
77
    protected function buildManageFieldsTab(ManyManyList $list, FieldList $fields)
78
    {
79
        // GridField for managing page specific fields
80
        $config = GridFieldConfig_RelationEditor::create();
81
        $config->getComponentByType('GridFieldPaginator')->setItemsPerPage(10);
82
        $config->removeComponentsByType('GridFieldAddNewButton');
83
        $config->removeComponentsByType('GridFieldEditButton');
84
        $config->getComponentByType('GridFieldDataColumns')->setDisplayFields([
85
            'Name'  => _t('ConfigurablePage.NAME', 'Name'),
86
            'Title' => _t('ConfigurablePage.TITLE', 'Title'),
87
            'Group' => _t('ConfigurablePage.GROUP', 'Group'),
88
        ]);
89
        $config->addComponent(new GridFieldOrderableRows('Sort'));
90
        $config->getComponentByType('GridFieldDataColumns')
91
            ->setFieldFormatting([
92
                'Group' => function ($value) {
93
                    return !$value ? '' : $this->EditableFieldGroup()->Title;
94
                },
95
            ]);
96
        $fieldsField = new GridField('Fields', 'Fields', $list, $config);
97
98
        // Drop-down list of editable field groups
99
        $groups = EditableFieldGroup::get()->map();
100
        $groups->unshift('', '');
101
102
        $groupsField = new DropdownField(
103
            'EditableFieldGroupID',
104
            _t('ConfigurablePage.FIELDGROUP', 'Editable field group'),
105
            $groups
106
        );
107
        $groupsField->setDescription(_t(
108
            'ConfigurablePage.FIELDGROUP_HELP',
109
            'Select a group to load its collection of fields in the current page. '
110
            . 'You need to click save to update the page fields.'
111
        ));
112
113
        // Add fields to manage page fields tab
114
        $fields->addFieldsToTab('Root.ManagePageFields', [
115
            $groupsField, $fieldsField,
116
        ]);
117
    }
118
119
    /**
120
     * Create tab to edit fields values.
121
     *
122
     * @param ManyManyList $list
123
     * @param FieldList    $fields
124
     */
125
    protected function buildPageFieldsTab(ManyManyList $list, FieldList $fields)
126
    {
127
        $fields->findOrMakeTab('Root.Fields', _t('ConfigurablePage.FIELDS', 'Fields'));
128
129
        $list->each(function (Moo_EditableField $editableField) use ($fields) {
130
            $field = $this->getFieldFromEditableField($editableField);
131
            if (false !== $field) {
132
                $fields->addFieldToTab('Root.Fields', $field);
0 ignored issues
show
Bug introduced by
It seems like $field defined by $this->getFieldFromEditableField($editableField) on line 130 can also be of type boolean; however, FieldList::addFieldToTab() does only seem to accept object<FormField>, 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...
133
            }
134
        });
135
    }
136
137
    /**
138
     * Add an editable field to the fields tab.
139
     *
140
     * @param Moo_EditableField $editableField
141
     *
142
     * @return bool|FormField
143
     */
144
    protected function getFieldFromEditableField(Moo_EditableField $editableField)
145
    {
146
        // Get the raw form field from the editable version
147
        $field = $editableField->getFormField();
148
        if (!$field) {
149
            return false;
150
        }
151
152
        // Set the error / formatting messages
153
        $field->setCustomValidationMessage($editableField->getErrorMessage());
154
155
        // Set the right title on this field
156
        $right = $editableField->getSetting('RightTitle');
157
        if ($right) {
158
            $field->setRightTitle($right);
159
            $field->addExtraClass('help');
160
        }
161
162
        // Set the required field
163
        if ($editableField->Required) {
164
            $this->requiredFields[] = $editableField->Name;
165
        }
166
167
        // Set the value
168
        if (!$field instanceof DatalessField) {
169
            $field->value = Convert::raw2att($editableField->Value);
170
            $this->setField($editableField->Name, $editableField->Value);
171
        }
172
173
        return $field;
174
    }
175
176
    /**
177
     * Set required fields.
178
     *
179
     * @return RequiredFields
180
     */
181
    public function getCMSValidator()
182
    {
183
        return new RequiredFields($this->requiredFields);
184
    }
185
186
    public function onAfterWrite()
187
    {
188
        parent::onAfterWrite();
189
190
        // Skip on publishing
191
        if (Versioned::get_live_stage() == Versioned::current_stage()) {
192
            return;
193
        }
194
195
        // Update the values of all fields added from editable field
196
        if ($this->ID && $this->manyMany('Fields') && $pageFields = $this->getEditableFields()) {
197
            $pageFields->each(function (Moo_EditableField $pageField) use ($pageFields) {
198
                // Set submitted value into the field
199
                $field = $pageField->getFormField();
200
                if (!$field) {
201
                    return;
202
                }
203
                $field->setValue($this->{$pageField->Name});
204
205
                // Extra fields to be saved
206
                $value = $field->Value();
207
                $sort = $pageField->Sort;
208
                $group = $pageField->Group;
209
210
                // Clone the editable field object
211
                // Remove the current saved one
212
                $pageFields->remove($pageField);
213
                // Add the clone with the new extra data
214
                $pageFields->add($pageField, ['Value' => $value, 'Sort' => $sort, 'Group' => $group]);
215
            });
216
        }
217
    }
218
219
    /**
220
     * Format the page Content.
221
     *
222
     * @return string
223
     */
224
    public function Content()
225
    {
226
        // Get custom fields
227
        $fields = $this->getEditableFields();
228
        $values = [];
229
230
        // Add custom fields to the current object
231
        // & create dictionary of the custom fields values
232
        foreach ($fields as $field) {
233
            $value = $field->getViewValue();
234
            $name  = $field->getViewFieldName();
235
236
            // Fields with false value are not viewable data
237
            if ($value !== false) {
238
                $this->setField($name, $value);
239
                $values['$' . $name] = $field->getValueAsString();
240
            }
241
        }
242
243
        // Execute content from extensions
244
        // Set content from view template module
245
        $this->extend('Content');
246
247
        // & Replace ${Field Name} with a string value
248
        return strtr($this->Content, $values);
249
    }
250
251
    /**
252
     * Get an array of all of the editable fields for the view template.
253
     *
254
     * @return ManyManyList
255
     */
256
    public function getEditableFields()
257
    {
258
        if (null === $this->editableFields) {
259
            // Fields from editable field groups
260
            $groupFields = $this->EditableFieldGroup()->Fields();
261
            $ids         = $groupFields->getIDList();
262
263
            // Set page specific fields
264
            $this->editableFields = $this->Fields();
265
266
            // Remove all fields that are used to belong to editable field group
267
            // Then sync editable field group with page specific fields
268
            // Else remove all of a group editable fields if exists
269
            if (!empty($ids)) {
270
                $this->editableFields->removeByFilter(
271
                    '"Group" > 0 AND EditableFieldID NOT IN (' . implode(',', $ids) . ')'
272
                )->addMany($groupFields);
273
            } else {
274
                $this->editableFields->removeByFilter('"Group" > 0');
275
            }
276
        }
277
278
        return $this->editableFields;
279
    }
280
}
281