From 60416cf21faf869cafdf66757adf010d0cf095e8 Mon Sep 17 00:00:00 2001 From: Arif Hoque Date: Sat, 15 Nov 2025 11:19:20 +0600 Subject: [PATCH 1/3] optional job class now, can be queueable or can be syncable --- src/Attributes/Queueable.php | 22 +++++++++ src/InteractsWithQueueableAttributes.php | 39 ++++++++++++++++ src/Job.php | 59 ++++++++++++++++++++++-- 3 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/Attributes/Queueable.php create mode 100644 src/InteractsWithQueueableAttributes.php diff --git a/src/Attributes/Queueable.php b/src/Attributes/Queueable.php new file mode 100644 index 0000000..056d6be --- /dev/null +++ b/src/Attributes/Queueable.php @@ -0,0 +1,22 @@ +getAttributes(Queueable::class); + + if (!empty($attributes)) { + $attribute = $attributes[0]->newInstance(); + + if ($attribute->tries !== null) { + $this->tries = $attribute->tries; + } + + if ($attribute->retryAfter !== null) { + $this->retryAfter = $attribute->retryAfter; + } + + if ($attribute->delayFor !== null) { + $this->jobDelay = $attribute->delayFor; + } + + if ($attribute->onQueue !== null) { + $this->queueName = $attribute->onQueue; + } + } + } +} \ No newline at end of file diff --git a/src/Job.php b/src/Job.php index bc187df..b66abc3 100644 --- a/src/Job.php +++ b/src/Job.php @@ -4,9 +4,12 @@ use Doppar\Queue\Facades\Queue; use Doppar\Queue\Contracts\JobInterface; +use Doppar\Queue\Attributes\Queueable; abstract class Job implements JobInterface { + use InteractsWithQueueableAttributes; + /** * The number of times the job may be attempted. * @@ -147,14 +150,35 @@ public function delayFor(int $delay): self return $this; } + /** + * Check if the job should be queued based on the Queueable attribute. + * + * @return bool + */ + public function shouldQueue(): bool + { + $reflection = new \ReflectionClass($this); + $attributes = $reflection->getAttributes(Queueable::class); + + return !empty($attributes); + } + /** * Dispatch the job to the queue. * - * @return string Job ID + * @return string|null */ - public function dispatch(): string + public function dispatch(): ?string { - return Queue::push($this); + $this->applyQueueableAttributes(); + + if ($this->shouldQueue()) { + return Queue::push($this); + } + + $this->handle(); + + return null; } /** @@ -167,6 +191,8 @@ public function dispatchAfter(int $delay): string { $this->delayFor($delay); + $this->applyQueueableAttributes(); + return $this->dispatch(); } @@ -180,6 +206,8 @@ public function dispatchOn(string $queue): string { $this->onQueue($queue); + $this->applyQueueableAttributes(); + return $this->dispatch(); } @@ -195,4 +223,29 @@ public static function dispatchNow(...$args): string return $job->dispatch(); } + + /** + * Dispatch the job synchronously + * + * @param mixed ...$args + * @return void + */ + public static function dispatchSync(...$args): void + { + $job = new static(...$args); + + $job->handle(); + } + + /** + * Force the job to be queued even without Queueable attribute. + * + * @return string Job ID + */ + public function forceQueue(): string + { + $this->applyQueueableAttributes(); + + return Queue::push($this); + } } From 943dfd2e9a620719e125d0568c653b5e88e05ba1 Mon Sep 17 00:00:00 2001 From: Arif Hoque Date: Sat, 15 Nov 2025 12:14:06 +0600 Subject: [PATCH 2/3] Dispatchable trait to dispacth job using static method --- src/Commands/MakeJobCommand.php | 10 +++++ src/Dispatchable.php | 52 ++++++++++++++++++++++++ src/InteractsWithQueueableAttributes.php | 13 ++++++ src/Job.php | 14 ------- 4 files changed, 75 insertions(+), 14 deletions(-) create mode 100644 src/Dispatchable.php diff --git a/src/Commands/MakeJobCommand.php b/src/Commands/MakeJobCommand.php index 00e8de8..ae0b650 100644 --- a/src/Commands/MakeJobCommand.php +++ b/src/Commands/MakeJobCommand.php @@ -77,9 +77,19 @@ protected function generateJobContent(string $namespace, string $className): str namespace {$namespace}; use Doppar\Queue\Job; +use Doppar\Queue\Dispatchable; +// use Doppar\Queue\Attributes\Queueable; +// #[Queueable(tries: 3, retryAfter: 60, delayFor: 300, onQueue: 'default')] class {$className} extends Job { + use Dispatchable; + + /** + * Create a new job instance. + */ + public function __construct(){} + /** * Execute the job. * diff --git a/src/Dispatchable.php b/src/Dispatchable.php new file mode 100644 index 0000000..283dd0b --- /dev/null +++ b/src/Dispatchable.php @@ -0,0 +1,52 @@ +dispatch(); + } + + /** + * Dispatch the job synchronously with the given arguments. + * + * @param mixed ...$args + * @return void + */ + public static function queueAsSync(...$args): void + { + (new static(...$args))->handle(); + } + + /** + * Dispatch the job after a delay with the given arguments. + * + * @param int $delay + * @param mixed ...$args + * @return string Job ID + */ + public static function queueAfter(int $delay, ...$args): string + { + return (new static(...$args))->delayFor($delay)->forceQueue(); + } + + /** + * Dispatch the job to a specific queue with the given arguments. + * + * @param string $queue + * @param mixed ...$args + * @return string Job ID + */ + public static function queueOn(string $queue, ...$args): string + { + return (new static(...$args))->onQueue($queue)->forceQueue(); + } +} diff --git a/src/InteractsWithQueueableAttributes.php b/src/InteractsWithQueueableAttributes.php index 31a00fe..f3400b3 100644 --- a/src/InteractsWithQueueableAttributes.php +++ b/src/InteractsWithQueueableAttributes.php @@ -6,6 +6,19 @@ trait InteractsWithQueueableAttributes { + /** + * Check if the job should be queued based on the Queueable attribute. + * + * @return bool + */ + public function shouldQueue(): bool + { + $reflection = new \ReflectionClass($this); + $attributes = $reflection->getAttributes(Queueable::class); + + return !empty($attributes); + } + /** * Apply the Queueable attribute settings to the job. * diff --git a/src/Job.php b/src/Job.php index b66abc3..d5525d8 100644 --- a/src/Job.php +++ b/src/Job.php @@ -4,7 +4,6 @@ use Doppar\Queue\Facades\Queue; use Doppar\Queue\Contracts\JobInterface; -use Doppar\Queue\Attributes\Queueable; abstract class Job implements JobInterface { @@ -150,19 +149,6 @@ public function delayFor(int $delay): self return $this; } - /** - * Check if the job should be queued based on the Queueable attribute. - * - * @return bool - */ - public function shouldQueue(): bool - { - $reflection = new \ReflectionClass($this); - $attributes = $reflection->getAttributes(Queueable::class); - - return !empty($attributes); - } - /** * Dispatch the job to the queue. * From 42962f270a49c20541f56dfefd7d3bcc57ab3148 Mon Sep 17 00:00:00 2001 From: Arif Hoque Date: Sat, 15 Nov 2025 12:15:58 +0600 Subject: [PATCH 3/3] make job command move to core framework --- src/Commands/MakeJobCommand.php | 117 -------------------------------- src/QueueServiceProvider.php | 2 - 2 files changed, 119 deletions(-) delete mode 100644 src/Commands/MakeJobCommand.php diff --git a/src/Commands/MakeJobCommand.php b/src/Commands/MakeJobCommand.php deleted file mode 100644 index ae0b650..0000000 --- a/src/Commands/MakeJobCommand.php +++ /dev/null @@ -1,117 +0,0 @@ -executeWithTiming(function () { - $name = $this->argument('name'); - $parts = explode('/', $name); - $className = array_pop($parts); - - // Ensure class name ends with Job - if (!str_ends_with($className, 'Job')) { - $className .= 'Job'; - } - - $namespace = 'App\\Jobs' . (count($parts) > 0 ? '\\' . implode('\\', $parts) : ''); - $filePath = base_path('app/Jobs/' . str_replace('/', DIRECTORY_SEPARATOR, $name) . '.php'); - - // Check if Job already exists - if (file_exists($filePath)) { - $this->displayError('Job already exists at:'); - $this->line('' . str_replace(base_path(), '', $filePath) . ''); - return Command::FAILURE; - } - - // Create directory if needed - $directoryPath = dirname($filePath); - if (!is_dir($directoryPath)) { - mkdir($directoryPath, 0755, true); - } - - // Generate and save Job class - $content = $this->generateJobContent($namespace, $className); - file_put_contents($filePath, $content); - - $this->displaySuccess('Job created successfully'); - $this->line('📦 File: ' . str_replace(base_path(), '', $filePath) . ''); - $this->newLine(); - $this->line('⚙️ Class: ' . $className . ''); - - return Command::SUCCESS; - }); - } - - /** - * Generate Job class content. - */ - protected function generateJobContent(string $namespace, string $className): string - { - return <<commands([ QueueRunCommand::class, QueueRetryCommand::class, - MakeJobCommand::class, QueueFlushCommand::class, QueueFailedCommand::class, QueueMonitorCommand::class