Issues (90)

src/database/ForeignKey.php (5 issues)

1
<?php
2
namespace yentu\database;
3
4
use yentu\exceptions\SyntaxErrorException;
5
6
class ForeignKey extends DatabaseItem implements Commitable, Changeable, Initializable
7
{
8
    private Table $table;
9
    private array $columns;
10
    private Table $foreignTable;
11
    private array $foreignColumns;
12
    private string $name = '';
13
    public string $onDelete;
14
    public string $onUpdate;
15
    public static string $defaultOnDelete = 'NO ACTION';
16
    public static string $defaultOnUpdate = 'NO ACTION';
17
18
    public function __construct(array $columns, Table $table)
19
    {
20
        $this->table = $table;
21
        $this->columns = $columns;
22
        $this->onDelete = self::$defaultOnDelete;
23
        $this->onUpdate = self::$defaultOnUpdate;
24
    }
25
26
    #[\Override]
27
    public function initialize()
28
    {
29
        $name = $this->getChangeLogger()->doesForeignKeyExist([
0 ignored issues
show
The method doesForeignKeyExist() does not exist on yentu\ChangeLogger. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

29
        $name = $this->getChangeLogger()->/** @scrutinizer ignore-call */ doesForeignKeyExist([
Loading history...
30
            'schema' => $this->table->getSchema()->getName(),
31
            'table' => $this->table->getName(),
32
            'columns' => $this->columns
33
        ]);
34
        if ($name === false) {
35
            $this->new = true;
36
        } else {
37
            $this->name = $name;
38
        }
39
    }
40
41
    /**
42
     * 
43
     * @param \yentu\database\Table $table
44
     * @return \yentu\database\ForeignKey
45
     */
46
    public function references(Table $table): DatabaseItem
47
    {
48
        if ($table->isReference()) {
49
            $this->foreignTable = $table;
50
        } else {
51
            throw new \yentu\exceptions\DatabaseManipulatorException(
52
                    "References cannot be created from a non referencing table. "
53
                    . "Please use either a reftable() or refschema() "
54
                    . "construct to link a referenced table"
55
            );
56
        }
57
        return $this;
58
    }
59
60
    public function columns(string ...$args)
61
    {
62
        $this->foreignColumns = $args;
63
        return $this;
64
    }
65
66
    public function drop()
67
    {
68
        $description = $this->getChangeLogger()->getDescription();
0 ignored issues
show
The method getDescription() does not exist on yentu\ChangeLogger. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

68
        $description = $this->getChangeLogger()->/** @scrutinizer ignore-call */ getDescription();
Loading history...
69
        $key = $description['schemata'][$this->table->getSchema()->getName()]['tables'][$this->table->getName()]['foreign_keys'][$this->name];
70
71
        $this->getChangeLogger()->dropForeignKey(
0 ignored issues
show
The method dropForeignKey() does not exist on yentu\ChangeLogger. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

71
        $this->getChangeLogger()->/** @scrutinizer ignore-call */ dropForeignKey(
Loading history...
72
            array(
73
                'columns' => $this->columns,
74
                'table' => $this->table->getName(),
75
                'schema' => $this->table->getSchema()->getName(),
76
                'foreign_columns' => $key['foreign_columns'],
77
                'foreign_table' => $key['foreign_table'],
78
                'foreign_schema' => $key['foreign_schema'],
79
                'name' => $this->name,
80
                'on_delete' => $key['on_delete'],
81
                'on_update' => $key['on_update']
82
            )
83
        );
84
        return $this;
85
    }
86
87
    private function validate()
88
    {
89
        if (!is_array($this->foreignColumns)) {
0 ignored issues
show
The condition is_array($this->foreignColumns) is always true.
Loading history...
90
            throw new SyntaxErrorException("No foreign columns specified for foreign key {$this->name}", $this->home);
91
        }
92
    }
93
94
    #[\Override]
95
    public function commitNew()
96
    {
97
        $this->validate();
98
        if ($this->name == '' && is_object($this->foreignTable)) {
99
            $this->name = $this->table->getName() . '_' . implode('_', $this->columns) .
100
                '_' . $this->foreignTable->getName() .
101
                '_' . implode('_', $this->foreignColumns) . '_fk';
102
        } else if (!is_object($this->foreignTable)) {
103
            throw new \yentu\exceptions\DatabaseManipulatorException(
104
                    "No references defined for foreign key {$this->name}"
105
            );
106
        }
107
108
        $this->getChangeLogger()->addForeignKey($this->buildDescription());
0 ignored issues
show
The method addForeignKey() does not exist on yentu\ChangeLogger. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

108
        $this->getChangeLogger()->/** @scrutinizer ignore-call */ addForeignKey($this->buildDescription());
Loading history...
109
    }
110
111
    public function name($name)
112
    {
113
        if ($this->getChangeLogger()->doesForeignKeyExist([
114
                'schema' => $this->table->getSchema()->getName(),
115
                'table' => $this->table->getName(),
116
                'name' => $name
117
            ])) {
118
            $this->setKeyDetails($name);
119
            $this->new = false;
120
        }
121
        $this->name = $name;
122
        return $this;
123
    }
124
125
    private function setKeyDetails($name)
126
    {
127
        $foreignKey = $this->getChangeLogger()
128
                ->getDescription()
129
                ->getTable([
130
                    'table' => $this->table->getName(),
131
                    'schema' => $this->table->getSchema()->getName()
132
                    ]
133
                )['foreign_keys'][$name];
134
        $this->columns = $foreignKey['columns'];
135
        $this->foreignTable = new Table($foreignKey['foreign_table'], new Schema($foreignKey['foreign_schema']));
136
        $this->foreignTable->setIsReference(true);
137
        $this->foreignColumns = $foreignKey['foreign_columns'];
138
        $this->onUpdate = $foreignKey['on_update'];
139
        $this->onDelete = $foreignKey['on_delete'];
140
    }
141
142
    public function onDelete($onDelete)
143
    {
144
        return $this->addChange('onDelete', 'on_delete', $onDelete);
145
    }
146
147
    public function onUpdate($onUpdate)
148
    {
149
        return $this->addChange('onUpdate', 'on_update', $onUpdate);
150
    }
151
152
    #[\Override]
153
    public function buildDescription()
154
    {
155
        if ($this->foreignTable === null) {
156
            throw new \yentu\exceptions\DatabaseManipulatorException(
157
                    "No references defined for foreign key {$this->name}"
158
            );
159
        }
160
        return array(
161
            'columns' => $this->columns,
162
            'table' => $this->table->getName(),
163
            'schema' => $this->table->getSchema()->getName(),
164
            'foreign_columns' => $this->foreignColumns,
165
            'foreign_table' => $this->foreignTable->getName(),
166
            'foreign_schema' => $this->foreignTable->getSchema()->getName(),
167
            'name' => $this->name,
168
            'on_delete' => $this->onDelete,
169
            'on_update' => $this->onUpdate
170
        );
171
    }
172
}
173