Passed
Push — main ( 3f5d4e...df4575 )
by James Ekow Abaka
01:53
created

ForeignKey::init()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 10
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 13
rs 9.9332
1
<?php
2
3
namespace yentu\database;
4
5
use yentu\exceptions\SyntaxErrorException;
6
7
class ForeignKey extends DatabaseItem implements Commitable
8
{
9
10
    /**
11
     *
12
     * @var Table
13
     */
14
    private $table;
15
    private $columns;
16
    private $foreignTable;
17
    private $foreignColumns;
18
    private $name;
19
    private $nameSet;
20
    public $onDelete;
21
    public $onUpdate;
22
    public static $defaultOnDelete = 'NO ACTION';
23
    public static $defaultOnUpdate = 'NO ACTION';
24
25
    public function __construct($columns, $table) {
26
        $this->table = $table;
27
        $this->columns = $columns;
28
        $this->onDelete = self::$defaultOnDelete;
29
        $this->onUpdate = self::$defaultOnUpdate;
30
31
        // Prevent the committing of the foreign key even if the context
32
        // switches
33
    }
34
    
35
    #[\Override]
36
    public function init()
37
    {
38
        $name = $this->getDriver()->doesForeignKeyExist([
0 ignored issues
show
Bug introduced by
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

38
        $name = $this->getDriver()->/** @scrutinizer ignore-call */ doesForeignKeyExist([
Loading history...
39
            'schema' => $this->table->getSchema()->getName(),
40
            'table' => $this->table->getName(),
41
            'columns' => $this->columns
42
        ]);
43
        if ($name === false) {
44
            $this->new = true;
45
        } else {
46
            $this->name = $name;
47
            $this->nameSet = true;
48
        }
49
    }
50
51
    /**
52
     * 
53
     * @param \yentu\database\Table $table
54
     * @return \yentu\database\ForeignKey
55
     */
56
    public function references($table) {
57
        if ($table->isReference()) {
58
            $this->foreignTable = $table;
59
        } else {
60
            throw new \yentu\exceptions\DatabaseManipulatorException(
61
            "References cannot be created from a non referencing table. "
62
            . "Please use either a reftable() or refschema() "
63
            . "construct to link a referenced table"
64
            );
65
        }
66
        return $this;
67
    }
68
69
    public function columns() {
70
        $this->foreignColumns = func_get_args();
71
        return $this;
72
    }
73
74
    public function drop() {
75
        $description = $this->getDriver()->getDescription();
0 ignored issues
show
Bug introduced by
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

75
        $description = $this->getDriver()->/** @scrutinizer ignore-call */ getDescription();
Loading history...
76
        $key = $description['schemata'][$this->table->getSchema()->getName()]['tables'][$this->table->getName()]['foreign_keys'][$this->name];
77
78
        $this->getDriver()->dropForeignKey(
0 ignored issues
show
Bug introduced by
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

78
        $this->getDriver()->/** @scrutinizer ignore-call */ dropForeignKey(
Loading history...
79
                array(
80
                    'columns' => $this->columns,
81
                    'table' => $this->table->getName(),
82
                    'schema' => $this->table->getSchema()->getName(),
83
                    'foreign_columns' => $key['foreign_columns'],
84
                    'foreign_table' => $key['foreign_table'],
85
                    'foreign_schema' => $key['foreign_schema'],
86
                    'name' => $this->name,
87
                    'on_delete' => $key['on_delete'],
88
                    'on_update' => $key['on_update']
89
                )
90
        );
91
        return $this;
92
    }
93
94
    private function validate() {
95
        if (!is_array($this->foreignColumns)) {
96
            throw new SyntaxErrorException("No foreign columns specified for foreign key {$this->name}", $this->home);
97
        }
98
    }
99
100
    #[\Override]
101
    public function commitNew() {
102
        $this->validate();
103
        if ($this->name == '' && is_object($this->foreignTable)) {
104
            $this->name = $this->table->getName() . '_' . implode('_', $this->columns) .
105
                    '_' . $this->foreignTable->getName() .
106
                    '_' . implode('_', $this->foreignColumns) . '_fk';
107
        } else if (!is_object($this->foreignTable)) {
108
            throw new \yentu\exceptions\DatabaseManipulatorException(
109
            "No references defined for foreign key {$this->name}"
110
            );
111
        }
112
113
        $this->getDriver()->addForeignKey($this->buildDescription());
0 ignored issues
show
Bug introduced by
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

113
        $this->getDriver()->/** @scrutinizer ignore-call */ addForeignKey($this->buildDescription());
Loading history...
114
    }
115
116
    public function name($name) {
117
        if ($this->getDriver()->doesForeignKeyExist([
118
                    'schema' => $this->table->getSchema()->getName(),
119
                    'table' => $this->table->getName(),
120
                    'name' => $name
121
                ])) {
122
            $this->setKeyDetails($name);
123
            $this->new = false;
124
        }
125
        $this->name = $name;
126
        $this->nameSet = true;
127
        return $this;
128
    }
129
130
    private function setKeyDetails($name) {
131
        $foreignKey = $this->getDriver()
132
                        ->getDescription()
133
                        ->getTable([
134
                            'table' => $this->table->getName(),
135
                            'schema' => $this->table->getSchema()->getName()
136
                                ]
137
                        )['foreign_keys'][$name];
138
        $this->columns = $foreignKey['columns'];
139
        $this->foreignTable = new Table($foreignKey['foreign_table'], new Schema($foreignKey['foreign_schema']));
140
        $this->foreignTable->setIsReference(true);
141
        $this->foreignColumns = $foreignKey['foreign_columns'];
142
        $this->onUpdate = $foreignKey['on_update'];
143
        $this->onDelete = $foreignKey['on_delete'];
144
    }
145
146
    public function onDelete($onDelete) {
147
        return $this->addChange('onDelete', 'on_delete', $onDelete);
148
    }
149
150
    public function onUpdate($onUpdate) {
151
        return $this->addChange('onUpdate', 'on_update', $onUpdate);
152
    }
153
154
    protected function buildDescription() {
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
}
174