From fe1ff9aba90936028ae9b4e6bc4867e86785fda0 Mon Sep 17 00:00:00 2001 From: Jose Postiga Date: Sun, 2 Feb 2025 17:48:36 +0000 Subject: [PATCH 1/4] fix: Ensure batched jobs are actually batchable --- src/Illuminate/Bus/PendingBatch.php | 17 +++++++++++------ tests/Bus/BusPendingBatchTest.php | 9 +++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Bus/PendingBatch.php b/src/Illuminate/Bus/PendingBatch.php index 56297bc80e0d..0cd593fab4c0 100644 --- a/src/Illuminate/Bus/PendingBatch.php +++ b/src/Illuminate/Bus/PendingBatch.php @@ -49,14 +49,14 @@ class PendingBatch /** * Create a new pending batch instance. * - * @param \Illuminate\Contracts\Container\Container $container - * @param \Illuminate\Support\Collection $jobs * @return void */ public function __construct(Container $container, Collection $jobs) { $this->container = $container; - $this->jobs = $jobs; + $this->jobs = $jobs->each(function ($job) { + $this->checkJobIsBatchable($job); + }); } /** @@ -70,6 +70,7 @@ public function add($jobs) $jobs = is_iterable($jobs) ? $jobs : Arr::wrap($jobs); foreach ($jobs as $job) { + $this->checkJobIsBatchable($job); $this->jobs->push($job); } @@ -227,7 +228,6 @@ public function allowsFailures() /** * Set the name for the batch. * - * @param string $name * @return $this */ public function name(string $name) @@ -240,7 +240,6 @@ public function name(string $name) /** * Specify the queue connection that the batched jobs should run on. * - * @param string $connection * @return $this */ public function onConnection(string $connection) @@ -286,7 +285,6 @@ public function queue() /** * Add additional data into the batch's options array. * - * @param string $key * @param mixed $value * @return $this */ @@ -414,4 +412,11 @@ protected function store($repository) return $batch; } + + private function checkJobIsBatchable($job): void + { + if (! in_array(Batchable::class, class_uses_recursive($job))) { + throw new \RuntimeException(sprintf('Job %s must use Batchable trait', $job::class)); + } + } } diff --git a/tests/Bus/BusPendingBatchTest.php b/tests/Bus/BusPendingBatchTest.php index d5b9bd8d9ea7..d0398da85e69 100644 --- a/tests/Bus/BusPendingBatchTest.php +++ b/tests/Bus/BusPendingBatchTest.php @@ -222,4 +222,13 @@ public function test_batch_before_event_is_called() $this->assertTrue($beforeCalled); } + + public function test_it_throws_exception_if_batched_job_is_not_batchable(): void + { + $nonBatchableJob = new class {}; + + $this->expectException(RuntimeException::class); + + new PendingBatch(new Container, new Collection([$nonBatchableJob])); + } } From 192a9cfb642d2b8a6238408d21835aad969e288f Mon Sep 17 00:00:00 2001 From: Jose Postiga Date: Sun, 2 Feb 2025 18:24:52 +0000 Subject: [PATCH 2/4] fix: Handle deeply nested PendingBatch instances --- src/Illuminate/Bus/PendingBatch.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Bus/PendingBatch.php b/src/Illuminate/Bus/PendingBatch.php index 0cd593fab4c0..6cef362cc018 100644 --- a/src/Illuminate/Bus/PendingBatch.php +++ b/src/Illuminate/Bus/PendingBatch.php @@ -54,7 +54,7 @@ class PendingBatch public function __construct(Container $container, Collection $jobs) { $this->container = $container; - $this->jobs = $jobs->each(function ($job) { + $this->jobs = $jobs->each(function (object|array $job) { $this->checkJobIsBatchable($job); }); } @@ -413,10 +413,18 @@ protected function store($repository) return $batch; } - private function checkJobIsBatchable($job): void + private function checkJobIsBatchable(object|array $job): void { - if (! in_array(Batchable::class, class_uses_recursive($job))) { - throw new \RuntimeException(sprintf('Job %s must use Batchable trait', $job::class)); + + foreach (Arr::wrap($job) as $job) { + if ($job instanceof PendingBatch) { + $this->checkJobIsBatchable($job->jobs->all()); + return; + } + + if (! in_array(Batchable::class, class_uses_recursive($job))) { + throw new \RuntimeException(sprintf('Job %s must use Batchable trait', $job::class)); + } } } } From f90205dcca0e10c093cfe2c935cc350b3dd64474 Mon Sep 17 00:00:00 2001 From: Jose Postiga Date: Sun, 2 Feb 2025 18:26:01 +0000 Subject: [PATCH 3/4] style: Fix --- src/Illuminate/Bus/PendingBatch.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Bus/PendingBatch.php b/src/Illuminate/Bus/PendingBatch.php index 6cef362cc018..f34504872c74 100644 --- a/src/Illuminate/Bus/PendingBatch.php +++ b/src/Illuminate/Bus/PendingBatch.php @@ -415,7 +415,6 @@ protected function store($repository) private function checkJobIsBatchable(object|array $job): void { - foreach (Arr::wrap($job) as $job) { if ($job instanceof PendingBatch) { $this->checkJobIsBatchable($job->jobs->all()); From 8bdd39c5123dd5252a7515a61d1f9028e8b707fe Mon Sep 17 00:00:00 2001 From: Jose Postiga Date: Sun, 2 Feb 2025 18:31:15 +0000 Subject: [PATCH 4/4] style: Fix --- src/Illuminate/Bus/PendingBatch.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Bus/PendingBatch.php b/src/Illuminate/Bus/PendingBatch.php index f34504872c74..654c83ac334a 100644 --- a/src/Illuminate/Bus/PendingBatch.php +++ b/src/Illuminate/Bus/PendingBatch.php @@ -418,6 +418,7 @@ private function checkJobIsBatchable(object|array $job): void foreach (Arr::wrap($job) as $job) { if ($job instanceof PendingBatch) { $this->checkJobIsBatchable($job->jobs->all()); + return; }