These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Symbiote\QueuedJobs\Jobs; |
||
4 | |||
5 | use Exception; |
||
6 | use Page; |
||
7 | use SilverStripe\Control\Director; |
||
8 | use SilverStripe\Core\Environment; |
||
9 | use SilverStripe\Core\TempFolder; |
||
10 | use SilverStripe\ErrorPage\ErrorPage; |
||
11 | use SilverStripe\ORM\DB; |
||
12 | use SilverStripe\ORM\FieldType\DBDatetime; |
||
13 | use SilverStripe\Versioned\Versioned; |
||
14 | use Symbiote\QueuedJobs\Services\AbstractQueuedJob; |
||
15 | use Symbiote\QueuedJobs\Services\QueuedJob; |
||
16 | use Symbiote\QueuedJobs\Services\QueuedJobService; |
||
17 | |||
18 | /** |
||
19 | * A job for generating a site's google sitemap |
||
20 | * |
||
21 | * If the sitemap module is installed, uses information from that to populate things |
||
22 | * |
||
23 | * @author [email protected] |
||
24 | * @license http://silverstripe.org/bsd-license/ |
||
25 | */ |
||
26 | class GenerateGoogleSitemapJob extends AbstractQueuedJob |
||
27 | { |
||
28 | /** |
||
29 | * @var int |
||
30 | */ |
||
31 | private static $regenerate_time = 43200; |
||
32 | |||
33 | public function __construct() |
||
34 | { |
||
35 | $this->pagesToProcess = DB::query('SELECT ID FROM "SiteTree_Live" WHERE "ShowInSearch"=1')->column(); |
||
36 | $this->currentStep = 0; |
||
37 | $this->totalSteps = count($this->pagesToProcess); |
||
38 | } |
||
39 | |||
40 | /** |
||
41 | * Sitemap job is going to run for a while... |
||
42 | * |
||
43 | * @return int |
||
44 | */ |
||
45 | public function getJobType() |
||
46 | { |
||
47 | return QueuedJob::QUEUED; |
||
48 | } |
||
49 | |||
50 | /** |
||
51 | * @return string |
||
52 | */ |
||
53 | public function getTitle() |
||
54 | { |
||
55 | return _t(__CLASS__ . '.REGENERATE', 'Regenerate Google sitemap .xml file'); |
||
56 | } |
||
57 | |||
58 | /** |
||
59 | * Return a signature for this queued job |
||
60 | * |
||
61 | * For the generate sitemap job, we only ever want one instance running, so just use the class name |
||
62 | * |
||
63 | * @return string |
||
64 | */ |
||
65 | public function getSignature() |
||
66 | { |
||
67 | return md5(get_class($this)); |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Note that this is duplicated for backwards compatibility purposes... |
||
72 | */ |
||
73 | public function setup() |
||
74 | { |
||
75 | parent::setup(); |
||
76 | Environment::increaseTimeLimitTo(); |
||
77 | |||
78 | $restart = $this->currentStep == 0; |
||
79 | if (!$this->tempFile || !file_exists($this->tempFile)) { |
||
80 | $tmpfile = tempnam(TempFolder::getTempFolder(BASE_PATH), 'sitemap'); |
||
81 | if (file_exists($tmpfile)) { |
||
82 | $this->tempFile = $tmpfile; |
||
83 | } |
||
84 | $restart = true; |
||
85 | } |
||
86 | |||
87 | if ($restart) { |
||
88 | $this->pagesToProcess = DB::query('SELECT ID FROM SiteTree_Live WHERE ShowInSearch=1')->column(); |
||
89 | } |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * On any restart, make sure to check that our temporary file is being created still. |
||
94 | */ |
||
95 | public function prepareForRestart() |
||
96 | { |
||
97 | parent::prepareForRestart(); |
||
98 | // if the file we've been building is missing, lets fix it up |
||
99 | if (!$this->tempFile || !file_exists($this->tempFile)) { |
||
100 | $tmpfile = tempnam(TempFolder::getTempFolder(BASE_PATH), 'sitemap'); |
||
101 | if (file_exists($tmpfile)) { |
||
102 | $this->tempFile = $tmpfile; |
||
103 | } |
||
104 | $this->currentStep = 0; |
||
105 | $this->pagesToProcess = DB::query('SELECT ID FROM SiteTree_Live WHERE ShowInSearch=1')->column(); |
||
106 | } |
||
107 | } |
||
108 | |||
109 | public function process() |
||
110 | { |
||
111 | if (!$this->tempFile) { |
||
112 | throw new Exception("Temporary sitemap file has not been set"); |
||
113 | } |
||
114 | |||
115 | if (!file_exists($this->tempFile)) { |
||
116 | throw new Exception("Temporary file $this->tempFile has been deleted!"); |
||
117 | } |
||
118 | |||
119 | $remainingChildren = $this->pagesToProcess; |
||
120 | |||
121 | // if there's no more, we're done! |
||
122 | if (!count($remainingChildren)) { |
||
123 | $this->completeJob(); |
||
124 | $this->isComplete = true; |
||
125 | return; |
||
126 | } |
||
127 | |||
128 | // lets process our first item - note that we take it off the list of things left to do |
||
129 | $ID = array_shift($remainingChildren); |
||
130 | |||
131 | // get the page |
||
132 | $page = Versioned::get_by_stage(Page::class, Versioned::LIVE, '"SiteTree_Live"."ID" = '.$ID); |
||
133 | |||
134 | if (!$page || !$page->Count()) { |
||
135 | $this->addMessage("Page ID #$ID could not be found, skipping"); |
||
136 | } else { |
||
137 | $page = $page->First(); |
||
138 | } |
||
139 | |||
140 | if ($page && $page instanceof Page && !($page instanceof ErrorPage)) { |
||
0 ignored issues
–
show
|
|||
141 | if ($page->canView() && (!isset($page->Priority) || $page->Priority > 0)) { |
||
142 | /** @var DBDatetime $created */ |
||
143 | $created = $page->dbObject('Created'); |
||
144 | $now = DBDatetime::create(); |
||
145 | $now->setValue(date('Y-m-d H:i:s')); |
||
146 | $versions = $page->Version; |
||
147 | $timediff = $now->format('U') - $created->format('U'); |
||
148 | |||
149 | // Check how many revisions have been made over the lifetime of the |
||
150 | // Page for a rough estimate of it's changing frequency. |
||
151 | $period = $timediff / ($versions + 1); |
||
152 | |||
153 | if ($period > 60*60*24*365) { // > 1 year |
||
154 | $page->ChangeFreq = 'yearly'; |
||
155 | } elseif ($period > 60*60*24*30) { // > ~1 month |
||
156 | $page->ChangeFreq = 'monthly'; |
||
157 | } elseif ($period > 60*60*24*7) { // > 1 week |
||
158 | $page->ChangeFreq = 'weekly'; |
||
159 | } elseif ($period > 60*60*24) { // > 1 day |
||
160 | $page->ChangeFreq = 'daily'; |
||
161 | } elseif ($period > 60*60) { // > 1 hour |
||
162 | $page->ChangeFreq = 'hourly'; |
||
163 | } else { // < 1 hour |
||
164 | $page->ChangeFreq = 'always'; |
||
165 | } |
||
166 | |||
167 | // do the generation of the file in a temporary location |
||
168 | $content = $page->renderWith('SitemapEntry'); |
||
169 | |||
170 | $fp = fopen($this->tempFile, "a"); |
||
171 | if (!$fp) { |
||
172 | throw new Exception("Could not open $this->tempFile for writing"); |
||
173 | } |
||
174 | fputs($fp, $content, strlen($content)); |
||
175 | fclose($fp); |
||
176 | } |
||
177 | } |
||
178 | |||
179 | // and now we store the new list of remaining children |
||
180 | $this->pagesToProcess = $remainingChildren; |
||
181 | $this->currentStep++; |
||
182 | |||
183 | if (!count($remainingChildren)) { |
||
184 | $this->completeJob(); |
||
185 | $this->isComplete = true; |
||
186 | return; |
||
187 | } |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * Outputs the completed file to the site's webroot |
||
192 | */ |
||
193 | protected function completeJob() |
||
194 | { |
||
195 | $content = '<?xml version="1.0" encoding="UTF-8"?>' . |
||
196 | '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'; |
||
197 | $content .= file_get_contents($this->tempFile); |
||
198 | $content .= '</urlset>'; |
||
199 | |||
200 | $sitemap = Director::baseFolder() .'/sitemap.xml'; |
||
201 | |||
202 | file_put_contents($sitemap, $content); |
||
203 | |||
204 | if (file_exists($this->tempFile)) { |
||
205 | unlink($this->tempFile); |
||
206 | } |
||
207 | |||
208 | $nextgeneration = new GenerateGoogleSitemapJob(); |
||
209 | singleton(QueuedJobService::class)->queueJob($nextgeneration, date('Y-m-d H:i:s', time() + self::$regenerate_time)); |
||
210 | } |
||
211 | } |
||
212 |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.