Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Queue;
4
 
5
use Exception;
6
use Illuminate\Bus\Batchable;
7
use Illuminate\Bus\UniqueLock;
8
use Illuminate\Contracts\Bus\Dispatcher;
9
use Illuminate\Contracts\Cache\Repository as Cache;
10
use Illuminate\Contracts\Container\Container;
11
use Illuminate\Contracts\Encryption\Encrypter;
12
use Illuminate\Contracts\Queue\Job;
13
use Illuminate\Contracts\Queue\ShouldBeUnique;
14
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
15
use Illuminate\Database\Eloquent\ModelNotFoundException;
16
use Illuminate\Pipeline\Pipeline;
17
use ReflectionClass;
18
use RuntimeException;
19
 
20
class CallQueuedHandler
21
{
22
    /**
23
     * The bus dispatcher implementation.
24
     *
25
     * @var \Illuminate\Contracts\Bus\Dispatcher
26
     */
27
    protected $dispatcher;
28
 
29
    /**
30
     * The container instance.
31
     *
32
     * @var \Illuminate\Contracts\Container\Container
33
     */
34
    protected $container;
35
 
36
    /**
37
     * Create a new handler instance.
38
     *
39
     * @param  \Illuminate\Contracts\Bus\Dispatcher  $dispatcher
40
     * @param  \Illuminate\Contracts\Container\Container  $container
41
     * @return void
42
     */
43
    public function __construct(Dispatcher $dispatcher, Container $container)
44
    {
45
        $this->container = $container;
46
        $this->dispatcher = $dispatcher;
47
    }
48
 
49
    /**
50
     * Handle the queued job.
51
     *
52
     * @param  \Illuminate\Contracts\Queue\Job  $job
53
     * @param  array  $data
54
     * @return void
55
     */
56
    public function call(Job $job, array $data)
57
    {
58
        try {
59
            $command = $this->setJobInstanceIfNecessary(
60
                $job, $this->getCommand($data)
61
            );
62
        } catch (ModelNotFoundException $e) {
63
            return $this->handleModelNotFound($job, $e);
64
        }
65
 
66
        if ($command instanceof ShouldBeUniqueUntilProcessing) {
67
            $this->ensureUniqueJobLockIsReleased($command);
68
        }
69
 
70
        $this->dispatchThroughMiddleware($job, $command);
71
 
72
        if (! $job->isReleased() && ! $command instanceof ShouldBeUniqueUntilProcessing) {
73
            $this->ensureUniqueJobLockIsReleased($command);
74
        }
75
 
76
        if (! $job->hasFailed() && ! $job->isReleased()) {
77
            $this->ensureNextJobInChainIsDispatched($command);
78
            $this->ensureSuccessfulBatchJobIsRecorded($command);
79
        }
80
 
81
        if (! $job->isDeletedOrReleased()) {
82
            $job->delete();
83
        }
84
    }
85
 
86
    /**
87
     * Get the command from the given payload.
88
     *
89
     * @param  array  $data
90
     * @return mixed
91
     *
92
     * @throws \RuntimeException
93
     */
94
    protected function getCommand(array $data)
95
    {
96
        if (str_starts_with($data['command'], 'O:')) {
97
            return unserialize($data['command']);
98
        }
99
 
100
        if ($this->container->bound(Encrypter::class)) {
101
            return unserialize($this->container[Encrypter::class]->decrypt($data['command']));
102
        }
103
 
104
        throw new RuntimeException('Unable to extract job payload.');
105
    }
106
 
107
    /**
108
     * Dispatch the given job / command through its specified middleware.
109
     *
110
     * @param  \Illuminate\Contracts\Queue\Job  $job
111
     * @param  mixed  $command
112
     * @return mixed
113
     */
114
    protected function dispatchThroughMiddleware(Job $job, $command)
115
    {
116
        if ($command instanceof \__PHP_Incomplete_Class) {
117
            throw new Exception('Job is incomplete class: '.json_encode($command));
118
        }
119
 
120
        return (new Pipeline($this->container))->send($command)
121
                ->through(array_merge(method_exists($command, 'middleware') ? $command->middleware() : [], $command->middleware ?? []))
122
                ->then(function ($command) use ($job) {
123
                    return $this->dispatcher->dispatchNow(
124
                        $command, $this->resolveHandler($job, $command)
125
                    );
126
                });
127
    }
128
 
129
    /**
130
     * Resolve the handler for the given command.
131
     *
132
     * @param  \Illuminate\Contracts\Queue\Job  $job
133
     * @param  mixed  $command
134
     * @return mixed
135
     */
136
    protected function resolveHandler($job, $command)
137
    {
138
        $handler = $this->dispatcher->getCommandHandler($command) ?: null;
139
 
140
        if ($handler) {
141
            $this->setJobInstanceIfNecessary($job, $handler);
142
        }
143
 
144
        return $handler;
145
    }
146
 
147
    /**
148
     * Set the job instance of the given class if necessary.
149
     *
150
     * @param  \Illuminate\Contracts\Queue\Job  $job
151
     * @param  mixed  $instance
152
     * @return mixed
153
     */
154
    protected function setJobInstanceIfNecessary(Job $job, $instance)
155
    {
156
        if (in_array(InteractsWithQueue::class, class_uses_recursive($instance))) {
157
            $instance->setJob($job);
158
        }
159
 
160
        return $instance;
161
    }
162
 
163
    /**
164
     * Ensure the next job in the chain is dispatched if applicable.
165
     *
166
     * @param  mixed  $command
167
     * @return void
168
     */
169
    protected function ensureNextJobInChainIsDispatched($command)
170
    {
171
        if (method_exists($command, 'dispatchNextJobInChain')) {
172
            $command->dispatchNextJobInChain();
173
        }
174
    }
175
 
176
    /**
177
     * Ensure the batch is notified of the successful job completion.
178
     *
179
     * @param  mixed  $command
180
     * @return void
181
     */
182
    protected function ensureSuccessfulBatchJobIsRecorded($command)
183
    {
184
        $uses = class_uses_recursive($command);
185
 
186
        if (! in_array(Batchable::class, $uses) ||
187
            ! in_array(InteractsWithQueue::class, $uses)) {
188
            return;
189
        }
190
 
191
        if ($batch = $command->batch()) {
192
            $batch->recordSuccessfulJob($command->job->uuid());
193
        }
194
    }
195
 
196
    /**
197
     * Ensure the lock for a unique job is released.
198
     *
199
     * @param  mixed  $command
200
     * @return void
201
     */
202
    protected function ensureUniqueJobLockIsReleased($command)
203
    {
204
        if ($command instanceof ShouldBeUnique) {
205
            (new UniqueLock($this->container->make(Cache::class)))->release($command);
206
        }
207
    }
208
 
209
    /**
210
     * Handle a model not found exception.
211
     *
212
     * @param  \Illuminate\Contracts\Queue\Job  $job
213
     * @param  \Throwable  $e
214
     * @return void
215
     */
216
    protected function handleModelNotFound(Job $job, $e)
217
    {
218
        $class = $job->resolveName();
219
 
220
        try {
221
            $shouldDelete = (new ReflectionClass($class))
222
                    ->getDefaultProperties()['deleteWhenMissingModels'] ?? false;
223
        } catch (Exception $e) {
224
            $shouldDelete = false;
225
        }
226
 
227
        if ($shouldDelete) {
228
            return $job->delete();
229
        }
230
 
231
        return $job->fail($e);
232
    }
233
 
234
    /**
235
     * Call the failed method on the job instance.
236
     *
237
     * The exception that caused the failure will be passed.
238
     *
239
     * @param  array  $data
240
     * @param  \Throwable|null  $e
241
     * @param  string  $uuid
242
     * @return void
243
     */
244
    public function failed(array $data, $e, string $uuid)
245
    {
246
        $command = $this->getCommand($data);
247
 
248
        if (! $command instanceof ShouldBeUniqueUntilProcessing) {
249
            $this->ensureUniqueJobLockIsReleased($command);
250
        }
251
 
252
        if ($command instanceof \__PHP_Incomplete_Class) {
253
            return;
254
        }
255
 
256
        $this->ensureFailedBatchJobIsRecorded($uuid, $command, $e);
257
        $this->ensureChainCatchCallbacksAreInvoked($uuid, $command, $e);
258
 
259
        if (method_exists($command, 'failed')) {
260
            $command->failed($e);
261
        }
262
    }
263
 
264
    /**
265
     * Ensure the batch is notified of the failed job.
266
     *
267
     * @param  string  $uuid
268
     * @param  mixed  $command
269
     * @param  \Throwable  $e
270
     * @return void
271
     */
272
    protected function ensureFailedBatchJobIsRecorded(string $uuid, $command, $e)
273
    {
274
        if (! in_array(Batchable::class, class_uses_recursive($command))) {
275
            return;
276
        }
277
 
278
        if ($batch = $command->batch()) {
279
            $batch->recordFailedJob($uuid, $e);
280
        }
281
    }
282
 
283
    /**
284
     * Ensure the chained job catch callbacks are invoked.
285
     *
286
     * @param  string  $uuid
287
     * @param  mixed  $command
288
     * @param  \Throwable  $e
289
     * @return void
290
     */
291
    protected function ensureChainCatchCallbacksAreInvoked(string $uuid, $command, $e)
292
    {
293
        if (method_exists($command, 'invokeChainCatchCallbacks')) {
294
            $command->invokeChainCatchCallbacks($e);
295
        }
296
    }
297
}