Skip to content

Commit 07bb9a7

Browse files
committed
Fix TypeError when editing queued job with invalid JSON payload
When invalid JSON is submitted via the data edit form, the JsonableBehavior threw a TypeError because json_decode returned null but the return type was array. Changes: - Update _fromJson() to throw InvalidArgumentException with a descriptive error message instead of TypeError - Catch the exception in data() action and show a flash error - Preserve the user's invalid input so they can fix it - Add data_string virtual property annotation to QueuedJob entity - Add test for invalid JSON handling - Fix PHPStan errors: handle nullable description() in example tasks
1 parent 4de7db1 commit 07bb9a7

12 files changed

Lines changed: 50 additions & 15 deletions

src/Controller/Admin/QueuedJobsController.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Cake\Http\Exception\NotFoundException;
99
use Cake\I18n\DateTime;
1010
use Cake\View\JsonView;
11+
use InvalidArgumentException;
1112
use Queue\Queue\TaskFinder;
1213
use RuntimeException;
1314

@@ -304,14 +305,21 @@ public function data(?int $id = null) {
304305
}
305306

306307
if ($this->request->is(['patch', 'post', 'put'])) {
307-
$queuedJob = $this->QueuedJobs->patchEntity($queuedJob, $this->request->getData());
308-
if ($this->QueuedJobs->save($queuedJob)) {
309-
$this->Flash->success(__d('queue', 'The queued job has been saved.'));
308+
try {
309+
$queuedJob = $this->QueuedJobs->patchEntity($queuedJob, $this->request->getData());
310+
if ($this->QueuedJobs->save($queuedJob)) {
311+
$this->Flash->success(__d('queue', 'The queued job has been saved.'));
310312

311-
return $this->redirect(['action' => 'view', $id]);
312-
}
313+
return $this->redirect(['action' => 'view', $id]);
314+
}
313315

314-
$this->Flash->error(__d('queue', 'The queued job could not be saved. Please try again.'));
316+
$this->Flash->error(__d('queue', 'The queued job could not be saved. Please try again.'));
317+
} catch (InvalidArgumentException $e) {
318+
$this->Flash->error($e->getMessage());
319+
320+
// Preserve the user's invalid input so they can fix it
321+
$queuedJob->data_string = $this->request->getData('data_string');
322+
}
315323
}
316324

317325
$this->set(compact('queuedJob'));

src/Model/Behavior/JsonableBehavior.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,15 @@ public function _decode($val) {
216216
/**
217217
* @param string $val
218218
*
219+
* @throws \InvalidArgumentException
220+
*
219221
* @return array
220222
*/
221223
protected function _fromJson(string $val): array {
222-
$json = json_decode($val, true, JSON_THROW_ON_ERROR);
224+
$json = json_decode($val, true);
225+
if (!is_array($json)) {
226+
throw new InvalidArgumentException('Invalid JSON: ' . json_last_error_msg());
227+
}
223228

224229
return $json;
225230
}

src/Model/Entity/QueuedJob.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* @property int $id
1010
* @property string $job_task
1111
* @property array|null $data
12+
* @property string|null $data_string Virtual property from JsonableBehavior
1213
* @property string|null $job_group
1314
* @property string|null $reference
1415
* @property \Cake\I18n\DateTime $created

src/Queue/Task/CostsExampleTask.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class CostsExampleTask extends Task implements AddInterface, AddFromBackendInter
3333
public function add(?string $data): void {
3434
$this->io->out('CakePHP Queue CostsExample task.');
3535
$this->io->hr();
36-
$this->io->out($this->description());
36+
$this->io->out($this->description() ?? '');
3737
$this->io->out('I will now add an example Job into the Queue.');
3838
$this->io->out(' ');
3939
$this->io->out('To run a Worker use:');

src/Queue/Task/ExampleTask.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class ExampleTask extends Task implements AddInterface, AddFromBackendInterface
3636
public function add(?string $data): void {
3737
$this->io->out('CakePHP Queue Example task.');
3838
$this->io->hr();
39-
$this->io->out($this->description());
39+
$this->io->out($this->description() ?? '');
4040
$this->io->out('I will now add an example Job into the Queue.');
4141
$this->io->out(' ');
4242
$this->io->out('To run a Worker use:');

src/Queue/Task/ExceptionExampleTask.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class ExceptionExampleTask extends Task implements AddInterface, AddFromBackendI
3232
public function add(?string $data): void {
3333
$this->io->out('CakePHP Queue ExceptionExample task.');
3434
$this->io->hr();
35-
$this->io->out($this->description());
35+
$this->io->out($this->description() ?? '');
3636
$this->io->out('I will now add an example Job into the Queue.');
3737
$this->io->out(' ');
3838
$this->io->out('To run a Worker use:');

src/Queue/Task/MonitorExampleTask.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class MonitorExampleTask extends Task implements AddInterface, AddFromBackendInt
3838
public function add(?string $data): void {
3939
$this->io->out('CakePHP Queue MonitorExample task.');
4040
$this->io->hr();
41-
$this->io->out($this->description());
41+
$this->io->out($this->description() ?? '');
4242
$this->io->out('I will now add an example Job into the Queue.');
4343
$this->io->out(' ');
4444
$this->io->out('To run a Worker use:');

src/Queue/Task/ProgressExampleTask.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class ProgressExampleTask extends Task implements AddInterface, AddFromBackendIn
3636
public function add(?string $data): void {
3737
$this->io->out('CakePHP Queue ProgressExample task.');
3838
$this->io->hr();
39-
$this->io->out($this->description());
39+
$this->io->out($this->description() ?? '');
4040
$this->io->out('I will now add the Job into the Queue.');
4141
$this->io->out(' ');
4242
$this->io->out('To run a Worker use:');

src/Queue/Task/RetryExampleTask.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public static function init(): bool {
6868
public function add(?string $data): void {
6969
$this->io->out('CakePHP Queue RetryExample task.');
7070
$this->io->hr();
71-
$this->io->out($this->description());
71+
$this->io->out($this->description() ?? '');
7272
$this->io->out('I will now add an example Job into the Queue.');
7373
$this->io->out(' ');
7474
$this->io->out('To run a Worker use:');

src/Queue/Task/SuperExampleTask.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class SuperExampleTask extends Task implements AddInterface, AddFromBackendInter
3636
public function add(?string $data): void {
3737
$this->io->out('CakePHP Queue SuperExample task.');
3838
$this->io->hr();
39-
$this->io->out($this->description());
39+
$this->io->out($this->description() ?? '');
4040
$this->io->out('I will now add an example Job into the Queue.');
4141
$this->io->out(' ');
4242
$this->io->out('To run a Worker use:');

0 commit comments

Comments
 (0)