Checks if the types of the passed arguments in a function/method call are compatible.
1 | <?php |
||
2 | |||
3 | namespace DNADesign\Elemental\Forms; |
||
4 | |||
5 | use BlocksPage; |
||
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\FormField; |
||
17 | use SilverStripe\Forms\GridField\GridField; |
||
18 | use SilverStripe\Forms\TabSet; |
||
19 | use SilverStripe\ORM\DataObjectInterface; |
||
20 | use Symbiote\GridFieldExtensions\GridFieldAddNewMultiClass; |
||
21 | |||
22 | class ElementalAreaField extends GridField |
||
23 | { |
||
24 | /** |
||
25 | * @var ElementalArea $area |
||
26 | */ |
||
27 | protected $area; |
||
28 | |||
29 | /** |
||
30 | * @var array $type |
||
31 | */ |
||
32 | protected $types = []; |
||
33 | |||
34 | /** |
||
35 | * @var null |
||
36 | */ |
||
37 | protected $inputType = null; |
||
38 | |||
39 | protected $modelClassName = BaseElement::class; |
||
40 | |||
41 | /** |
||
42 | * @param string $name |
||
43 | * @param ElementalArea $area |
||
44 | * @param string[] $blockTypes |
||
45 | */ |
||
46 | public function __construct($name, ElementalArea $area, array $blockTypes) |
||
47 | { |
||
48 | $this->setTypes($blockTypes); |
||
49 | |||
50 | $config = new ElementalAreaConfig(); |
||
51 | |||
52 | if (!empty($blockTypes)) { |
||
53 | /** @var GridFieldAddNewMultiClass $adder */ |
||
54 | $adder = Injector::inst()->create(GridFieldAddNewMultiClass::class); |
||
55 | $adder->setClasses($blockTypes); |
||
56 | $config->addComponent($adder); |
||
57 | } |
||
58 | |||
59 | // By default, no need for a title on the editor. If there is more than one area then use `setTitle` to describe |
||
60 | parent::__construct($name, '', $area->Elements(), $config); |
||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
61 | $this->area = $area; |
||
62 | |||
63 | $this->addExtraClass('element-editor__container no-change-track'); |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * @param array $types |
||
68 | * |
||
69 | * @return $this |
||
70 | */ |
||
71 | public function setTypes($types) |
||
72 | { |
||
73 | $this->types = $types; |
||
74 | |||
75 | return $this; |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * @return array |
||
80 | */ |
||
81 | public function getTypes() |
||
82 | { |
||
83 | $types = $this->types; |
||
84 | |||
85 | $this->extend('updateGetTypes', $types); |
||
86 | |||
87 | return $types; |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | * @return ElementalArea |
||
92 | */ |
||
93 | public function getArea() |
||
94 | { |
||
95 | return $this->area; |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * Overloaded to skip GridField implementation - this is copied from FormField. |
||
100 | * |
||
101 | * @param array $properties |
||
102 | * @return \SilverStripe\ORM\FieldType\DBHTMLText|string |
||
103 | */ |
||
104 | public function FieldHolder($properties = array()) |
||
105 | { |
||
106 | $context = $this; |
||
107 | |||
108 | if (count($properties)) { |
||
109 | $context = $this->customise($properties); |
||
110 | } |
||
111 | |||
112 | return $context->renderWith($this->getFieldHolderTemplates()); |
||
113 | } |
||
114 | |||
115 | public function getSchemaDataDefaults() |
||
116 | { |
||
117 | $schemaData = parent::getSchemaDataDefaults(); |
||
118 | |||
119 | $area = $this->getArea(); |
||
120 | $pageId = ($area && ($page = $area->getOwnerPage())) ? $page->ID : null; |
||
121 | $schemaData['page-id'] = $pageId; |
||
122 | $schemaData['elemental-area-id'] = $area ? (int) $area->ID : null; |
||
123 | |||
124 | $allowedTypes = $this->getTypes(); |
||
125 | $schemaData['allowed-elements'] = array_keys($allowedTypes); |
||
126 | |||
127 | return $schemaData; |
||
128 | } |
||
129 | |||
130 | /** |
||
131 | * A getter method that seems redundant in that it is a function that returns a function, |
||
132 | * however the returned closure is used in an array map function to return a complete FieldList |
||
133 | * representing a read only view of the element passed in (to the closure). |
||
134 | * |
||
135 | * @return callable |
||
136 | */ |
||
137 | protected function getReadOnlyBlockReducer() |
||
138 | { |
||
139 | return function (BaseElement $element) { |
||
140 | $parentName = 'Element' . $element->ID; |
||
141 | $elementFields = $element->getCMSFields(); |
||
142 | |||
143 | // Obtain highest impact fields for a summary (e.g. Title & Content) |
||
144 | foreach ($elementFields as $field) { |
||
145 | if (is_object($field) && $field instanceof TabSet) { |
||
146 | // Assign the fields of the first Tab in the TabSet - most regularly 'Root.Main' |
||
147 | $elementFields = $field->FieldList()->first()->FieldList(); |
||
148 | break; |
||
149 | } |
||
150 | } |
||
151 | |||
152 | // Set values (before names don't match anymore) |
||
153 | $elementFields->setValues($element->getQueriedDatabaseFields()); |
||
154 | |||
155 | // Combine into an appropriately named group |
||
156 | $elementGroup = FieldGroup::create($elementFields); |
||
157 | $elementGroup->setForm($this->getForm()); |
||
158 | $elementGroup->setName($parentName); |
||
159 | $elementGroup->addExtraClass('elemental-area__element--historic'); |
||
160 | |||
161 | // Also set the important data for the rendering Component |
||
162 | $elementGroup->setSchemaData([ |
||
163 | 'data' => [ |
||
164 | 'ElementID' => $element->ID, |
||
165 | 'ElementType' => $element->getType(), |
||
166 | 'ElementIcon' => $element->config()->icon, |
||
167 | 'ElementTitle' => $element->Title, |
||
168 | // @todo: Change this to block history permalink when that functionality becomes available. |
||
169 | 'ElementEditLink' => $element->CMSEditLink() |
||
170 | ] |
||
171 | ]); |
||
172 | |||
173 | return $elementGroup; |
||
174 | }; |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Provides a readonly representation of the GridField (superclass) Uses a reducer |
||
179 | * {@see ElementalAreaField::getReadOnlyBlockReducer()} to fetch a read only representation of the listed class |
||
180 | * {@see GridField::getModelClass()} |
||
181 | * |
||
182 | * @return CompositeField |
||
183 | */ |
||
184 | public function performReadonlyTransformation() |
||
185 | { |
||
186 | /** @var CompositeField $readOnlyField */ |
||
187 | $readOnlyField = $this->castedCopy(CompositeField::class); |
||
188 | $blockReducer = $this->getReadOnlyBlockReducer(); |
||
189 | $readOnlyField->setChildren( |
||
190 | FieldList::create(array_map($blockReducer, $this->getArea()->Elements()->toArray())) |
||
191 | ); |
||
192 | |||
193 | $readOnlyField = $readOnlyField->performReadonlyTransformation(); |
||
194 | |||
195 | // Ensure field names are unique between elements on parent form but only after transformations have been |
||
196 | // performed |
||
197 | /** @var FieldGroup $elementForm */ |
||
198 | foreach ($readOnlyField->getChildren() as $elementForm) { |
||
199 | $parentName = $elementForm->getName(); |
||
200 | $elementForm->getChildren()->recursiveWalk(function (FormField $field) use ($parentName) { |
||
201 | $field->setName($parentName . '_' . $field->getName()); |
||
202 | }); |
||
203 | } |
||
204 | |||
205 | return $readOnlyField |
||
206 | ->setReadOnly(true) |
||
207 | ->setName($this->getName()) |
||
208 | ->addExtraClass('elemental-area--read-only'); |
||
209 | } |
||
210 | |||
211 | public function setSubmittedValue($value, $data = null) |
||
212 | { |
||
213 | // Content comes through as a JSON encoded list through a hidden field. |
||
214 | return $this->setValue(json_decode($value, true)); |
||
215 | } |
||
216 | |||
217 | public function saveInto(DataObjectInterface $dataObject) |
||
218 | { |
||
219 | /** @var BlocksPage $dataObject */ |
||
220 | parent::saveInto($dataObject); |
||
221 | |||
222 | $elementData = $this->Value(); |
||
223 | $idPrefixLength = strlen(sprintf(ElementalAreaController::FORM_NAME_TEMPLATE, '')); |
||
224 | |||
225 | if (!$elementData) { |
||
226 | return; |
||
227 | } |
||
228 | |||
229 | foreach ($elementData as $form => $data) { |
||
230 | // Extract the ID |
||
231 | $elementId = (int) substr($form, $idPrefixLength); |
||
232 | |||
233 | /** @var BaseElement $element */ |
||
234 | $element = $this->getArea()->Elements()->byID($elementId); |
||
235 | |||
236 | if (!$element) { |
||
237 | // Ignore invalid elements |
||
238 | continue; |
||
239 | } |
||
240 | |||
241 | $data = ElementalAreaController::removeNamespacesFromFields($data, $element->ID); |
||
242 | |||
243 | $element->updateFromFormData($data); |
||
244 | $element->write(); |
||
245 | } |
||
246 | } |
||
247 | } |
||
248 |