Passed
Pull Request — master (#652)
by Guy
03:36
created

MigrateContentToElement::getAreaRelationFromPage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace DNADesign\Elemental\Tasks;
4
5
use DNADesign\Elemental\Extensions\ElementalAreasExtension;
6
use DNADesign\Elemental\Extensions\ElementalPageExtension;
7
use DNADesign\Elemental\Models\BaseElement;
8
use DNADesign\Elemental\Models\ElementalArea;
9
use DNADesign\Elemental\Models\ElementContent;
10
use SilverStripe\CMS\Model\SiteTree;
11
use SilverStripe\Core\Injector\Injector;
12
use SilverStripe\Dev\BuildTask;
13
use SilverStripe\Versioned\Versioned;
14
15
class MigrateContentToElement extends BuildTask
16
{
17
    /**
18
     * Configures if the existing content should be left blank.
19
     *
20
     * @config
21
     * @var bool
22
     */
23
    private static $clear_content = true;
0 ignored issues
show
introduced by
The private property $clear_content is not used, and could be removed.
Loading history...
24
25
    /**
26
     * The FQN of an element that will be the target of the content
27
     *
28
     * @config
29
     * @var string
30
     */
31
    private static $target_element = ElementContent::class;
0 ignored issues
show
introduced by
The private property $target_element is not used, and could be removed.
Loading history...
32
33
    /**
34
     * The name of the field on the `target_element` where the content should be placed
35
     *
36
     * @config
37
     * @var string
38
     */
39
    private static $target_element_field = 'HTML';
0 ignored issues
show
introduced by
The private property $target_element_field is not used, and could be removed.
Loading history...
40
41
    /**
42
     * Indicates that the updated page and elements should be immediately published (provided the Versioned extension
43
     * is present)
44
     *
45
     * @config
46
     * @var bool
47
     */
48
    private static $publish_changes = true;
0 ignored issues
show
introduced by
The private property $publish_changes is not used, and could be removed.
Loading history...
49
50
    protected $title = 'MigrateContentToElement';
51
52
    protected $description = 'When installing Elemental this task converts content in the $Content '
53
        . 'field to an ElementContent';
54
55
    public function run($request)
56
    {
57
        $pageTypes = singleton(ElementalArea::class)->supportedPageTypes();
58
        $count = 0;
59
        foreach ($pageTypes as $pageType) {
60
            // Only pages that have the ElementalPageExtension have a known ElementalArea relation
61
            if (!$this->isMigratable($pageType)) {
62
                continue;
63
            }
64
65
            $pages = $pageType::get()->filter('Content:not', ['', null]);;
66
            $clearContent = $this->config()->get('clear_content');
67
68
            $this->extend('updatePageFilter', $pages, $pageType);
69
            $pageTypeCount = 0;
70
71
            /** @var SiteTree&ElementalAreasExtension $page */
72
            foreach ($pages as $page) {
73
                if ($this->shouldSkipMigration($page)) {
74
                    continue;
75
                }
76
                // Fetch and clear existing content (if configured)
77
                $content = $page->Content;
78
                if ($clearContent) {
79
                    $page->Content = '';
80
                }
81
82
                // Get the area
83
                $area = $this->getAreaRelationFromPage($page);
84
85
                // Write the page if we're clearing content or if the area doesn't exist - we write to trigger a
86
                // relationship update
87
                if ($clearContent || !$area->exists()) {
88
                    $page->write();
89
90
                    if (!$area->exists()) {
91
                        $area = $this->getAreaRelationFromPage($page);
92
                    }
93
                }
94
95
                // Create a new element
96
                /** @var BaseElement $element */
97
                $element = Injector::inst()->create($this->config()->get('target_element'));
98
                $element->Title = 'Auto migrated content';
99
100
                // Set the configured field
101
                $element->setField($this->config()->get('target_element_field'), $content);
102
103
                // Provide an extension hook for further updates to the new element
104
                $this->extend('updateMigratedElement', $element);
105
106
                // Add and write to the area
107
                $area->Elements()->add($element);
108
109
                // Publish the record if configured
110
                if ($this->config()->get('publish_changes')) {
111
                    $page->publishRecursive();
112
                }
113
114
                $pageTypeCount++;
115
            }
116
            $count += $pageTypeCount;
117
            echo 'Migrated ' . $pageTypeCount . ' ' . $pageType . ' pages\' content<br>';
118
        }
119
        echo 'Finished migrating ' . $count . ' pages\' content<br>';
120
    }
121
122
    /**
123
     * Indicates if the given page type is migratable
124
     *
125
     * @param string|SiteTree $pageType
126
     * @return bool
127
     */
128
    protected function isMigratable($pageType)
129
    {
130
        $migratable = SiteTree::has_extension($pageType, ElementalPageExtension::class);
131
132
        $this->extend('updateIsMigratable', $migratable, $pageType);
133
134
        return $migratable;
135
    }
136
137
    /**
138
     * Extracts the relevant ElementalArea from the given page. This can be overloaded for custom page types that might
139
     * prefer an alternate area to hold the migrated content
140
     *
141
     * @param SiteTree&ElementalPageExtension $page
142
     * @return ElementalArea
143
     */
144
    protected function getAreaRelationFromPage(SiteTree $page)
145
    {
146
        return $page->ElementalArea;
147
    }
148
149
    /**
150
     * Assert that the given page should actually have content migrated. By default this asserts that no elements
151
     * currently exist IFF the "clear_content" config is on
152
     *
153
     * @param SiteTree $page
154
     * @return bool
155
     */
156
    protected function shouldSkipMigration(SiteTree $page)
157
    {
158
        $skip = !$this->config()->get('clear_content')
159
            && $this->getAreaRelationFromPage($page)->Elements()->count() > 0;
160
161
        $this->extend('updatePageShouldSkip', $skip, $page);
162
163
        return $skip;
164
    }
165
}
166