Passed
Pull Request — master (#132)
by
unknown
04:04
created

onAfterPublishRecursive()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 2
nop 1
dl 0
loc 21
rs 9.9
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\StaticPublishQueue\Extension\Engine;
4
5
use SilverStripe\CMS\Model\SiteTree;
6
use SilverStripe\CMS\Model\SiteTreeExtension;
7
use SilverStripe\Core\Environment;
8
use SilverStripe\Core\Injector\Injector;
9
use SilverStripe\Core\Resettable;
10
use SilverStripe\ORM\ValidationException;
11
use SilverStripe\StaticPublishQueue\Contract\StaticPublishingTrigger;
12
use SilverStripe\StaticPublishQueue\Extension\Publishable\PublishableSiteTree;
13
use SilverStripe\StaticPublishQueue\Job\DeleteStaticCacheJob;
14
use SilverStripe\StaticPublishQueue\Job\GenerateStaticCacheJob;
15
use SilverStripe\StaticPublishQueue\Service\UrlBundleInterface;
16
use Symbiote\QueuedJobs\Services\QueuedJobService;
17
18
/**
19
 * This extension couples to the StaticallyPublishable and StaticPublishingTrigger implementations
20
 * on the SiteTree objects and makes sure the actual change to SiteTree is triggered/enqueued.
21
 *
22
 * Provides the following information as a context to StaticPublishingTrigger:
23
 * * action - name of the executed action: publish or unpublish
24
 *
25
 * @see PublishableSiteTree
26
 */
27
class SiteTreePublishingEngine extends SiteTreeExtension implements Resettable
28
{
29
    /**
30
     * Queued job service injection property
31
     * Used for unit tests only to cover edge cases where Injector doesn't cover
32
     *
33
     * @var QueuedJobService|null
34
     */
35
    protected static $queueService = null;
36
37
    /**
38
     * Queues the urls to be flushed into the queue.
39
     *
40
     * @var array
41
     */
42
    private $toUpdate = [];
43
44
    /**
45
     * Queues the urls to be deleted as part of a next flush operation.
46
     *
47
     * @var array
48
     */
49
    private $toDelete = [];
50
51
    public static function reset(): void
52
    {
53
        static::$queueService = null;
54
    }
55
56
    /**
57
     * Force inject queue service
58
     * Used for unit tests only to cover edge cases where Injector doesn't cover
59
     *
60
     *
61
     * @param QueuedJobService $service
62
     */
63
    public static function setQueueService(QueuedJobService $service): void
64
    {
65
        static::$queueService = $service;
66
    }
67
68
    /**
69
     * @return array
70
     */
71
    public function getToUpdate()
72
    {
73
        return $this->toUpdate;
74
    }
75
76
    /**
77
     * @return array
78
     */
79
    public function getToDelete()
80
    {
81
        return $this->toDelete;
82
    }
83
84
    /**
85
     * @param array $toUpdate
86
     * @return $this
87
     */
88
    public function setToUpdate($toUpdate)
89
    {
90
        $this->toUpdate = $toUpdate;
91
        return $this;
92
    }
93
94
    /**
95
     * @param array $toDelete
96
     * @return $this
97
     */
98
    public function setToDelete($toDelete)
99
    {
100
        $this->toDelete = $toDelete;
101
        return $this;
102
    }
103
104
    /**
105
     * @param SiteTree|SiteTreePublishingEngine|null $original
106
     * @throws ValidationException
107
     */
108
    public function onAfterPublishRecursive(&$original)
109
    {
110
        // If the site tree has been "reorganised" (ie: the parentID has changed)
111
        // then this is the equivalent of an un-publish and publish as far as the
112
        // static publisher is concerned
113
        if ($original && (
114
            (int) $original->ParentID !== (int) $this->getOwner()->ParentID
0 ignored issues
show
Bug Best Practice introduced by
The property ParentID does not exist on SilverStripe\StaticPubli...iteTreePublishingEngine. Did you maybe forget to declare it?
Loading history...
115
                || $original->URLSegment !== $this->getOwner()->URLSegment
0 ignored issues
show
Bug Best Practice introduced by
The property URLSegment does not exist on SilverStripe\StaticPubli...iteTreePublishingEngine. Did you maybe forget to declare it?
Loading history...
116
            )
117
        ) {
118
            $context = [
119
                'action' => 'unpublish',
120
            ];
121
            $original->collectChanges($context);
122
            $original->flushChanges();
123
        }
124
        $context = [
125
            'action' => 'publish',
126
        ];
127
        $this->collectChanges($context);
128
        $this->flushChanges();
129
    }
130
131
    public function onBeforeUnpublish()
132
    {
133
        $context = [
134
            'action' => 'unpublish',
135
        ];
136
        $this->collectChanges($context);
137
    }
138
139
    /**
140
     * @throws ValidationException
141
     */
142
    public function onAfterUnpublish()
143
    {
144
        $this->flushChanges();
145
    }
146
147
    /**
148
     * Collect all changes for the given context.
149
     *
150
     * @param array $context
151
     */
152
    public function collectChanges($context)
153
    {
154
        Environment::increaseMemoryLimitTo();
155
        Environment::increaseTimeLimitTo();
156
157
        if ($this->getOwner()->hasExtension(PublishableSiteTree::class)
158
            || $this->getOwner() instanceof StaticPublishingTrigger
159
        ) {
160
            $toUpdate = $this->getOwner()->objectsToUpdate($context);
161
            $this->setToUpdate($toUpdate);
162
163
            $toDelete = $this->getOwner()->objectsToDelete($context);
164
            $this->setToDelete($toDelete);
165
        }
166
    }
167
168
    /**
169
     * Execute URL deletions, enqueue URL updates.
170
     * @throws ValidationException
171
     */
172
    public function flushChanges()
173
    {
174
        $queueService = static::$queueService ?? QueuedJobService::singleton();
175
176
        if (count($this->toUpdate) > 0) {
177
            /** @var UrlBundleInterface $urlService */
178
            $urlService = Injector::inst()->create(UrlBundleInterface::class);
179
180
            foreach ($this->toUpdate as $item) {
181
                $urls = $item->urlsToCache();
182
                ksort($urls);
183
                $urls = array_keys($urls);
184
                $urlService->addUrls($urls);
185
            }
186
187
            $jobs = $urlService->getJobsForUrls(GenerateStaticCacheJob::class, 'Building URLs', $this->owner);
188
189
            foreach ($jobs as $job) {
190
                $queueService->queueJob($job);
191
            }
192
193
            $this->toUpdate = [];
194
        }
195
196
        if (count($this->toDelete) > 0) {
197
            /** @var UrlBundleInterface $urlService */
198
            $urlService = Injector::inst()->create(UrlBundleInterface::class);
199
200
            foreach ($this->toDelete as $item) {
201
                $urls = $item->urlsToCache();
202
                ksort($urls);
203
                $urls = array_keys($urls);
204
                $urlService->addUrls($urls);
205
            }
206
207
            $jobs = $urlService->getJobsForUrls(DeleteStaticCacheJob::class, 'Purging URLs', $this->owner);
208
209
            foreach ($jobs as $job) {
210
                $queueService->queueJob($job);
211
            }
212
213
            $this->toDelete = [];
214
        }
215
    }
216
}
217