|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* components |
|
4
|
|
|
* |
|
5
|
|
|
* @author Wolfy-J |
|
6
|
|
|
*/ |
|
7
|
|
|
namespace Spiral\Database\Schemas\Prototypes; |
|
8
|
|
|
|
|
9
|
|
|
use Spiral\Database\Entities\Driver; |
|
10
|
|
|
use Spiral\Database\Exceptions\SchemaException; |
|
11
|
|
|
use Spiral\Database\Schemas\ReferenceInterface; |
|
12
|
|
|
|
|
13
|
|
|
/** |
|
14
|
|
|
* Abstract foreign schema with read (see ReferenceInterface) and write abilities. Must be |
|
15
|
|
|
* implemented by driver to support DBMS specific syntax and creation rules. |
|
16
|
|
|
*/ |
|
17
|
|
|
abstract class AbstractReference extends AbstractElement implements ReferenceInterface |
|
18
|
|
|
{ |
|
19
|
|
|
/** |
|
20
|
|
|
* Local column name (key name). |
|
21
|
|
|
* |
|
22
|
|
|
* @var string |
|
23
|
|
|
*/ |
|
24
|
|
|
protected $column = ''; |
|
25
|
|
|
|
|
26
|
|
|
/** |
|
27
|
|
|
* Referenced table name (including prefix). |
|
28
|
|
|
* |
|
29
|
|
|
* @var string |
|
30
|
|
|
*/ |
|
31
|
|
|
protected $foreignTable = ''; |
|
32
|
|
|
|
|
33
|
|
|
/** |
|
34
|
|
|
* Linked foreign key name (foreign column). |
|
35
|
|
|
* |
|
36
|
|
|
* @var string |
|
37
|
|
|
*/ |
|
38
|
|
|
protected $foreignKey = ''; |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* Action on foreign column value deletion. |
|
42
|
|
|
* |
|
43
|
|
|
* @var string |
|
44
|
|
|
*/ |
|
45
|
|
|
protected $deleteRule = self::NO_ACTION; |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* Action on foreign column value update. |
|
49
|
|
|
* |
|
50
|
|
|
* @var string |
|
51
|
|
|
*/ |
|
52
|
|
|
protected $updateRule = self::NO_ACTION; |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* {@inheritdoc} |
|
56
|
|
|
* |
|
57
|
|
|
* @param string $name |
|
58
|
|
|
*/ |
|
59
|
|
|
public function setName(string $name): AbstractElement |
|
60
|
|
|
{ |
|
61
|
|
|
if (!empty($this->name)) { |
|
62
|
|
|
throw new SchemaException('Changing reference name is not allowed'); |
|
|
|
|
|
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
return parent::setName($name); |
|
66
|
|
|
} |
|
67
|
|
|
|
|
68
|
|
|
/** |
|
69
|
|
|
* {@inheritdoc} |
|
70
|
|
|
*/ |
|
71
|
|
|
public function getName(): string |
|
72
|
|
|
{ |
|
73
|
|
|
if (empty($this->name)) { |
|
74
|
|
|
//Generating name on a fly |
|
75
|
|
|
$this->setName($this->generateName()); |
|
76
|
|
|
} |
|
77
|
|
|
|
|
78
|
|
|
return parent::getName(); |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* {@inheritdoc} |
|
83
|
|
|
*/ |
|
84
|
|
|
public function getColumn(): string |
|
85
|
|
|
{ |
|
86
|
|
|
return $this->column; |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
|
|
/** |
|
90
|
|
|
* {@inheritdoc} |
|
91
|
|
|
*/ |
|
92
|
|
|
public function getForeignTable(): string |
|
93
|
|
|
{ |
|
94
|
|
|
return $this->foreignTable; |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
/** |
|
98
|
|
|
* {@inheritdoc} |
|
99
|
|
|
*/ |
|
100
|
|
|
public function getForeignKey(): string |
|
101
|
|
|
{ |
|
102
|
|
|
return $this->foreignKey; |
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
|
|
/** |
|
106
|
|
|
* {@inheritdoc} |
|
107
|
|
|
*/ |
|
108
|
|
|
public function getDeleteRule(): string |
|
109
|
|
|
{ |
|
110
|
|
|
return $this->deleteRule; |
|
111
|
|
|
} |
|
112
|
|
|
|
|
113
|
|
|
/** |
|
114
|
|
|
* {@inheritdoc} |
|
115
|
|
|
*/ |
|
116
|
|
|
public function getUpdateRule(): string |
|
117
|
|
|
{ |
|
118
|
|
|
return $this->updateRule; |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
|
|
//--- MODIFICATIONS |
|
122
|
|
|
|
|
123
|
|
|
/** |
|
124
|
|
|
* Foreign key creation syntax. |
|
125
|
|
|
* |
|
126
|
|
|
* @param Driver $driver |
|
127
|
|
|
* |
|
128
|
|
|
* @return string |
|
129
|
|
|
*/ |
|
130
|
|
|
public function sqlStatement(Driver $driver): string |
|
131
|
|
|
{ |
|
132
|
|
|
$statement = []; |
|
133
|
|
|
|
|
134
|
|
|
$statement[] = 'CONSTRAINT'; |
|
135
|
|
|
$statement[] = $driver->identifier($this->name); |
|
136
|
|
|
$statement[] = 'FOREIGN KEY'; |
|
137
|
|
|
$statement[] = '(' . $driver->identifier($this->column) . ')'; |
|
138
|
|
|
|
|
139
|
|
|
$statement[] = 'REFERENCES ' . $driver->identifier($this->foreignTable); |
|
140
|
|
|
$statement[] = '(' . $driver->identifier($this->foreignKey) . ')'; |
|
141
|
|
|
|
|
142
|
|
|
$statement[] = "ON DELETE {$this->deleteRule}"; |
|
143
|
|
|
$statement[] = "ON UPDATE {$this->updateRule}"; |
|
144
|
|
|
|
|
145
|
|
|
return implode(' ', $statement); |
|
146
|
|
|
} |
|
147
|
|
|
|
|
148
|
|
|
/** |
|
149
|
|
|
* {@inheritdoc} |
|
150
|
|
|
*/ |
|
151
|
|
|
public function compare(ReferenceInterface $initial): bool |
|
152
|
|
|
{ |
|
153
|
|
|
return $this == clone $initial; |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
/** |
|
157
|
|
|
* Generate unique foreign key name. |
|
158
|
|
|
* |
|
159
|
|
|
* @return string |
|
160
|
|
|
*/ |
|
161
|
|
|
protected function generateName(): string |
|
162
|
|
|
{ |
|
163
|
|
|
$name = $this->table . '_foreign_' . $this->column . '_' . uniqid(); |
|
164
|
|
|
|
|
165
|
|
|
if (strlen($name) > 64) { |
|
166
|
|
|
//Many dbs has limitations on identifier length |
|
167
|
|
|
$name = md5($name); |
|
168
|
|
|
} |
|
169
|
|
|
|
|
170
|
|
|
return $name; |
|
171
|
|
|
} |
|
172
|
|
|
} |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.