These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * @package elemental |
||
5 | */ |
||
6 | class ElementPageExtension extends DataExtension |
||
7 | { |
||
8 | |||
9 | /** |
||
10 | * @config |
||
11 | * |
||
12 | * @var string $elements_title Title of the element in the CMS. |
||
13 | */ |
||
14 | private static $elements_title = 'Content Blocks'; |
||
15 | |||
16 | /** |
||
17 | * @config |
||
18 | * |
||
19 | * @var array $ignored_classes Classes to ignore adding elements too. |
||
20 | */ |
||
21 | private static $ignored_classes = array(); |
||
22 | |||
23 | /** |
||
24 | * @var array $db |
||
25 | */ |
||
26 | private static $db = array(); |
||
27 | |||
28 | private static $has_one = array( |
||
29 | 'ElementArea' => 'ElementalArea' |
||
30 | ); |
||
31 | |||
32 | /** |
||
33 | * Setup the CMS Fields |
||
34 | * |
||
35 | * @param FieldList |
||
36 | */ |
||
37 | public function updateCMSFields(FieldList $fields) |
||
38 | { |
||
39 | // redirector pages should not have elements |
||
40 | if (is_a($this->owner, 'RedirectorPage')) { |
||
41 | return; |
||
42 | View Code Duplication | } else if ($ignored = Config::inst()->get('ElementPageExtension', 'ignored_classes')) { |
|
0 ignored issues
–
show
|
|||
43 | foreach ($ignored as $check) { |
||
44 | if (is_a($this->owner, $check)) { |
||
45 | return; |
||
46 | } |
||
47 | } |
||
48 | } |
||
49 | |||
50 | // add an empty holder for content as some module explicitly use insert |
||
51 | // after content. |
||
52 | $fields->replaceField('Content', new LiteralField('Content', '')); |
||
53 | |||
54 | $adder = new ElementalGridFieldAddNewMultiClass(); |
||
55 | |||
56 | $list = $this->getAvailableTypes(); |
||
57 | $adder->setClasses($list); |
||
58 | |||
59 | $area = $this->owner->ElementArea(); |
||
60 | |||
61 | if (!$area->exists() || !$area->isInDB()) { |
||
62 | $area->write(); |
||
63 | |||
64 | $this->owner->ElementAreaID = $area->ID; |
||
65 | $this->owner->write(); |
||
66 | } |
||
67 | |||
68 | $gridField = GridField::create('ElementArea', |
||
69 | Config::inst()->get("ElementPageExtension", 'elements_title'), |
||
70 | $this->owner->ElementArea()->Elements(), |
||
71 | GridFieldConfig_RelationEditor::create() |
||
72 | ->removeComponentsByType('GridFieldAddNewButton') |
||
73 | ->removeComponentsByType('GridFieldAddExistingAutocompleter') |
||
74 | ->removeComponentsByType('GridFieldDeleteAction') |
||
75 | ->addComponent(new GridFieldDeleteAction(false)) |
||
76 | ->addComponent($adder) |
||
77 | ->addComponent(new GridFieldSortableRows('Sort')) |
||
78 | ); |
||
79 | |||
80 | $config = $gridField->getConfig(); |
||
81 | $paginator = $config->getComponentByType('GridFieldPaginator'); |
||
82 | $paginator->setItemsPerPage(100); |
||
83 | |||
84 | $config->removeComponentsByType('GridFieldDetailForm'); |
||
85 | $config->addComponent(new VersionedDataObjectDetailsForm()); |
||
86 | |||
87 | $fields->addFieldToTab('Root.Main', $gridField, 'Metadata'); |
||
88 | |||
89 | return $fields; |
||
90 | } |
||
91 | |||
92 | public function getAvailableTypes() { |
||
93 | if (is_array($this->owner->config()->get('allowed_elements'))) { |
||
94 | $list = $this->owner->config()->get('allowed_elements'); |
||
95 | View Code Duplication | } else { |
|
96 | $classes = ClassInfo::subclassesFor('BaseElement'); |
||
97 | $list = array(); |
||
98 | unset($classes['BaseElement']); |
||
99 | |||
100 | foreach ($classes as $class) { |
||
101 | $inst = singleton($class); |
||
102 | |||
103 | if ($inst->canCreate()) { |
||
104 | $list[$class] = singleton($class)->i18n_singular_name(); |
||
105 | } |
||
106 | } |
||
107 | } |
||
108 | if (method_exists($this->owner, 'sortElementalOptions')) { |
||
109 | $this->owner->sortElementalOptions($list); |
||
110 | } else { |
||
111 | asort($list); |
||
112 | } |
||
113 | |||
114 | return $list; |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Make sure there is always a WidgetArea sidebar for adding widgets |
||
119 | * |
||
120 | */ |
||
121 | public function onBeforeWrite() |
||
122 | { |
||
123 | // enable theme incase elements are being rendered with templates stored in theme folder |
||
124 | $originalThemeEnabled = Config::inst()->get('SSViewer', 'theme_enabled'); |
||
125 | Config::inst()->update('SSViewer', 'theme_enabled', true); |
||
126 | |||
127 | View Code Duplication | if ($ignored = Config::inst()->get('ElementPageExtension', 'ignored_classes')) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
128 | foreach ($ignored as $check) { |
||
129 | if (is_a($this->owner, $check)) { |
||
130 | return; |
||
131 | } |
||
132 | } |
||
133 | } |
||
134 | |||
135 | if ($this->owner->hasMethod('ElementArea')) { |
||
136 | $elements = $this->owner->ElementArea(); |
||
137 | |||
138 | if (!$elements->isInDB()) { |
||
139 | $elements->write(); |
||
140 | $this->owner->ElementAreaID = $elements->ID; |
||
141 | } else { |
||
142 | // Copy widgets content to Content to enable search |
||
143 | $searchableContent = array(); |
||
144 | |||
145 | foreach ($elements->Items() as $element) { |
||
146 | if ($element->config()->exclude_from_content) { |
||
147 | continue; |
||
148 | } |
||
149 | |||
150 | $controller = $element->getController(); |
||
151 | $controller->init(); |
||
152 | |||
153 | array_push($searchableContent, $controller->WidgetHolder()); |
||
154 | } |
||
155 | |||
156 | $this->owner->Content = trim(implode(' ', $searchableContent)); |
||
157 | } |
||
158 | } |
||
159 | |||
160 | |||
161 | // set theme_enabled back to what it was |
||
162 | Config::inst()->update('SSViewer', 'theme_enabled', $originalThemeEnabled); |
||
163 | |||
164 | parent::onBeforeWrite(); |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * If the page is duplicated, copy the widgets across too. |
||
169 | * Gets called twice from either direction, due to bad DataObject |
||
170 | * and SiteTree code, hence the weird if statement |
||
171 | * |
||
172 | * @return Page The duplicated page |
||
173 | */ |
||
174 | public function onAfterDuplicate($duplicatePage) |
||
175 | { |
||
176 | if ($this->owner->ID != 0 && $this->owner->ID < $duplicatePage->ID) { |
||
177 | $originalWidgetArea = $this->owner->getComponent('ElementArea'); |
||
178 | $duplicateWidgetArea = $originalWidgetArea->duplicate(false); |
||
179 | $duplicateWidgetArea->write(); |
||
180 | $duplicatePage->ElementAreaID = $duplicateWidgetArea->ID; |
||
181 | $duplicatePage->write(); |
||
182 | |||
183 | View Code Duplication | foreach ($originalWidgetArea->Items() as $originalWidget) { |
|
184 | $duplicateWidget = $originalWidget->duplicate(true); |
||
185 | |||
186 | // manually set the ParentID of each widget, so we don't get versioning issues |
||
187 | DB::query(sprintf("UPDATE Widget SET ParentID = %d WHERE ID = %d", $duplicateWidgetArea->ID, $duplicateWidget->ID)); |
||
188 | } |
||
189 | } |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * If the page is duplicated across subsites, copy the widgets across too. |
||
194 | * |
||
195 | * @return Page The duplicated page |
||
196 | */ |
||
197 | public function onAfterDuplicateToSubsite($originalPage) |
||
198 | { |
||
199 | $originalWidgetArea = $originalPage->getComponent('ElementArea'); |
||
200 | $duplicateWidgetArea = $originalWidgetArea->duplicate(false); |
||
201 | $duplicateWidgetArea->write(); |
||
202 | $this->owner->ElementAreaID = $duplicateWidgetArea->ID; |
||
203 | $this->owner->write(); |
||
204 | |||
205 | View Code Duplication | foreach ($originalWidgetArea->Items() as $originalWidget) { |
|
206 | $duplicateWidget = $originalWidget->duplicate(true); |
||
207 | |||
208 | // manually set the ParentID of each widget, so we don't get versioning issues |
||
209 | DB::query(sprintf("UPDATE Widget SET ParentID = %d WHERE ID = %d", $duplicateWidgetArea->ID, $duplicateWidget->ID)); |
||
210 | } |
||
211 | } |
||
212 | |||
213 | public function onAfterPublish() |
||
214 | { |
||
215 | if ($id = $this->owner->ElementAreaID) { |
||
216 | $widgets = Versioned::get_by_stage('BaseElement', 'Stage', "ParentID = '$id'"); |
||
217 | $staged = array(); |
||
218 | |||
219 | foreach ($widgets as $widget) { |
||
220 | $staged[] = $widget->ID; |
||
221 | |||
222 | $widget->publish('Stage', 'Live'); |
||
223 | } |
||
224 | |||
225 | // remove any elements that are on live but not in draft. |
||
226 | $widgets = Versioned::get_by_stage('BaseElement', 'Live', "ParentID = '$id'"); |
||
227 | |||
228 | foreach ($widgets as $widget) { |
||
229 | if (!in_array($widget->ID, $staged)) { |
||
230 | $widget->deleteFromStage('Live'); |
||
231 | } |
||
232 | } |
||
233 | } |
||
234 | } |
||
235 | |||
236 | /** |
||
237 | * Roll back all changes if the parent page has a rollback event |
||
238 | * |
||
239 | * Only do rollback if it's the 'cancel draft changes' rollback, not a specific version |
||
240 | * rollback. |
||
241 | * |
||
242 | * @param string $version |
||
243 | * @return null |
||
244 | */ |
||
245 | public function onBeforeRollback($version) |
||
246 | { |
||
247 | if ($version !== 'Live') { |
||
248 | // we don't yet have a smart way of rolling back to a specific version |
||
249 | return; |
||
250 | } |
||
251 | if ($id = $this->owner->ElementAreaID) { |
||
252 | $widgets = Versioned::get_by_stage('BaseElement', 'Live', "ParentID = '$id'"); |
||
253 | $staged = array(); |
||
254 | |||
255 | foreach ($widgets as $widget) { |
||
256 | $staged[] = $widget->ID; |
||
257 | |||
258 | $widget->invokeWithExtensions('onBeforeRollback', $widget); |
||
259 | |||
260 | $widget->publish("Live", "Stage", false); |
||
261 | |||
262 | $widget->invokeWithExtensions('onAfterRollback', $widget); |
||
263 | } |
||
264 | } |
||
265 | } |
||
266 | } |
||
267 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.