SupportsDeleteWhereIDsNotIn   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 59
Duplicated Lines 0 %

Test Coverage

Coverage 55%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 7
eloc 19
c 1
b 1
f 0
dl 0
loc 59
ccs 11
cts 20
cp 0.55
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A deleteByChunk() 0 14 3
A deleteWhereIDsNotIn() 0 24 4
1
<?php
2
3
namespace App\Traits;
4
5
use Exception;
6
use Illuminate\Database\DatabaseManager;
7
use Illuminate\Database\Eloquent\Builder;
8
9
/**
10
 * With reference to GitHub issue #463.
11
 * MySQL and PostgreSQL seem to have a limit of 2^16-1 (65535) elements in an IN statement.
12
 * This trait provides a method as a workaround to this limitation.
13
 *
14
 * @method static Builder whereIn($keys, array $values)
15
 * @method static Builder whereNotIn($keys, array $values)
16
 * @method static Builder select(string $string)
17
 */
18
trait SupportsDeleteWhereIDsNotIn
19
{
20
    /**
21
     * Deletes all records whose IDs are not in an array.
22
     *
23
     * @param string[]|int[] $ids The array of IDs.
24
     * @param string         $key Name of the primary key.
25
     *
26
     * @throws Exception
27
     */
28 11
    public static function deleteWhereIDsNotIn(array $ids, string $key = 'id'): void
29
    {
30 11
        $maxChunkSize = config('database.default') === 'sqlite-persistent' ? 999 : 65535;
31
        // If the number of entries is lower than, or equals to maxChunkSize, just go ahead.
32 11
        if (count($ids) <= $maxChunkSize) {
33 11
            static::whereNotIn($key, $ids)->delete();
34
35 11
            return;
36
        }
37
38
        // Otherwise, we get the actual IDs that should be deleted…
39
        $allIDs = static::select($key)->get()->pluck($key)->all();
40
        $whereInIDs = array_diff($allIDs, $ids);
41
42
        // …and see if we can delete them instead.
43
        if (count($whereInIDs) < $maxChunkSize) {
44
            static::whereIn($key, $whereInIDs)->delete();
45
46
            return;
47
        }
48
49
        // If that's not possible (i.e. this array has more than maxChunkSize elements, too)
50
        // then we'll delete chunk by chunk.
51
        static::deleteByChunk($ids, $key, $maxChunkSize);
52
    }
53
54
    /**
55
     * Delete records chunk by chunk.
56
     *
57
     * @param string[]|int[] $ids       The array of record IDs to delete
58
     * @param string         $key       Name of the primary key
59
     * @param int            $chunkSize Size of each chunk. Defaults to 2^16-1 (65535)
60
     *
61
     * @throws Exception
62
     */
63 1
    public static function deleteByChunk(array $ids, string $key = 'id', int $chunkSize = 65535): void
64
    {
65
        /** @var DatabaseManager $db */
66 1
        $db = app(DatabaseManager::class);
67 1
        $db->beginTransaction();
68
69
        try {
70 1
            foreach (array_chunk($ids, $chunkSize) as $chunk) {
71 1
                static::whereIn($key, $chunk)->delete();
72
            }
73
74 1
            $db->commit();
75
        } catch (Exception $e) {
76
            $db->rollBack();
77
        }
78 1
    }
79
}
80