dnadesign /
silverstripe-elemental
| 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\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
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...
|
|||||
| 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; |
||||
|
0 ignored issues
–
show
|
|||||
| 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()->get('icon'), |
||||
| 167 | 'ElementTitle' => $element->Title, |
||||
| 168 | // @todo: Change this to block history permalink when that functionality becomes available. |
||||
| 169 | 'ElementEditLink' => Controller::join_links( |
||||
| 170 | // Always get the edit link for the block directly, not the in-line edit form if supported |
||||
| 171 | $element->CMSEditLink(true), |
||||
| 172 | // @todo make this auto-permalinking work somehow |
||||
| 173 | '#Root_History' |
||||
| 174 | ), |
||||
| 175 | ], |
||||
| 176 | ]); |
||||
| 177 | |||||
| 178 | return $elementGroup; |
||||
| 179 | }; |
||||
| 180 | } |
||||
| 181 | |||||
| 182 | /** |
||||
| 183 | * Provides a readonly representation of the GridField (superclass) Uses a reducer |
||||
| 184 | * {@see ElementalAreaField::getReadOnlyBlockReducer()} to fetch a read only representation of the listed class |
||||
| 185 | * {@see GridField::getModelClass()} |
||||
| 186 | * |
||||
| 187 | * @return CompositeField |
||||
| 188 | */ |
||||
| 189 | public function performReadonlyTransformation() |
||||
| 190 | { |
||||
| 191 | /** @var CompositeField $readOnlyField */ |
||||
| 192 | $readOnlyField = $this->castedCopy(CompositeField::class); |
||||
| 193 | $blockReducer = $this->getReadOnlyBlockReducer(); |
||||
| 194 | $readOnlyField->setChildren( |
||||
| 195 | FieldList::create(array_map($blockReducer, $this->getArea()->Elements()->toArray())) |
||||
| 196 | ); |
||||
| 197 | |||||
| 198 | $readOnlyField = $readOnlyField->performReadonlyTransformation(); |
||||
| 199 | |||||
| 200 | // Ensure field names are unique between elements on parent form but only after transformations have been |
||||
| 201 | // performed |
||||
| 202 | /** @var FieldGroup $elementForm */ |
||||
| 203 | foreach ($readOnlyField->getChildren() as $elementForm) { |
||||
| 204 | $parentName = $elementForm->getName(); |
||||
| 205 | $elementForm->getChildren()->recursiveWalk(function (FormField $field) use ($parentName) { |
||||
| 206 | $field->setName($parentName . '_' . $field->getName()); |
||||
| 207 | }); |
||||
| 208 | } |
||||
| 209 | |||||
| 210 | return $readOnlyField |
||||
| 211 | ->setReadOnly(true) |
||||
| 212 | ->setName($this->getName()) |
||||
| 213 | ->addExtraClass('elemental-area--read-only'); |
||||
| 214 | } |
||||
| 215 | |||||
| 216 | public function setSubmittedValue($value, $data = null) |
||||
| 217 | { |
||||
| 218 | // Content comes through as a JSON encoded list through a hidden field. |
||||
| 219 | return $this->setValue(json_decode($value, true)); |
||||
| 220 | } |
||||
| 221 | |||||
| 222 | public function saveInto(DataObjectInterface $dataObject) |
||||
| 223 | { |
||||
| 224 | /** @var BlocksPage $dataObject */ |
||||
| 225 | parent::saveInto($dataObject); |
||||
| 226 | |||||
| 227 | $elementData = $this->Value(); |
||||
| 228 | $idPrefixLength = strlen(sprintf(ElementalAreaController::FORM_NAME_TEMPLATE, '')); |
||||
| 229 | |||||
| 230 | if (!$elementData) { |
||||
| 231 | return; |
||||
| 232 | } |
||||
| 233 | |||||
| 234 | foreach ($elementData as $form => $data) { |
||||
| 235 | // Extract the ID |
||||
| 236 | $elementId = (int) substr($form, $idPrefixLength); |
||||
| 237 | |||||
| 238 | /** @var BaseElement $element */ |
||||
| 239 | $element = $this->getArea()->Elements()->byID($elementId); |
||||
| 240 | |||||
| 241 | if (!$element) { |
||||
| 242 | // Ignore invalid elements |
||||
| 243 | continue; |
||||
| 244 | } |
||||
| 245 | |||||
| 246 | $data = ElementalAreaController::removeNamespacesFromFields($data, $element->ID); |
||||
| 247 | |||||
| 248 | $element->updateFromFormData($data); |
||||
| 249 | $element->write(); |
||||
| 250 | } |
||||
| 251 | } |
||||
| 252 | } |
||||
| 253 |
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