Completed
Push — master ( 59c799...149ad0 )
by Will
02:15
created

code/extensions/ElementPageExtension.php (2 issues)

Upgrade to new PHP Analysis Engine

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
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...
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