Completed
Push — master ( cd60cf...f7a4c7 )
by
unknown
22s
created

ElementalAreaField::getTypes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace DNADesign\Elemental\Forms;
4
5
use BlocksPage;
0 ignored issues
show
Bug introduced by
The type BlocksPage was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use DNADesign\Elemental\Controllers\ElementalAreaController;
7
use DNADesign\Elemental\Models\BaseElement;
8
use DNADesign\Elemental\Models\ElementalArea;
9
use DNADesign\Elemental\Services\ElementTabProvider;
10
use SilverStripe\Control\Controller;
11
use SilverStripe\Core\Config\Config;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\Forms\CompositeField;
14
use SilverStripe\Forms\FieldGroup;
15
use SilverStripe\Forms\FieldList;
16
use SilverStripe\Forms\GridField\GridField;
17
use SilverStripe\Forms\TabSet;
18
use SilverStripe\ORM\DataObjectInterface;
19
use Symbiote\GridFieldExtensions\GridFieldAddNewMultiClass;
20
21
class ElementalAreaField extends GridField
22
{
23
    /**
24
     * @var ElementalArea $area
25
     */
26
    protected $area;
27
28
    /**
29
     * @var array $type
30
     */
31
    protected $types = [];
32
33
    /**
34
     * @var null
35
     */
36
    protected $inputType = null;
37
38
    protected $modelClassName = BaseElement::class;
39
40
    /**
41
     * @param string $name
42
     * @param ElementalArea $area
43
     * @param string[] $blockTypes
44
     */
45
    public function __construct($name, ElementalArea $area, array $blockTypes)
46
    {
47
        $this->setTypes($blockTypes);
48
49
        $config = new ElementalAreaConfig();
50
51
        if (!empty($blockTypes)) {
52
            /** @var GridFieldAddNewMultiClass $adder */
53
            $adder = Injector::inst()->create(GridFieldAddNewMultiClass::class);
54
            $adder->setClasses($blockTypes);
55
            $config->addComponent($adder);
56
        }
57
58
        // By default, no need for a title on the editor. If there is more than one area then use `setTitle` to describe
59
        parent::__construct($name, '', $area->Elements(), $config);
0 ignored issues
show
Bug introduced by
It seems like $area->Elements() can also be of type DNADesign\Elemental\Models\BaseElement[]; however, parameter $dataList of SilverStripe\Forms\GridF...ridField::__construct() does only seem to accept SilverStripe\ORM\SS_List|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

59
        parent::__construct($name, '', /** @scrutinizer ignore-type */ $area->Elements(), $config);
Loading history...
60
        $this->area = $area;
61
62
        $this->addExtraClass('element-editor__container');
63
    }
64
65
    /**
66
     * @param array $types
67
     *
68
     * @return $this
69
     */
70
    public function setTypes($types)
71
    {
72
        $this->types = $types;
73
74
        return $this;
75
    }
76
77
    /**
78
     * @return array
79
     */
80
    public function getTypes()
81
    {
82
        $types = $this->types;
83
84
        $this->extend('updateGetTypes', $types);
85
86
        return $types;
87
    }
88
89
    /**
90
     * @return ElementalArea
91
     */
92
    public function getArea()
93
    {
94
        return $this->area;
95
    }
96
97
    /**
98
     * Overloaded to skip GridField implementation - this is copied from FormField.
99
     *
100
     * @param array $properties
101
     * @return \SilverStripe\ORM\FieldType\DBHTMLText|string
102
     */
103
    public function FieldHolder($properties = array())
104
    {
105
        $context = $this;
106
107
        if (count($properties)) {
108
            $context = $this->customise($properties);
109
        }
110
111
        return $context->renderWith($this->getFieldHolderTemplates());
112
    }
113
114
    public function getSchemaDataDefaults()
115
    {
116
        $schemaData = parent::getSchemaDataDefaults();
117
118
        $area = $this->getArea();
119
        $pageId = ($area && ($page = $area->getOwnerPage())) ? $page->ID : null;
120
        $schemaData['page-id'] = $pageId;
121
        $schemaData['elemental-area-id'] = $area ? $area->ID : null;
0 ignored issues
show
introduced by
$area is of type DNADesign\Elemental\Models\ElementalArea, thus it always evaluated to true.
Loading history...
122
123
        $blockTypes = [];
124
125
        // Use the internal (temporary) provider to get cached tab names.
126
        /** @var ElementTabProvider $tabProvider */
127
        $tabProvider = Injector::inst()->get(ElementTabProvider::class);
128
129
        foreach ($this->getTypes() as $className => $blockTitle) {
130
            $blockTypes[] = [
131
                'name' => str_replace('\\', '-', $className),
132
                'title' => $blockTitle,
133
                'icon' => Config::inst()->get($className, 'icon'),
134
                'tabs' => $tabProvider->getTabsForElement($className),
135
            ];
136
        }
137
138
        $schemaData['element-types'] = $blockTypes;
139
        $schemaData['base-add-href'] = Controller::join_links($this->Link(), 'add-multi-class');
140
        return $schemaData;
141
    }
142
143
    /**
144
     * A getter method that seems redundant in that it is a function that returns a function,
145
     * however the returned closure is used in an array map function to return a complete FieldList
146
     * representing a read only view of the element passed in (to the closure).
147
     *
148
     * @return callable
149
     */
150
    protected function getReadOnlyBlockReducer()
151
    {
152
        return function (BaseElement $element) {
153
            $parentName = 'Element' . $element->ID;
154
            $elementFields = $element->getCMSFields();
155
156
            // Obtain highest impact fields for a summary (e.g. Title & Content)
157
            foreach ($elementFields as $field) {
158
                if (is_object($field) && $field instanceof TabSet) {
159
                    // Assign the fields of the first Tab in the TabSet - most regularly 'Root.Main'
160
                    $elementFields = $field->FieldList()->first()->FieldList();
161
                    break;
162
                }
163
            }
164
165
            // Set values (before names don't match anymore)
166
            $elementFields->setValues($element->getQueriedDatabaseFields());
167
168
            // Ensure field names are unique between elements on parent form
169
            $elementFields->recursiveWalk(function ($field) use ($parentName) {
170
                $field->setName($parentName . '_' . $field->getName());
171
            });
172
173
            // Combine into an appropriately named group
174
            $elementGroup = FieldGroup::create($elementFields);
175
            $elementGroup->setForm($this->getForm());
176
            $elementGroup->setName($parentName);
177
            $elementGroup->addExtraClass('elemental-area__element--historic');
178
179
            // Also set the important data for the rendering Component
180
            $elementGroup->setSchemaData([
181
                'data' => [
182
                    'ElementID' => $element->ID,
183
                    'ElementType' => $element->getType(),
184
                    'ElementIcon' => $element->config()->icon,
185
                    'ElementTitle' => $element->Title,
186
                    // @todo: Change this to block history permalink when that functionality becomes available.
187
                    'ElementEditLink' => $element->CMSEditLink()
188
                ]
189
            ]);
190
191
            return $elementGroup;
192
        };
193
    }
194
195
    /**
196
     * Provides a readonly representation of the GridField (superclass) Uses a reducer
197
     * {@see ElementalAreaField::getReadOnlyBlockReducer()} to fetch a read only representation of the listed class
198
     * {@see GridField::getModelClass()}
199
     *
200
     * @return CompositeField
201
     */
202
    public function performReadonlyTransformation()
203
    {
204
        /** @var CompositeField $readOnlyField */
205
        $readOnlyField = $this->castedCopy(CompositeField::class);
206
        $blockReducer = $this->getReadOnlyBlockReducer();
207
        $readOnlyField->setChildren(
208
            FieldList::create(array_map($blockReducer, $this->getArea()->Elements()->toArray()))
209
        );
210
211
        $readOnlyField = $readOnlyField->performReadonlyTransformation();
212
        return $readOnlyField
213
            ->setReadOnly(true)
214
            ->setName($this->getName())
215
            ->addExtraClass('elemental-area--read-only');
216
    }
217
218
    public function setSubmittedValue($value, $data = null)
219
    {
220
        // Content comes through as a JSON encoded list through a hidden field.
221
        return $this->setValue(json_decode($value, true));
222
    }
223
224
    public function saveInto(DataObjectInterface $dataObject)
225
    {
226
        /** @var BlocksPage $dataObject */
227
        parent::saveInto($dataObject);
228
229
        $elementData = $this->Value();
230
        $idPrefixLength = strlen(sprintf(ElementalAreaController::FORM_NAME_TEMPLATE, ''));
231
232
        foreach ($elementData as $form => $data) {
233
            // Extract the ID
234
            $elementId = (int) substr($form, $idPrefixLength);
235
236
            /** @var BaseElement $element */
237
            $element = $this->getArea()->Elements()->byID($elementId);
238
239
            if (!$element) {
240
                // Ignore invalid elements
241
                continue;
242
            }
243
244
            $fields = [];
245
246
            $fieldNamePrefix = sprintf(EditFormFactory::FIELD_NAMESPACE_TEMPLATE, $elementId, '');
247
            $prefixLength = strlen($fieldNamePrefix);
248
249
            foreach ($data as $field => $datum) {
250
                // Check that the field starts with a valid name
251
                if (strpos($field, $fieldNamePrefix) !== 0) {
252
                    continue;
253
                }
254
255
                $fields[substr($field, $prefixLength)] = $datum;
256
            }
257
258
            $element->update($fields);
259
            $element->write();
260
        }
261
    }
262
}
263