This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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\DataObjects; |
||
4 | |||
5 | use SilverStripe\Assets\Filesystem; |
||
6 | use SilverStripe\Core\Config\Config; |
||
7 | use SilverStripe\Forms\DropdownField; |
||
8 | use SilverStripe\ORM\DataObject; |
||
9 | use Symbiote\QueuedJobs\Services\QueuedJob; |
||
10 | use SilverStripe\Security\Permission; |
||
11 | |||
12 | /** |
||
13 | * A QueuedJobDescriptor is the stored representation of a piece of work that could take a while to execute, |
||
14 | * because of which it is desireable to not have it executing in parallel to other jobs. |
||
15 | * |
||
16 | * A queued job should always attempt to report how many potential dataobjects will be affected by being executed; |
||
17 | * this will determine which queue it is placed within so that some shorter jobs can execute immediately without needing |
||
18 | * to wait for a potentially long running job. |
||
19 | * |
||
20 | * @property string $JobTitle Name of job |
||
21 | * @property string $Signature Unique identifier for this job instance |
||
22 | * @property string $Implementation Classname of underlying job |
||
23 | * @property string $StartAfter Don't start until this date, if set |
||
24 | * @property string $JobStarted When this job was started |
||
25 | * @property string $JobFinished When this job was finished |
||
26 | * @property int $TotalSteps Number of steps |
||
27 | * @property int $StepsProcessed Number of completed steps |
||
28 | * @property int $LastProcessedCount Number at which StepsProcessed was last checked for stalled jobs |
||
29 | * @property int $ResumeCounts Number of times this job has been resumed |
||
30 | * @property string $SavedJobData serialised data for the job to use as storage |
||
31 | * @property string $SavedJobMessages List of messages saved for this job |
||
32 | * @property string $JobStatus Status of this job |
||
33 | * @property string $JobType Type of job |
||
34 | * |
||
35 | * @method Member RunAs() Member to run this job as |
||
36 | * |
||
37 | * @author Marcus Nyeholt <[email protected]> |
||
38 | * @license BSD http://silverstripe.org/bsd-license/ |
||
39 | */ |
||
40 | class QueuedJobDescriptor extends DataObject |
||
41 | { |
||
42 | /** |
||
43 | * {@inheritDoc} |
||
44 | * @var string |
||
45 | */ |
||
46 | private static $table_name = 'QueuedJobDescriptor'; |
||
0 ignored issues
–
show
Comprehensibility
introduced
by
![]() |
|||
47 | |||
48 | /** |
||
49 | * @var array |
||
50 | */ |
||
51 | private static $db = array( |
||
0 ignored issues
–
show
|
|||
52 | 'JobTitle' => 'Varchar(255)', |
||
53 | 'Signature' => 'Varchar(64)', |
||
54 | 'Implementation' => 'Varchar(255)', |
||
55 | 'StartAfter' => 'DBDatetime', |
||
56 | 'JobStarted' => 'DBDatetime', |
||
57 | 'JobRestarted' => 'DBDatetime', |
||
58 | 'JobFinished' => 'DBDatetime', |
||
59 | 'TotalSteps' => 'Int', |
||
60 | 'StepsProcessed' => 'Int', |
||
61 | 'LastProcessedCount' => 'Int(-1)', // -1 means never checked, 0 means checked but no work is done |
||
62 | 'ResumeCounts' => 'Int', |
||
63 | 'SavedJobData' => 'Text', |
||
64 | 'SavedJobMessages' => 'Text', |
||
65 | 'JobStatus' => 'Varchar(16)', |
||
66 | 'JobType' => 'Varchar(16)', |
||
67 | ); |
||
68 | |||
69 | /** |
||
70 | * @var array |
||
71 | */ |
||
72 | private static $has_one = array( |
||
0 ignored issues
–
show
|
|||
73 | 'RunAs' => 'SilverStripe\\Security\\Member', |
||
74 | ); |
||
75 | |||
76 | /** |
||
77 | * @var array |
||
78 | */ |
||
79 | private static $defaults = array( |
||
0 ignored issues
–
show
|
|||
80 | 'JobStatus' => 'New', |
||
81 | 'ResumeCounts' => 0, |
||
82 | 'LastProcessedCount' => -1 // -1 means never checked, 0 means checked and none were processed |
||
83 | ); |
||
84 | |||
85 | /** |
||
86 | * @var array |
||
87 | */ |
||
88 | private static $indexes = array( |
||
0 ignored issues
–
show
|
|||
89 | 'JobStatus' => true, |
||
90 | 'StartAfter' => true, |
||
91 | 'Signature' => true |
||
92 | ); |
||
93 | |||
94 | /** |
||
95 | * @var array |
||
96 | */ |
||
97 | private static $casting = array( |
||
0 ignored issues
–
show
|
|||
98 | 'Messages' => 'HTMLText' |
||
99 | ); |
||
100 | |||
101 | /** |
||
102 | * @var array |
||
103 | */ |
||
104 | private static $searchable_fields = array( |
||
0 ignored issues
–
show
|
|||
105 | 'JobTitle', |
||
106 | ); |
||
107 | |||
108 | /** |
||
109 | * @var string |
||
110 | */ |
||
111 | private static $default_sort = 'Created DESC'; |
||
0 ignored issues
–
show
|
|||
112 | |||
113 | public function requireDefaultRecords() |
||
114 | { |
||
115 | parent::requireDefaultRecords(); |
||
116 | $this->getJobDir(); |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * @return array |
||
121 | */ |
||
122 | public function summaryFields() |
||
123 | { |
||
124 | return array( |
||
125 | 'JobTitle' => _t('QueuedJobs.TABLE_TITLE', 'Title'), |
||
126 | 'Created' => _t('QueuedJobs.TABLE_ADDE', 'Added'), |
||
127 | 'JobStarted' => _t('QueuedJobs.TABLE_STARTED', 'Started'), |
||
128 | // 'JobRestarted' => _t('QueuedJobs.TABLE_RESUMED', 'Resumed'), |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
62% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
129 | 'StartAfter' => _t('QueuedJobs.TABLE_START_AFTER', 'Start After'), |
||
130 | 'JobType' => _t('QueuedJobs.JOB_TYPE', 'Job Type'), |
||
131 | 'JobStatus' => _t('QueuedJobs.TABLE_STATUS', 'Status'), |
||
132 | 'Messages' => _t('QueuedJobs.TABLE_MESSAGES', 'Message'), |
||
133 | 'StepsProcessed' => _t('QueuedJobs.TABLE_NUM_PROCESSED', 'Done'), |
||
134 | 'TotalSteps' => _t('QueuedJobs.TABLE_TOTAL', 'Total'), |
||
135 | ); |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * Pause this job, but only if it is waiting, running, or init |
||
140 | * |
||
141 | * @param bool $force Pause this job even if it's not waiting, running, or init |
||
142 | * @return bool Return true if this job was paused |
||
143 | */ |
||
144 | public function pause($force = false) |
||
145 | { |
||
146 | if ($force || in_array( |
||
147 | $this->JobStatus, |
||
148 | array(QueuedJob::STATUS_WAIT, QueuedJob::STATUS_RUN, QueuedJob::STATUS_INIT) |
||
149 | )) { |
||
150 | $this->JobStatus = QueuedJob::STATUS_PAUSED; |
||
151 | $this->write(); |
||
152 | return true; |
||
153 | } |
||
154 | return false; |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Resume this job and schedules it for execution |
||
159 | * |
||
160 | * @param bool $force Resume this job even if it's not paused or broken |
||
161 | * @return bool Return true if this job was resumed |
||
162 | */ |
||
163 | public function resume($force = false) |
||
164 | { |
||
165 | if ($force || in_array($this->JobStatus, array(QueuedJob::STATUS_PAUSED, QueuedJob::STATUS_BROKEN))) { |
||
166 | $this->JobStatus = QueuedJob::STATUS_WAIT; |
||
167 | $this->ResumeCounts++; |
||
168 | $this->write(); |
||
169 | singleton('Symbiote\\QueuedJobs\\Services\\QueuedJobService')->startJob($this); |
||
170 | return true; |
||
171 | } |
||
172 | return false; |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * Restarts this job via a forced resume |
||
177 | */ |
||
178 | public function restart() |
||
179 | { |
||
180 | $this->resume(true); |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * Called to indicate that the job is ready to be run on the queue. This is done either as the result of |
||
185 | * creating the job and adding it, or when resuming. |
||
186 | */ |
||
187 | public function activateOnQueue() |
||
188 | { |
||
189 | // if it's an immediate job, lets cache it to disk to be picked up later |
||
190 | if ($this->JobType == QueuedJob::IMMEDIATE |
||
191 | && !Config::inst()->get('Symbiote\\QueuedJobs\\Services\\QueuedJobService', 'use_shutdown_function') |
||
192 | ) { |
||
193 | touch($this->getJobDir() . '/queuedjob-' . $this->ID); |
||
194 | } |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * Gets the path to the queuedjob cache directory |
||
199 | * |
||
200 | * @return string |
||
201 | */ |
||
202 | protected function getJobDir() |
||
203 | { |
||
204 | // make sure our temp dir is in place. This is what will be inotify watched |
||
205 | $jobDir = Config::inst()->get('Symbiote\\QueuedJobs\\Services\\QueuedJobService', 'cache_dir'); |
||
206 | if ($jobDir{0} != '/') { |
||
207 | $jobDir = TEMP_FOLDER . '/' . $jobDir; |
||
208 | } |
||
209 | |||
210 | if (!is_dir($jobDir)) { |
||
211 | Filesystem::makeFolder($jobDir); |
||
212 | } |
||
213 | return $jobDir; |
||
214 | } |
||
215 | |||
216 | public function execute() |
||
217 | { |
||
218 | $service = singleton('Symbiote\\QueuedJobs\\Services\\QueuedJobService'); |
||
219 | $service->runJob($this->ID); |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * Called when the job has completed and we want to cleanup anything the descriptor has lying around |
||
224 | * in caches or the like. |
||
225 | */ |
||
226 | public function cleanupJob() |
||
227 | { |
||
228 | // remove the job's temp file if it exists |
||
229 | $tmpFile = $this->getJobDir() . '/queuedjob-' . $this->ID; |
||
230 | if (file_exists($tmpFile)) { |
||
231 | unlink($tmpFile); |
||
232 | } |
||
233 | } |
||
234 | |||
235 | public function onBeforeDelete() |
||
236 | { |
||
237 | parent::onBeforeDelete(); |
||
238 | $this->cleanupJob(); |
||
239 | } |
||
240 | |||
241 | /** |
||
242 | * @return string|void |
||
243 | */ |
||
244 | public function getMessages() |
||
245 | { |
||
246 | if (strlen($this->SavedJobMessages)) { |
||
247 | $msgs = @unserialize($this->SavedJobMessages); |
||
248 | return is_array($msgs) ? '<ul><li>'.implode('</li><li>', $msgs).'</li></ul>' : ''; |
||
249 | } |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * @return string |
||
254 | */ |
||
255 | public function getTitle() |
||
256 | { |
||
257 | return $this->JobTitle; |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * @return FieldList |
||
262 | */ |
||
263 | public function getCMSFields() |
||
264 | { |
||
265 | $fields = parent::getCMSFields(); |
||
266 | $fields->replaceField( |
||
267 | 'JobType', |
||
268 | new DropdownField('JobType', $this->fieldLabel('JobType'), array( |
||
269 | QueuedJob::IMMEDIATE => 'Immediate', |
||
270 | QueuedJob::QUEUED => 'Queued', |
||
271 | QueuedJob::LARGE => 'Large' |
||
272 | )) |
||
273 | ); |
||
274 | $statuses = array( |
||
275 | QueuedJob::STATUS_NEW, |
||
276 | QueuedJob::STATUS_INIT, |
||
277 | QueuedJob::STATUS_RUN, |
||
278 | QueuedJob::STATUS_WAIT, |
||
279 | QueuedJob::STATUS_COMPLETE, |
||
280 | QueuedJob::STATUS_PAUSED, |
||
281 | QueuedJob::STATUS_CANCELLED, |
||
282 | QueuedJob::STATUS_BROKEN |
||
283 | ); |
||
284 | $fields->replaceField( |
||
285 | 'JobStatus', |
||
286 | DropdownField::create('JobStatus', $this->fieldLabel('JobStatus'), array_combine($statuses, $statuses)) |
||
287 | ); |
||
288 | |||
289 | $fields->removeByName('SavedJobData'); |
||
290 | $fields->removeByName('SavedJobMessages'); |
||
291 | |||
292 | if (Permission::check('ADMIN')) { |
||
293 | return $fields; |
||
294 | } else { |
||
295 | // Readonly CMS view is a lot more useful for debugging than no view at all |
||
296 | return $fields->makeReadonly(); |
||
297 | } |
||
298 | } |
||
299 | } |
||
300 |