• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / jobs / 19498141349

19 Nov 2025 10:30AM UTC coverage: 62.5% (+0.7%) from 61.815%
19498141349

push

github

daycry
- Fixes

4 of 4 new or added lines in 4 files covered. (100.0%)

41 existing lines in 9 files now uncovered.

1145 of 1832 relevant lines covered (62.5%)

4.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/src/Traits/EnqueuableTrait.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Daycry Queues.
7
 *
8
 * (c) Daycry <daycry9@proton.me>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Daycry\Jobs\Traits;
15

16
use CodeIgniter\I18n\Time;
17
use DateInterval;
18
use DateTime;
19
use DateTimeInterface;
20
use Daycry\Jobs\Exceptions\JobException;
21
use Daycry\Jobs\Exceptions\QueueException;
22
use Daycry\Jobs\Interfaces\QueueInterface;
23
use Daycry\Jobs\Interfaces\WorkerInterface;
24
use Daycry\Jobs\Libraries\QueueManager;
25
use Daycry\Jobs\Libraries\Utils;
26
use Daycry\Jobs\Queues\SyncQueue;
27

28
/**
29
 * Queue-centric capabilities: queue selection, scheduling, attempts tracking and priority validation.
30
 * push(): validates job data and delegates to configured worker enqueue.
31
 */
32
trait EnqueuableTrait
33
{
34
    /**
35
     * Number of completed execution cycles for this job.
36
     * Starts at 0 (never executed). Incremented exactly once per run (success or failure)
37
     * by RequeueHelper::finalize(). A requeued job therefore keeps its historical attempts
38
     * count so retry policies can make consistent decisions.
39
     */
40
    protected int $attempts = 0;
41

42
    protected ?string $queue = null;
43
    private QueueInterface $worker;
44
    protected ?DateTime $schedule = null;
45
    protected int $priority       = 0;
46

47
    /**
48
     * Marks the job to be placed on a queue (assigns/validates queue name).
49
     * Fluent: returns $this instead of bool so you can chain ->enqueue()->named('...')->priority(...)
50
     * NOTE: This does NOT actually push the job to the backend. Call push() for that.
51
     */
52
    public function enqueue(?string $queue = null): self
53
    {
54
        $queues = Utils::parseConfigFile(config('Jobs')->queues);
6✔
55
        // If a queue name is explicitly provided, assign it
56
        if ($queue !== null) {
6✔
57
            $this->queue = $queue;
5✔
58
        }
59

60
        // If still null, take the first available queue (if any)
61
        if ($this->queue === null && count($queues) > 0) {
6✔
62
            $this->queue = $queues[0];
1✔
63
        }
64

65
        if (! in_array($this->queue, $queues, true)) {
6✔
UNCOV
66
            throw QueueException::forInvalidQueue($this->queue);
×
67
        }
68

69
        return $this;
6✔
70
    }
71

72
    public function priority(int $priority): self
73
    {
74
        if ($priority < 0 || $priority > 10) {
63✔
UNCOV
75
            throw JobException::forInvalidPriority($priority);
×
76
        }
77

78
        $this->priority = $priority;
63✔
79

80
        return $this;
63✔
81
    }
82

83
    public function push()
84
    {
85
        // Assign default source if not already defined (direct queue usage)
86
        if (method_exists($this, 'getSource') && method_exists($this, 'source') && $this->getSource() === null) {
13✔
87
            $this->source('queue');
12✔
88
        }
89
        $this->checkWorker();
13✔
90
        // Fast path for SyncQueue: pass original Job instance so callback descriptor & closures are preserved.
91
        if ($this->worker instanceof SyncQueue) {
13✔
92
            // Perform validation using an export snapshot; inject placeholder for closure payload.
93
            $export = $this->toObject();
2✔
94
            if ($this->getJob() === 'closure') {
2✔
UNCOV
95
                $export->payload = '__closure__';
×
96
            }
97
            Utils::checkDataQueue($export, 'queueData');
2✔
98
            if ($this->getJob() !== 'closure') {
2✔
99
                Utils::checkDataQueue($export, $this->getJob());
2✔
100
            }
101

102
            return $this->worker->enqueue($this);
2✔
103
        }
104

105
        $object = $this->toObject();
11✔
106
        if ($this->getJob() === 'closure') {
11✔
107
            // Validation snapshot with placeholder
108
            $snapshot          = clone $object;
1✔
109
            $snapshot->payload = '__closure__';
1✔
110
            Utils::checkDataQueue($snapshot, 'queueData');
1✔
111
        } else {
112
            Utils::checkDataQueue($object, 'queueData');
10✔
113
            Utils::checkDataQueue($object, $this->getJob());
10✔
114
        }
115

116
        return $this->worker->enqueue($object);
11✔
117
    }
118

119
    public function setQueue(string $queue): self
120
    {
121
        $this->queue = $queue;
15✔
122

123
        return $this;
15✔
124
    }
125

126
    public function getQueue(): ?string
127
    {
128
        return $this->queue;
22✔
129
    }
130

131
    public function scheduled(DateTime|Time $schedule)
132
    {
133
        if ($schedule instanceof Time) {
7✔
UNCOV
134
            $schedule = $schedule->toDateTime();
×
135
        }
136

137
        $this->schedule = $schedule;
7✔
138

139
        return $this;
7✔
140
    }
141

142
    public function addAttempt(): self
143
    {
144
        $this->attempts++;
6✔
145

146
        if ($this->schedule !== null) {
6✔
147
            $this->scheduled((new DateTime())->add(new DateInterval('PT1H')));
1✔
148
        }
149

150
        return $this;
6✔
151
    }
152

153
    public function getAttempt(): int
154
    {
155
        return $this->attempts;
16✔
156
    }
157

158
    // No idempotency helpers (reverted)
159

160
    protected function checkWorker(): void
161
    {
162
        $this->worker = QueueManager::instance()->getDefault();
13✔
163
    }
164
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc