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

code/extensions/ElementPageExtension.php (1 issue)

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')) {
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() {
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
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')) {
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