Passed
Push — master ( 09c0a7...cde555 )
by Robbie
02:30
created

ElementalAreaField::getReadOnlyBlockReducer()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 42
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 22
nc 1
nop 0
dl 0
loc 42
rs 9.568
c 0
b 0
f 0
1
<?php
2
3
namespace DNADesign\Elemental\Forms;
4
5
use DNADesign\Elemental\Models\BaseElement;
6
use DNADesign\Elemental\Models\ElementalArea;
7
use SilverStripe\Control\Controller;
8
use SilverStripe\Core\Injector\Injector;
9
use SilverStripe\Forms\CompositeField;
10
use SilverStripe\Forms\FieldGroup;
11
use SilverStripe\Forms\FieldList;
12
use SilverStripe\Forms\GridField\GridField;
13
use SilverStripe\Forms\TabSet;
14
use Symbiote\GridFieldExtensions\GridFieldAddNewMultiClass;
15
16
class ElementalAreaField extends GridField
17
{
18
    /**
19
     * @var ElementalArea $area
20
     */
21
    protected $area;
22
23
    /**
24
     * @var array $type
25
     */
26
    protected $types = [];
27
28
    /**
29
     * @var null
30
     */
31
    protected $inputType = null;
32
33
    protected $modelClassName = BaseElement::class;
34
35
    /**
36
     * @param string $name
37
     * @param ElementalArea $area
38
     * @param string[] $blockTypes
39
     */
40
    public function __construct($name, ElementalArea $area, array $blockTypes)
41
    {
42
        $this->setTypes($blockTypes);
43
44
        $config = new ElementalAreaConfig();
45
46
        if (!empty($blockTypes)) {
47
            /** @var GridFieldAddNewMultiClass $adder */
48
            $adder = Injector::inst()->create(GridFieldAddNewMultiClass::class);
49
            $adder->setClasses($blockTypes);
50
            $config->addComponent($adder);
51
        }
52
53
        // By default, no need for a title on the editor. If there is more than one area then use `setTitle` to describe
54
        parent::__construct($name, '', $area->Elements(), $config);
55
        $this->area = $area;
56
57
        $this->addExtraClass('element-editor__container');
58
    }
59
60
    /**
61
     * @param array $types
62
     *
63
     * @return $this
64
     */
65
    public function setTypes($types)
66
    {
67
        $this->types = $types;
68
69
        return $this;
70
    }
71
72
    /**
73
     * @return array
74
     */
75
    public function getTypes()
76
    {
77
        $types = $this->types;
78
79
        $this->extend('updateGetTypes', $types);
80
81
        return $types;
82
    }
83
84
    /**
85
     * @return ElementalArea
86
     */
87
    public function getArea()
88
    {
89
        return $this->area;
90
    }
91
92
    /**
93
     * Overloaded to skip GridField implementation - this is copied from FormField.
94
     *
95
     * @param array $properties
96
     * @return \SilverStripe\ORM\FieldType\DBHTMLText|string
97
     */
98
    public function FieldHolder($properties = array())
99
    {
100
        $context = $this;
101
102
        if (count($properties)) {
103
            $context = $this->customise($properties);
104
        }
105
106
        return $context->renderWith($this->getFieldHolderTemplates());
107
    }
108
109
    public function getSchemaDataDefaults()
110
    {
111
        $schemaData = parent::getSchemaDataDefaults();
112
        $pageId = ($this->getArea() && ($page = $this->getArea()->getOwnerPage())) ? $page->ID : null;
113
        $schemaData['page-id'] = $pageId;
114
115
        $blockTypes = [];
116
117
        foreach ($this->getTypes() as $className => $blockTitle) {
118
            $blockTypes[] = [
119
                'value' => str_replace('\\', '-', $className),
120
                'title' => $blockTitle,
121
            ];
122
        }
123
124
        $schemaData['element-types'] = $blockTypes;
125
        $schemaData['base-add-href'] = Controller::join_links($this->Link(), 'add-multi-class');
126
        return $schemaData;
127
    }
128
129
    /**
130
     * A getter method that seems redundant in that it is a function that returns a function,
131
     * however the returned closure is used in an array map function to return a complete FieldList
132
     * representing a read only view of the element passed in (to the closure).
133
     *
134
     * @return callable
135
     */
136
    protected function getReadOnlyBlockReducer()
137
    {
138
        return function (BaseElement $element) {
139
            $parentName = 'Element' . $element->ID;
140
            $elementFields = $element->getCMSFields();
141
142
            // Obtain highest impact fields for a summary (e.g. Title & Content)
143
            foreach ($elementFields as $field) {
144
                if (is_object($field) && $field instanceof TabSet) {
145
                    // Assign the fields of the first Tab in the TabSet - most regularly 'Root.Main'
146
                    $elementFields = $field->FieldList()->first()->FieldList();
147
                    break;
148
                }
149
            }
150
151
            // Set values (before names don't match anymore)
152
            $elementFields->setValues($element->getQueriedDatabaseFields());
153
154
            // Ensure field names are unique between elements on parent form
155
            $elementFields->recursiveWalk(function ($field) use ($parentName) {
156
                $field->setName($parentName . '_' . $field->getName());
157
            });
158
159
            // Combine into an appropriately named group
160
            $elementGroup = FieldGroup::create($elementFields);
161
            $elementGroup->setForm($this->getForm());
162
            $elementGroup->setName($parentName);
163
            $elementGroup->addExtraClass('elemental-area__element--historic');
164
165
            // Also set the important data for the rendering Component
166
            $elementGroup->setSchemaData([
167
                'data' => [
168
                    'ElementID' => $element->ID,
169
                    'ElementType' => $element->getType(),
170
                    'ElementIcon' => $element->config()->icon,
171
                    'ElementTitle' => $element->Title,
172
                    // @todo: Change this to block history permalink when that functionality becomes available.
173
                    'ElementEditLink' => $element->CMSEditLink()
174
                ]
175
            ]);
176
177
            return $elementGroup;
178
        };
179
    }
180
181
    /**
182
     * Provides a readonly representation of the GridField (superclass) Uses a reducer
183
     * {@see ElementalAreaField::getReadOnlyBlockReducer()} to fetch a read only representation of the listed class
184
     * {@see GridField::getModelClass()}
185
     *
186
     * @return CompositeField
187
     */
188
    public function performReadonlyTransformation()
189
    {
190
        /** @var CompositeField $readOnlyField */
191
        $readOnlyField = $this->castedCopy(CompositeField::class);
192
        $blockReducer = $this->getReadOnlyBlockReducer();
193
        $readOnlyField->setChildren(
194
            FieldList::create(array_map($blockReducer, $this->getArea()->Elements()->toArray()))
195
        );
196
197
        $readOnlyField = $readOnlyField->performReadonlyTransformation();
198
        return $readOnlyField
199
            ->setReadOnly(true)
200
            ->setName($this->getName())
201
            ->addExtraClass('elemental-area--read-only');
202
    }
203
}
204