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\Bus;
4
 
5
use Carbon\CarbonImmutable;
6
use Closure;
7
use DateTimeInterface;
8
use Illuminate\Database\Connection;
9
use Illuminate\Database\PostgresConnection;
10
use Illuminate\Database\Query\Expression;
11
use Illuminate\Support\Str;
12
 
13
class DatabaseBatchRepository implements PrunableBatchRepository
14
{
15
    /**
16
     * The batch factory instance.
17
     *
18
     * @var \Illuminate\Bus\BatchFactory
19
     */
20
    protected $factory;
21
 
22
    /**
23
     * The database connection instance.
24
     *
25
     * @var \Illuminate\Database\Connection
26
     */
27
    protected $connection;
28
 
29
    /**
30
     * The database table to use to store batch information.
31
     *
32
     * @var string
33
     */
34
    protected $table;
35
 
36
    /**
37
     * Create a new batch repository instance.
38
     *
39
     * @param  \Illuminate\Bus\BatchFactory  $factory
40
     * @param  \Illuminate\Database\Connection  $connection
41
     * @param  string  $table
42
     */
43
    public function __construct(BatchFactory $factory, Connection $connection, string $table)
44
    {
45
        $this->factory = $factory;
46
        $this->connection = $connection;
47
        $this->table = $table;
48
    }
49
 
50
    /**
51
     * Retrieve a list of batches.
52
     *
53
     * @param  int  $limit
54
     * @param  mixed  $before
55
     * @return \Illuminate\Bus\Batch[]
56
     */
57
    public function get($limit = 50, $before = null)
58
    {
59
        return $this->connection->table($this->table)
60
                            ->orderByDesc('id')
61
                            ->take($limit)
62
                            ->when($before, fn ($q) => $q->where('id', '<', $before))
63
                            ->get()
64
                            ->map(function ($batch) {
65
                                return $this->toBatch($batch);
66
                            })
67
                            ->all();
68
    }
69
 
70
    /**
71
     * Retrieve information about an existing batch.
72
     *
73
     * @param  string  $batchId
74
     * @return \Illuminate\Bus\Batch|null
75
     */
76
    public function find(string $batchId)
77
    {
78
        $batch = $this->connection->table($this->table)
79
                            ->useWritePdo()
80
                            ->where('id', $batchId)
81
                            ->first();
82
 
83
        if ($batch) {
84
            return $this->toBatch($batch);
85
        }
86
    }
87
 
88
    /**
89
     * Store a new pending batch.
90
     *
91
     * @param  \Illuminate\Bus\PendingBatch  $batch
92
     * @return \Illuminate\Bus\Batch
93
     */
94
    public function store(PendingBatch $batch)
95
    {
96
        $id = (string) Str::orderedUuid();
97
 
98
        $this->connection->table($this->table)->insert([
99
            'id' => $id,
100
            'name' => $batch->name,
101
            'total_jobs' => 0,
102
            'pending_jobs' => 0,
103
            'failed_jobs' => 0,
104
            'failed_job_ids' => '[]',
105
            'options' => $this->serialize($batch->options),
106
            'created_at' => time(),
107
            'cancelled_at' => null,
108
            'finished_at' => null,
109
        ]);
110
 
111
        return $this->find($id);
112
    }
113
 
114
    /**
115
     * Increment the total number of jobs within the batch.
116
     *
117
     * @param  string  $batchId
118
     * @param  int  $amount
119
     * @return void
120
     */
121
    public function incrementTotalJobs(string $batchId, int $amount)
122
    {
123
        $this->connection->table($this->table)->where('id', $batchId)->update([
124
            'total_jobs' => new Expression('total_jobs + '.$amount),
125
            'pending_jobs' => new Expression('pending_jobs + '.$amount),
126
            'finished_at' => null,
127
        ]);
128
    }
129
 
130
    /**
131
     * Decrement the total number of pending jobs for the batch.
132
     *
133
     * @param  string  $batchId
134
     * @param  string  $jobId
135
     * @return \Illuminate\Bus\UpdatedBatchJobCounts
136
     */
137
    public function decrementPendingJobs(string $batchId, string $jobId)
138
    {
139
        $values = $this->updateAtomicValues($batchId, function ($batch) use ($jobId) {
140
            return [
141
                'pending_jobs' => $batch->pending_jobs - 1,
142
                'failed_jobs' => $batch->failed_jobs,
143
                'failed_job_ids' => json_encode(array_values(array_diff(json_decode($batch->failed_job_ids, true), [$jobId]))),
144
            ];
145
        });
146
 
147
        return new UpdatedBatchJobCounts(
148
            $values['pending_jobs'],
149
            $values['failed_jobs']
150
        );
151
    }
152
 
153
    /**
154
     * Increment the total number of failed jobs for the batch.
155
     *
156
     * @param  string  $batchId
157
     * @param  string  $jobId
158
     * @return \Illuminate\Bus\UpdatedBatchJobCounts
159
     */
160
    public function incrementFailedJobs(string $batchId, string $jobId)
161
    {
162
        $values = $this->updateAtomicValues($batchId, function ($batch) use ($jobId) {
163
            return [
164
                'pending_jobs' => $batch->pending_jobs,
165
                'failed_jobs' => $batch->failed_jobs + 1,
166
                'failed_job_ids' => json_encode(array_values(array_unique(array_merge(json_decode($batch->failed_job_ids, true), [$jobId])))),
167
            ];
168
        });
169
 
170
        return new UpdatedBatchJobCounts(
171
            $values['pending_jobs'],
172
            $values['failed_jobs']
173
        );
174
    }
175
 
176
    /**
177
     * Update an atomic value within the batch.
178
     *
179
     * @param  string  $batchId
180
     * @param  \Closure  $callback
181
     * @return int|null
182
     */
183
    protected function updateAtomicValues(string $batchId, Closure $callback)
184
    {
185
        return $this->connection->transaction(function () use ($batchId, $callback) {
186
            $batch = $this->connection->table($this->table)->where('id', $batchId)
187
                        ->lockForUpdate()
188
                        ->first();
189
 
190
            return is_null($batch) ? [] : tap($callback($batch), function ($values) use ($batchId) {
191
                $this->connection->table($this->table)->where('id', $batchId)->update($values);
192
            });
193
        });
194
    }
195
 
196
    /**
197
     * Mark the batch that has the given ID as finished.
198
     *
199
     * @param  string  $batchId
200
     * @return void
201
     */
202
    public function markAsFinished(string $batchId)
203
    {
204
        $this->connection->table($this->table)->where('id', $batchId)->update([
205
            'finished_at' => time(),
206
        ]);
207
    }
208
 
209
    /**
210
     * Cancel the batch that has the given ID.
211
     *
212
     * @param  string  $batchId
213
     * @return void
214
     */
215
    public function cancel(string $batchId)
216
    {
217
        $this->connection->table($this->table)->where('id', $batchId)->update([
218
            'cancelled_at' => time(),
219
            'finished_at' => time(),
220
        ]);
221
    }
222
 
223
    /**
224
     * Delete the batch that has the given ID.
225
     *
226
     * @param  string  $batchId
227
     * @return void
228
     */
229
    public function delete(string $batchId)
230
    {
231
        $this->connection->table($this->table)->where('id', $batchId)->delete();
232
    }
233
 
234
    /**
235
     * Prune all of the entries older than the given date.
236
     *
237
     * @param  \DateTimeInterface  $before
238
     * @return int
239
     */
240
    public function prune(DateTimeInterface $before)
241
    {
242
        $query = $this->connection->table($this->table)
243
            ->whereNotNull('finished_at')
244
            ->where('finished_at', '<', $before->getTimestamp());
245
 
246
        $totalDeleted = 0;
247
 
248
        do {
249
            $deleted = $query->take(1000)->delete();
250
 
251
            $totalDeleted += $deleted;
252
        } while ($deleted !== 0);
253
 
254
        return $totalDeleted;
255
    }
256
 
257
    /**
258
     * Prune all of the unfinished entries older than the given date.
259
     *
260
     * @param  \DateTimeInterface  $before
261
     * @return int
262
     */
263
    public function pruneUnfinished(DateTimeInterface $before)
264
    {
265
        $query = $this->connection->table($this->table)
266
            ->whereNull('finished_at')
267
            ->where('created_at', '<', $before->getTimestamp());
268
 
269
        $totalDeleted = 0;
270
 
271
        do {
272
            $deleted = $query->take(1000)->delete();
273
 
274
            $totalDeleted += $deleted;
275
        } while ($deleted !== 0);
276
 
277
        return $totalDeleted;
278
    }
279
 
280
    /**
281
     * Prune all of the cancelled entries older than the given date.
282
     *
283
     * @param  \DateTimeInterface  $before
284
     * @return int
285
     */
286
    public function pruneCancelled(DateTimeInterface $before)
287
    {
288
        $query = $this->connection->table($this->table)
289
            ->whereNotNull('cancelled_at')
290
            ->where('created_at', '<', $before->getTimestamp());
291
 
292
        $totalDeleted = 0;
293
 
294
        do {
295
            $deleted = $query->take(1000)->delete();
296
 
297
            $totalDeleted += $deleted;
298
        } while ($deleted !== 0);
299
 
300
        return $totalDeleted;
301
    }
302
 
303
    /**
304
     * Execute the given Closure within a storage specific transaction.
305
     *
306
     * @param  \Closure  $callback
307
     * @return mixed
308
     */
309
    public function transaction(Closure $callback)
310
    {
311
        return $this->connection->transaction(fn () => $callback());
312
    }
313
 
314
    /**
315
     * Serialize the given value.
316
     *
317
     * @param  mixed  $value
318
     * @return string
319
     */
320
    protected function serialize($value)
321
    {
322
        $serialized = serialize($value);
323
 
324
        return $this->connection instanceof PostgresConnection
325
            ? base64_encode($serialized)
326
            : $serialized;
327
    }
328
 
329
    /**
330
     * Unserialize the given value.
331
     *
332
     * @param  string  $serialized
333
     * @return mixed
334
     */
335
    protected function unserialize($serialized)
336
    {
337
        if ($this->connection instanceof PostgresConnection &&
338
            ! Str::contains($serialized, [':', ';'])) {
339
            $serialized = base64_decode($serialized);
340
        }
341
 
342
        return unserialize($serialized);
343
    }
344
 
345
    /**
346
     * Convert the given raw batch to a Batch object.
347
     *
348
     * @param  object  $batch
349
     * @return \Illuminate\Bus\Batch
350
     */
351
    protected function toBatch($batch)
352
    {
353
        return $this->factory->make(
354
            $this,
355
            $batch->id,
356
            $batch->name,
357
            (int) $batch->total_jobs,
358
            (int) $batch->pending_jobs,
359
            (int) $batch->failed_jobs,
360
            json_decode($batch->failed_job_ids, true),
361
            $this->unserialize($batch->options),
362
            CarbonImmutable::createFromTimestamp($batch->created_at),
363
            $batch->cancelled_at ? CarbonImmutable::createFromTimestamp($batch->cancelled_at) : $batch->cancelled_at,
364
            $batch->finished_at ? CarbonImmutable::createFromTimestamp($batch->finished_at) : $batch->finished_at
365
        );
366
    }
367
 
368
    /**
369
     * Get the underlying database connection.
370
     *
371
     * @return \Illuminate\Database\Connection
372
     */
373
    public function getConnection()
374
    {
375
        return $this->connection;
376
    }
377
 
378
    /**
379
     * Set the underlying database connection.
380
     *
381
     * @param  \Illuminate\Database\Connection  $connection
382
     * @return void
383
     */
384
    public function setConnection(Connection $connection)
385
    {
386
        $this->connection = $connection;
387
    }
388
}