Passed
Pull Request — master (#130)
by
unknown
03:21
created

StaticCacheFullBuildJob::processUrl()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 6
nc 4
nop 2
dl 0
loc 12
rs 10
c 1
b 0
f 0
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
        $this->URLsToProcess = $this->getAllLivePageURLs();
47
        $this->URLsToCleanUp = [];
48
        $this->totalSteps = count($this->URLsToProcess);
49
        $this->addMessage(sprintf('Building %s URLS', count($this->URLsToProcess)));
50
        $this->addMessage(var_export(array_keys($this->URLsToProcess), true));
51
    }
52
53
    /**
54
     * Do some processing yourself!
55
     */
56
    public function process(): void
57
    {
58
        // Remove any URLs which have already been processed
59
        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...
60
            $this->URLsToProcess = array_diff_key(
61
                $this->URLsToProcess,
62
                $this->ProcessedURLs
63
            );
64
        }
65
66
        $chunkSize = $this->getChunkSize();
67
        $count = 0;
68
69
        // Generate static cache for all live pages
70
        foreach ($this->URLsToProcess as $url => $priority) {
71
            $count += 1;
72
73
            if ($chunkSize > 0 && $count > $chunkSize) {
74
                return;
75
            }
76
77
            $this->processUrl($url, $priority);
78
        }
79
80
        if (count($this->URLsToProcess) === 0) {
81
            $trimSlashes = function ($value) {
82
                return trim($value, '/');
83
            };
84
85
            // List of all URLs which have a static cache file
86
            $this->publishedURLs = array_map($trimSlashes, Publisher::singleton()->getPublishedURLs());
87
88
            // List of all URLs which were published as a part of this job
89
            $this->ProcessedURLs = array_map($trimSlashes, $this->ProcessedURLs);
90
91
            // Determine stale URLs - those which were not published as a part of this job
92
            // but still have a static cache file
93
            $this->URLsToCleanUp = array_diff($this->publishedURLs, $this->ProcessedURLs);
94
95
            foreach ($this->URLsToCleanUp as $staleURL) {
96
                $purgeMeta = Publisher::singleton()->purgeURL($staleURL);
97
                $purgeMeta = (is_array($purgeMeta)) ? $purgeMeta : [];
98
99
                if (array_key_exists('success', $purgeMeta) && $purgeMeta['success']) {
100
                    unset($this->jobData->URLsToCleanUp[$staleURL]);
101
102
                    continue;
103
                }
104
105
                $this->handleFailedUrl($staleURL, $purgeMeta);
106
            }
107
        }
108
109
        $this->updateCompletedState();
110
    }
111
112
    /**
113
     * @return array
114
     */
115
    protected function getAllLivePageURLs(): array
116
    {
117
        $urls = [];
118
        $this->extend('beforeGetAllLivePageURLs', $urls);
119
        $livePages = Versioned::get_by_stage(SiteTree::class, Versioned::LIVE);
120
        foreach ($livePages as $page) {
121
            if ($page->hasExtension(PublishableSiteTree::class) || $page instanceof StaticallyPublishable) {
122
                $urls = array_merge($urls, $page->urlsToCache());
123
            }
124
        }
125
126
        $this->extend('afterGetAllLivePageURLs', $urls);
127
        // @TODO look here when integrating subsites
128
        // if (class_exists(Subsite::class)) {
129
        //     Subsite::disable_subsite_filter(true);
130
        // }
131
        return $urls;
132
    }
133
134
    /**
135
     * @param string $url
136
     * @param int $priority
137
     */
138
    protected function processUrl(string $url, int $priority): void
139
    {
140
        $meta = Publisher::singleton()->publishURL($url, true);
141
        $meta = (is_array($meta)) ? $meta : [];
142
143
        if (array_key_exists('success', $meta) && $meta['success']) {
144
            $this->markUrlAsProcessed($url);
145
146
            return;
147
        }
148
149
        $this->handleFailedUrl($url, $meta);
150
    }
151
152
    protected function updateCompletedState(): void
153
    {
154
        if (count($this->URLsToProcess) > 0) {
155
            return;
156
        }
157
158
        if (count($this->URLsToCleanUp) > 0) {
159
            return;
160
        }
161
162
        $this->isComplete = true;
163
    }
164
}
165