1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SilverStripe\StaticPublishQueue\Extension\Engine; |
4
|
|
|
|
5
|
|
|
use SilverStripe\CMS\Model\SiteTreeExtension; |
6
|
|
|
use SilverStripe\Core\Environment; |
7
|
|
|
use SilverStripe\Core\Injector\Injector; |
8
|
|
|
use SilverStripe\StaticPublishQueue\Contract\StaticPublishingTrigger; |
9
|
|
|
use SilverStripe\StaticPublishQueue\Extension\Publishable\PublishableSiteTree; |
10
|
|
|
use SilverStripe\StaticPublishQueue\Job\DeleteStaticCacheJob; |
11
|
|
|
use SilverStripe\StaticPublishQueue\Job\GenerateStaticCacheJob; |
12
|
|
|
use Symbiote\QueuedJobs\Services\QueuedJobService; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* This extension couples to the StaticallyPublishable and StaticPublishingTrigger implementations |
16
|
|
|
* on the SiteTree objects and makes sure the actual change to SiteTree is triggered/enqueued. |
17
|
|
|
* |
18
|
|
|
* Provides the following information as a context to StaticPublishingTrigger: |
19
|
|
|
* * action - name of the executed action: publish or unpublish |
20
|
|
|
* |
21
|
|
|
* @see PublishableSiteTree |
22
|
|
|
*/ |
23
|
|
|
class SiteTreePublishingEngine extends SiteTreeExtension |
24
|
|
|
{ |
25
|
|
|
/** |
26
|
|
|
* Queues the urls to be flushed into the queue. |
27
|
|
|
* |
28
|
|
|
* @var array |
29
|
|
|
*/ |
30
|
|
|
private $toUpdate = []; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Queues the urls to be deleted as part of a next flush operation. |
34
|
|
|
* |
35
|
|
|
* @var array |
36
|
|
|
*/ |
37
|
|
|
private $toDelete = []; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @return array |
41
|
|
|
*/ |
42
|
|
|
public function getToUpdate() |
43
|
|
|
{ |
44
|
|
|
return $this->toUpdate; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @return array |
49
|
|
|
*/ |
50
|
|
|
public function getToDelete() |
51
|
|
|
{ |
52
|
|
|
return $this->toDelete; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @param array $toUpdate |
57
|
|
|
* @return $this |
58
|
|
|
*/ |
59
|
|
|
public function setToUpdate($toUpdate) |
60
|
|
|
{ |
61
|
|
|
$this->toUpdate = $toUpdate; |
62
|
|
|
return $this; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @param array $toDelete |
67
|
|
|
* @return $this |
68
|
|
|
*/ |
69
|
|
|
public function setToDelete($toDelete) |
70
|
|
|
{ |
71
|
|
|
$this->toDelete = $toDelete; |
72
|
|
|
return $this; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @param \SilverStripe\CMS\Model\SiteTree|null $original |
77
|
|
|
*/ |
78
|
|
|
public function onAfterPublishRecursive(&$original) |
79
|
|
|
{ |
80
|
|
|
// if the site tree has been "reorganised" (ie: the parentID has changed) |
81
|
|
|
// then this is eht equivalent of an unpublish and publish as far as the |
82
|
|
|
// static publisher is concerned |
83
|
|
|
if ($original && ( |
84
|
|
|
$original->ParentID !== $this->getOwner()->ParentID |
85
|
|
|
|| $original->URLSegment !== $this->getOwner()->URLSegment |
86
|
|
|
) |
87
|
|
|
) { |
88
|
|
|
$context = [ |
89
|
|
|
'action' => 'unpublish', |
90
|
|
|
]; |
91
|
|
|
$original->collectChanges($context); |
92
|
|
|
$original->flushChanges(); |
93
|
|
|
} |
94
|
|
|
$context = [ |
95
|
|
|
'action' => 'publish', |
96
|
|
|
]; |
97
|
|
|
$this->collectChanges($context); |
98
|
|
|
$this->flushChanges(); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
public function onBeforeUnpublish() |
102
|
|
|
{ |
103
|
|
|
$context = [ |
104
|
|
|
'action' => 'unpublish', |
105
|
|
|
]; |
106
|
|
|
$this->collectChanges($context); |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
public function onAfterUnpublish() |
110
|
|
|
{ |
111
|
|
|
return; |
112
|
|
|
$this->flushChanges(); |
|
|
|
|
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Collect all changes for the given context. |
117
|
|
|
* |
118
|
|
|
* @param array $context |
119
|
|
|
*/ |
120
|
|
|
public function collectChanges($context) |
121
|
|
|
{ |
122
|
|
|
Environment::increaseMemoryLimitTo(); |
123
|
|
|
Environment::increaseTimeLimitTo(); |
124
|
|
|
|
125
|
|
|
if ($this->getOwner()->hasExtension(PublishableSiteTree::class) |
126
|
|
|
|| $this->getOwner() instanceof StaticPublishingTrigger |
127
|
|
|
) { |
128
|
|
|
$toUpdate = $this->getOwner()->objectsToUpdate($context); |
129
|
|
|
$this->setToUpdate($toUpdate); |
130
|
|
|
|
131
|
|
|
$toDelete = $this->getOwner()->objectsToDelete($context); |
132
|
|
|
$this->setToDelete($toDelete); |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Execute URL deletions, enqueue URL updates. |
138
|
|
|
*/ |
139
|
|
|
public function flushChanges() |
140
|
|
|
{ |
141
|
|
|
$queue = QueuedJobService::singleton(); |
142
|
|
|
echo get_class($queue); |
143
|
|
|
if (!empty($this->toUpdate)) { |
144
|
|
|
foreach ($this->toUpdate as $queueItem) { |
145
|
|
|
$job = Injector::inst()->create(GenerateStaticCacheJob::class); |
146
|
|
|
|
147
|
|
|
$jobData = new \stdClass(); |
148
|
|
|
$urls = $queueItem->urlsToCache(); |
149
|
|
|
ksort($urls); |
150
|
|
|
$jobData->URLsToProcess = $urls; |
151
|
|
|
|
152
|
|
|
$job->setJobData(0, 0, false, $jobData, [ |
153
|
|
|
'Building URLs: ' . var_export(array_keys($jobData->URLsToProcess), true), |
154
|
|
|
]); |
155
|
|
|
|
156
|
|
|
$queue->queueJob($job); |
157
|
|
|
} |
158
|
|
|
$this->toUpdate = []; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
if (!empty($this->toDelete)) { |
162
|
|
|
foreach ($this->toDelete as $queueItem) { |
163
|
|
|
$job = Injector::inst()->create(DeleteStaticCacheJob::class); |
164
|
|
|
|
165
|
|
|
$jobData = new \stdClass(); |
166
|
|
|
$urls = $queueItem->urlsToCache(); |
167
|
|
|
ksort($urls); |
168
|
|
|
$jobData->URLsToProcess = $urls; |
169
|
|
|
|
170
|
|
|
$job->setJobData(0, 0, false, $jobData, [ |
171
|
|
|
'Purging URLs: ' . var_export(array_keys($jobData->URLsToProcess), true), |
172
|
|
|
]); |
173
|
|
|
|
174
|
|
|
$queue->queueJob($job); |
175
|
|
|
} |
176
|
|
|
$this->toDelete = []; |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
} |
180
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.