StaticCacheFullBuildJob   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 1
Metric Value
eloc 57
c 5
b 0
f 1
dl 0
loc 146
rs 10
wmc 24

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getTitle() 0 3 1
A getSignature() 0 3 1
A setup() 0 9 1
A processUrl() 0 12 4
A updateCompletedState() 0 11 3
B process() 0 61 10
A getAllLivePageURLs() 0 17 4
1
<?php
2
3
namespace SilverStripe\StaticPublishQueue\Job;
4
5
use SilverStripe\CMS\Model\SiteTree;
6
use SilverStripe\StaticPublishQueue\Contract\StaticallyPublishable;
7
use SilverStripe\StaticPublishQueue\Extension\Publishable\PublishableSiteTree;
8
use SilverStripe\StaticPublishQueue\Job;
9
use SilverStripe\StaticPublishQueue\Publisher;
10
use SilverStripe\Versioned\Versioned;
11
12
/**
13
 * Class StaticCacheFullBuildJob
14
 *
15
 * Adds all live pages to the queue for caching. Best implemented on a cron via StaticCacheFullBuildTask.
16
 * WARNING: this job assumes that there are not too many pages to process (dozens are fine, thousands are not)
17
 * as collecting URLs from all live pages will either eat up all available memory and / or stall
18
 * If your site has thousands of pages you need to consider a different static cache refresh solution
19
 * Ideally, the whole site re-cache would be segmented into smaller chunks and spread across different times of the day
20
 *
21
 * @property array $URLsToCleanUp
22
 * @property array $publishedURLs
23
 * @package SilverStripe\StaticPublishQueue\Job
24
 */
25
class StaticCacheFullBuildJob extends Job
26
{
27
    /**
28
     * @return string
29
     */
30
    public function getTitle()
31
    {
32
        return 'Generate static pages for all URLs';
33
    }
34
35
    /**
36
     * @return string
37
     */
38
    public function getSignature(): string
39
    {
40
        return md5(static::class);
41
    }
42
43
    public function setup(): void
44
    {
45
        parent::setup();
46
        Publisher::singleton()->purgeAll();
47
        $this->URLsToProcess = $this->getAllLivePageURLs();
48
        $this->URLsToCleanUp = [];
49
        $this->totalSteps = count($this->URLsToProcess);
50
        $this->addMessage(sprintf('Building %s URLS', count($this->URLsToProcess)));
51
        $this->addMessage(var_export(array_keys($this->URLsToProcess), true));
52
    }
53
54
    /**
55
     * Do some processing yourself!
56
     */
57
    public function process(): void
58
    {
59
        // Remove any URLs which have already been processed
60
        if ($this->ProcessedURLs) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->ProcessedURLs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
61
            $this->URLsToProcess = array_diff_key(
62
                $this->URLsToProcess,
63
                $this->ProcessedURLs
64
            );
65
        }
66
67
        $chunkSize = $this->getChunkSize();
68
        $count = 0;
69
70
        // Generate static cache for all live pages
71
        foreach ($this->URLsToProcess as $url => $priority) {
72
            $count += 1;
73
74
            if ($chunkSize > 0 && $count > $chunkSize) {
75
                return;
76
            }
77
78
            $this->processUrl($url, $priority);
79
        }
80
81
        if (count($this->URLsToProcess) === 0) {
82
            $trimSlashes = function ($value) {
83
                $value = trim($value, '/');
84
85
                // We want to trim the schema from the beginning as they map to the same place
86
                // anyway.
87
                $value = ltrim($value, 'http://');
88
                $value = ltrim($value, 'https://');
89
90
                return $value;
91
            };
92
93
            // List of all URLs which have a static cache file
94
            $this->publishedURLs = array_map($trimSlashes, Publisher::singleton()->getPublishedURLs());
95
96
            // List of all URLs which were published as a part of this job
97
            $this->ProcessedURLs = array_map($trimSlashes, $this->ProcessedURLs);
98
99
            // Determine stale URLs - those which were not published as a part of this job
100
            // but still have a static cache file
101
            $this->URLsToCleanUp = array_diff($this->publishedURLs, $this->ProcessedURLs);
102
103
            foreach ($this->URLsToCleanUp as $staleURL) {
104
                $purgeMeta = Publisher::singleton()->purgeURL($staleURL);
105
                $purgeMeta = is_array($purgeMeta) ? $purgeMeta : [];
106
107
                if (array_key_exists('success', $purgeMeta) && $purgeMeta['success']) {
108
                    unset($this->jobData->URLsToCleanUp[$staleURL]);
109
110
                    continue;
111
                }
112
113
                $this->handleFailedUrl($staleURL, $purgeMeta);
114
            }
115
        }
116
117
        $this->updateCompletedState();
118
    }
119
120
    /**
121
     * @return array
122
     */
123
    protected function getAllLivePageURLs(): array
124
    {
125
        $urls = [];
126
        $this->extend('beforeGetAllLivePageURLs', $urls);
127
        $livePages = Versioned::get_by_stage(SiteTree::class, Versioned::LIVE);
128
        foreach ($livePages as $page) {
129
            if ($page->hasExtension(PublishableSiteTree::class) || $page instanceof StaticallyPublishable) {
130
                $urls = array_merge($urls, $page->urlsToCache());
131
            }
132
        }
133
134
        $this->extend('afterGetAllLivePageURLs', $urls);
135
        // @TODO look here when integrating subsites
136
        // if (class_exists(Subsite::class)) {
137
        //     Subsite::disable_subsite_filter(true);
138
        // }
139
        return $urls;
140
    }
141
142
    /**
143
     * @param string $url
144
     * @param int $priority
145
     */
146
    protected function processUrl(string $url, int $priority): void
147
    {
148
        $meta = Publisher::singleton()->publishURL($url, true);
149
        $meta = is_array($meta) ? $meta : [];
150
151
        if (array_key_exists('success', $meta) && $meta['success']) {
152
            $this->markUrlAsProcessed($url);
153
154
            return;
155
        }
156
157
        $this->handleFailedUrl($url, $meta);
158
    }
159
160
    protected function updateCompletedState(): void
161
    {
162
        if (count($this->URLsToProcess) > 0) {
163
            return;
164
        }
165
166
        if (count($this->URLsToCleanUp) > 0) {
167
            return;
168
        }
169
170
        $this->isComplete = true;
171
    }
172
}
173