diff --git a/src/Illuminate/Bus/Queueable.php b/src/Illuminate/Bus/Queueable.php index 6813363e39f3..828621227365 100644 --- a/src/Illuminate/Bus/Queueable.php +++ b/src/Illuminate/Bus/Queueable.php @@ -25,6 +25,13 @@ trait Queueable */ public $delay; + /** + * The jobs that should run if this job is successful. + * + * @var array + */ + public $chained = []; + /** * Set the desired connection for the job. * @@ -63,4 +70,31 @@ public function delay($delay) return $this; } + + /** + * Set the jobs that should run if this job is successful. + * + * @param array $chain + * @return $this + */ + public function then($chain) + { + $this->chained = collect($chain)->map(function ($job) { + return serialize($job); + })->all(); + + return $this; + } + + /** + * Dispatch the next job on the chain. + * + * @return void + */ + public function dispatchNextJobInChain() + { + if (! empty($this->chained)) { + dispatch(unserialize(array_shift($this->chained))->then($this->chained)); + } + } } diff --git a/src/Illuminate/Foundation/Bus/PendingDispatch.php b/src/Illuminate/Foundation/Bus/PendingDispatch.php index 7d5053d82241..c973d894e6f2 100644 --- a/src/Illuminate/Foundation/Bus/PendingDispatch.php +++ b/src/Illuminate/Foundation/Bus/PendingDispatch.php @@ -54,6 +54,19 @@ public function delay($delay) return $this; } + /** + * Set the jobs that should run if this job is successful. + * + * @param array $chain + * @return $this + */ + public function then($chain) + { + $this->job->then($chain); + + return $this; + } + /** * Handle the object's destruction. * diff --git a/src/Illuminate/Queue/CallQueuedHandler.php b/src/Illuminate/Queue/CallQueuedHandler.php index ebfb48b6fb1e..65dd7db348cc 100644 --- a/src/Illuminate/Queue/CallQueuedHandler.php +++ b/src/Illuminate/Queue/CallQueuedHandler.php @@ -43,6 +43,8 @@ public function call(Job $job, array $data) ); if (! $job->isDeletedOrReleased()) { + $this->ensureNextJobIsChainIsDispatched($command); + $job->delete(); } } @@ -81,6 +83,19 @@ protected function setJobInstanceIfNecessary(Job $job, $instance) return $instance; } + /** + * Ensure the next job in the chain is dispatched if applicable. + * + * @param mixed $command + * @return void + */ + protected function ensureNextJobIsChainIsDispatched($command) + { + if (method_exists($command, 'dispatchNextJobInChain')) { + $command->dispatchNextJobInChain(); + } + } + /** * Call the failed method on the job instance. * diff --git a/tests/Integration/IntegrationTest.php b/tests/Integration/IntegrationTest.php index e095cd6bed8d..66bcf597c3f4 100644 --- a/tests/Integration/IntegrationTest.php +++ b/tests/Integration/IntegrationTest.php @@ -1,11 +1,12 @@ then([ + new JobChainingTestSecondJob + ]); + + $this->assertTrue(JobChainingTestFirstJob::$ran); + $this->assertTrue(JobChainingTestSecondJob::$ran); + } +} + + +class JobChainingTestFirstJob implements ShouldQueue +{ + use Dispatchable, Queueable; + + public static $ran = false; + + public function handle() + { + static::$ran = true; + } +} + + +class JobChainingTestSecondJob implements ShouldQueue +{ + use Dispatchable, Queueable; + + public static $ran = false; + + public function handle() + { + static::$ran = true; + } +}