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

RonasIT / laravel-helpers / 14184733474

01 Apr 2025 01:05AM UTC coverage: 77.496% (+0.2%) from 77.344%
14184733474

push

github

web-flow
Merge pull request #198 from RonasIT/enum-migration-trait

feat: postgres enum helper for fast change ENUM field

13 of 14 new or added lines in 1 file covered. (92.86%)

1102 of 1422 relevant lines covered (77.5%)

12.31 hits per line

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

25.0
/src/Traits/MigrationTrait.php
1
<?php
2

3
namespace RonasIT\Support\Traits;
4

5
use Doctrine\DBAL\Types\Type;
6
use Doctrine\DBAL\Types\StringType;
7
use Illuminate\Support\Facades\DB;
8
use Illuminate\Support\Str;
9
use Illuminate\Support\Facades\Schema;
10
use Illuminate\Database\Schema\Blueprint;
11
use Exception;
12

13
trait MigrationTrait
14
{
15
    public function __construct()
16
    {
17
        $this->registerEnumType();
3✔
18
    }
19

20
    public function changeEnum(string $table, string $field, array $values, array $valuesToRename = []): void
21
    {
22
        $databaseDriver = config('database.default');
3✔
23

24
        match ($databaseDriver) {
25
            'pgsql' => $this->changePostgresEnums($table, $field, $values, $valuesToRename),
3✔
26
            default => throw new Exception("Database driver \"{$databaseDriver}\" not available")
1✔
27
        };
28
    }
29

30
    private function changePostgresEnums(string $table, string $field, array $values, array $valuesToRename = []): void
31
    {
32
        $check = "{$table}_{$field}_check";
2✔
33

34
        DB::statement("ALTER TABLE {$table} DROP CONSTRAINT {$check}");
2✔
35

36
        foreach ($valuesToRename as $key => $value) {
2✔
37
            DB::table($table)->where([$field => $key])->update([$field => $value]);
1✔
38
        }
39

40
        $values = $this->preparePostgresValues($values);
2✔
41

42
        DB::statement("ALTER TABLE {$table} ADD CONSTRAINT {$check} CHECK ({$field}::text = ANY (ARRAY[{$values}]::text[]))");
2✔
43
    }
44

45
    private function preparePostgresValues(array $values): string
46
    {
47
        $values = array_map(fn ($value) => "'{$value}'::character varying", $values);
2✔
48

49
        return join(', ', $values);
2✔
50
    }
51

52
    private function registerEnumType(): void
53
    {
54
        if (!Type::hasType('enum')) {
3✔
NEW
55
            Type::addType('enum', StringType::class);
×
56
        }
57
    }
58

59
    public function addForeignKey($fromEntity, $toEntity, $needAddField = false, $onDelete = 'cascade')
60
    {
61
        Schema::table(
×
62
            $this->getTableName($fromEntity),
×
63
            function (Blueprint $table) use ($toEntity, $needAddField, $onDelete) {
×
64
                $fieldName = Str::snake($toEntity) . '_id';
×
65

66
                if ($needAddField) {
×
67
                    $table->unsignedInteger($fieldName);
×
68
                }
69

70
                $table
×
71
                    ->foreign($fieldName)
×
72
                    ->references('id')
×
73
                    ->on($this->getTableName($toEntity))
×
74
                    ->onDelete($onDelete);
×
75
            }
×
76
        );
×
77
    }
78

79
    public function dropForeignKey($fromEntity, $toEntity, $needDropField = false)
80
    {
81
        $field = Str::snake($toEntity) . '_id';
×
82
        $table = $this->getTableName($fromEntity);
×
83

84
        if (Schema::hasColumn($table, $field)) {
×
85
            Schema::table($table, function (Blueprint $table) use ($field, $needDropField) {
×
86
                $table->dropForeign([$field]);
×
87

88
                if ($needDropField) {
×
89
                    $table->dropColumn([$field]);
×
90
                }
91
            });
×
92
        }
93
    }
94

95
    public function createBridgeTable($fromEntity, $toEntity)
96
    {
97
        $bridgeTableName = $this->getBridgeTable($fromEntity, $toEntity);
×
98

99
        Schema::create($bridgeTableName, function (Blueprint $table) {
×
100
            $table->increments('id');
×
101
        });
×
102

103
        $this->addForeignKey($bridgeTableName, $fromEntity, true);
×
104
        $this->addForeignKey($bridgeTableName, $toEntity, true);
×
105
    }
106

107
    public function dropBridgeTable($fromEntity, $toEntity)
108
    {
109
        $bridgeTableName = $this->getBridgeTable($fromEntity, $toEntity);
×
110

111
        $this->dropForeignKey($bridgeTableName, $fromEntity, true);
×
112
        $this->dropForeignKey($bridgeTableName, $toEntity, true);
×
113

114
        Schema::drop($bridgeTableName);
×
115
    }
116

117
    protected function getBridgeTable($fromEntity, $toEntity)
118
    {
119
        $entities = [Str::snake($fromEntity), Str::snake($toEntity)];
×
120
        sort($entities, SORT_STRING);
×
121

122
        return implode('_', $entities);
×
123
    }
124

125
    protected function getTableName($entityName)
126
    {
127
        if (Schema::hasTable($entityName)) {
×
128
            return $entityName;
×
129
        }
130

131
        $entityName = Str::snake($entityName);
×
132

133
        return Str::plural($entityName);
×
134
    }
135
}
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