Passed
Pull Request — master (#652)
by Guy
05:00
created

MigrateContentToElement::shouldSkipMigration()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
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 cleared once the migration task has completed.
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, and the page was previously in a published state)
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
                $pageIsLive = $page->isPublished();
79
                if ($clearContent) {
80
                    $page->Content = '';
81
                }
82
83
                // Get the area
84
                $area = $this->getAreaRelationFromPage($page);
85
86
                // Write the page if we're clearing content or if the area doesn't exist - we write to trigger a
87
                // relationship update
88
                if ($clearContent || !$area->exists()) {
89
                    $page->write();
90
91
                    if (!$area->exists()) {
92
                        $area = $this->getAreaRelationFromPage($page);
93
                    }
94
                }
95
96
                // Create a new element
97
                /** @var BaseElement $element */
98
                $element = Injector::inst()->create($this->config()->get('target_element'));
99
                $element->Title = 'Auto migrated content';
100
101
                // Set the configured field
102
                $element->setField($this->config()->get('target_element_field'), $content);
103
104
                // Provide an extension hook for further updates to the new element
105
                $this->extend('updateMigratedElement', $element, $content, $page);
106
107
                // Add and write to the area
108
                $area->Elements()->add($element);
109
110
                // Publish the record if configured
111
                if ($this->config()->get('publish_changes') && $pageIsLive) {
112
                    $page->publishRecursive();
113
                }
114
115
                $pageTypeCount++;
116
            }
117
            $count += $pageTypeCount;
118
            echo 'Migrated ' . $pageTypeCount . ' ' . $pageType . ' pages\' content<br>';
119
        }
120
        echo 'Finished migrating ' . $count . ' pages\' content<br>';
121
    }
122
123
    /**
124
     * Indicates if the given page type is migratable
125
     *
126
     * @param string|SiteTree $pageType
127
     * @return bool
128
     */
129
    protected function isMigratable($pageType)
130
    {
131
        $migratable = SiteTree::has_extension($pageType, ElementalPageExtension::class);
132
133
        $this->extend('updateIsMigratable', $migratable, $pageType);
134
135
        return $migratable;
136
    }
137
138
    /**
139
     * Extracts the relevant ElementalArea from the given page. This can be overloaded for custom page types that might
140
     * prefer an alternate area to hold the migrated content
141
     *
142
     * @param SiteTree&ElementalPageExtension $page
143
     * @return ElementalArea
144
     */
145
    protected function getAreaRelationFromPage(SiteTree $page)
146
    {
147
        return $page->ElementalArea;
148
    }
149
150
    /**
151
     * Assert that the given page should actually have content migrated. By default this asserts that no elements
152
     * currently exist IFF the "clear_content" config is on
153
     *
154
     * @param SiteTree $page
155
     * @return bool
156
     */
157
    protected function shouldSkipMigration(SiteTree $page)
158
    {
159
        $skip = !$this->config()->get('clear_content')
160
            && $this->getAreaRelationFromPage($page)->Elements()->count() > 0;
161
162
        $this->extend('updatePageShouldSkip', $skip, $page);
163
164
        return $skip;
165
    }
166
}
167