1 | <?php |
||||
2 | |||||
3 | namespace DNADesign\Elemental\Forms; |
||||
4 | |||||
5 | use BlocksPage; |
||||
0 ignored issues
–
show
|
|||||
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
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
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
|
|||||
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 | $data = ElementalAreaController::removeNamespacesFromFields($data, $element->ID); |
||||
245 | |||||
246 | $element->updateFromFormData($data); |
||||
247 | $element->write(); |
||||
248 | } |
||||
249 | } |
||||
250 | } |
||||
251 |
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:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths