-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathAutoincrement.php
67 lines (57 loc) · 1.9 KB
/
Autoincrement.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?php declare(strict_types=1);
namespace MLL\LaravelUtils\Database;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
/**
* Allows the creation of incrementing IDs without actually using autoincrement.
*/
abstract class Autoincrement
{
/** Use this method in a migration to create the backing table. */
public static function createTable(): void
{
$name = static::name();
Schema::create($name, static function (Blueprint $table) use ($name): void {
$table->engine = 'InnoDB';
$table->unsignedBigInteger($name);
});
}
/**
* Set the counter to the given value.
*
* Set to 0 if you want @see self::next() to start from 1 again.
*/
public static function set(int $value): void
{
$name = static::name();
$builder = DB::table($name);
$builder->delete();
$builder->insert([$name => $value]);
}
/**
* Return the next value in the sequence, e.g. 1, 2, 3.
*
* The usage of a transaction ensures that no two callers ever receive the same value.
*/
public static function next(): int
{
// @phpstan-ignore-next-line TODO remove when requiring Laravel 9+ that can infer this must return int
return DB::transaction(static function (): int {
$name = static::name();
$builder = DB::table($name);
$current = $builder
->lockForUpdate()
->max($name);
$next = $current + 1;
if ($current === null) {
$builder->insert([$name => $next]);
} else {
$builder->update([$name => $next]);
}
return $next;
});
}
/** Name of the table/column, must be unique in the used database. */
abstract protected static function name(): string;
}