MigrateContentToElement::run()   C
last analyzed

Complexity

Conditions 12
Paths 24

Size

Total Lines 74
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 38
c 1
b 0
f 0
nc 24
nop 1
dl 0
loc 74
rs 6.9666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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