Completed
Branch feature/pre-split (406cca)
by Anton
08:47
created

AbstractReference::references()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 3
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
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
     * Parent table isolation prefix.
21
     *
22
     * @var string
23
     */
24
    protected $tablePrefix = '';
25
26
    /**
27
     * Local column name (key name).
28
     *
29
     * @var string
30
     */
31
    protected $column = '';
32
33
    /**
34
     * Referenced table name (including prefix).
35
     *
36
     * @var string
37
     */
38
    protected $foreignTable = '';
39
40
    /**
41
     * Linked foreign key name (foreign column).
42
     *
43
     * @var string
44
     */
45
    protected $foreignKey = '';
46
47
    /**
48
     * Action on foreign column value deletion.
49
     *
50
     * @var string
51
     */
52
    protected $deleteRule = self::NO_ACTION;
53
54
    /**
55
     * Action on foreign column value update.
56
     *
57
     * @var string
58
     */
59
    protected $updateRule = self::NO_ACTION;
60
61
    /**
62
     * @param string $table
63
     * @param string $tablePrefix
64
     * @param string $name
65
     */
66
    public function __construct(string $table, string $tablePrefix, string $name)
67
    {
68
        parent::__construct($table, $name);
69
        $this->tablePrefix = $tablePrefix;
70
    }
71
72
    /**
73
     * {@inheritdoc}
74
     *
75
     * @param string $name
76
     */
77
    public function setName(string $name): AbstractElement
78
    {
79
        if (!empty($this->name)) {
80
            throw new SchemaException('Changing reference name is not allowed');
81
        }
82
83
        return parent::setName($name);
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89
    public function getColumn(): string
90
    {
91
        return $this->column;
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97
    public function getForeignTable(): string
98
    {
99
        return $this->foreignTable;
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105
    public function getForeignKey(): string
106
    {
107
        return $this->foreignKey;
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113
    public function getDeleteRule(): string
114
    {
115
        return $this->deleteRule;
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function getUpdateRule(): string
122
    {
123
        return $this->updateRule;
124
    }
125
126
    /**
127
     * Set local column name foreign key relates to. Make sure column type is the same as foreign
128
     * column one.
129
     *
130
     * @param string $column
131
     *
132
     * @return self
133
     */
134
    public function column(string $column): AbstractReference
135
    {
136
        $this->column = $column;
137
138
        return $this;
139
    }
140
141
    /**
142
     * Set foreign table name and key local column must reference to. Make sure local and foreign
143
     * column types are identical.
144
     *
145
     * @param string $table       Foreign table name with or without database prefix (see 3rd
146
     *                            argument).
147
     * @param string $column      Foreign key name (id by default).
148
     * @param bool   $forcePrefix When true foreign table will get same prefix as table being
149
     *                            modified.
150
     *
151
     * @return self
152
     */
153
    public function references(
154
        string $table,
155
        string $column = 'id',
156
        bool $forcePrefix = true
157
    ): AbstractReference {
158
        $this->foreignTable = ($forcePrefix ? $this->tablePrefix : '') . $table;
159
        $this->foreignKey = $column;
160
161
        return $this;
162
    }
163
164
    /**
165
     * Set foreign key delete behaviour.
166
     *
167
     * @param string $rule Possible values: NO ACTION, CASCADE, etc (driver specific).
168
     *
169
     * @return self
170
     */
171
    public function onDelete(string $rule = self::NO_ACTION): AbstractReference
172
    {
173
        $this->deleteRule = strtoupper($rule);
174
175
        return $this;
176
    }
177
178
    /**
179
     * Set foreign key update behaviour.
180
     *
181
     * @param string $rule Possible values: NO ACTION, CASCADE, etc (driver specific).
182
     *
183
     * @return self
184
     */
185
    public function onUpdate(string $rule = self::NO_ACTION): AbstractReference
186
    {
187
        $this->updateRule = strtoupper($rule);
188
189
        return $this;
190
    }
191
192
    /**
193
     * Foreign key creation syntax.
194
     *
195
     * @param Driver $driver
196
     *
197
     * @return string
198
     */
199
    public function sqlStatement(Driver $driver): string
200
    {
201
        $statement = [];
202
203
        $statement[] = 'CONSTRAINT';
204
        $statement[] = $driver->identifier($this->name);
205
        $statement[] = 'FOREIGN KEY';
206
        $statement[] = '(' . $driver->identifier($this->column) . ')';
207
208
        $statement[] = 'REFERENCES ' . $driver->identifier($this->foreignTable);
209
        $statement[] = '(' . $driver->identifier($this->foreignKey) . ')';
210
211
        $statement[] = "ON DELETE {$this->deleteRule}";
212
        $statement[] = "ON UPDATE {$this->updateRule}";
213
214
        return implode(' ', $statement);
215
    }
216
217
    /**
218
     * {@inheritdoc}
219
     */
220
    public function compare(ReferenceInterface $initial): bool
221
    {
222
        return $this == clone $initial;
223
    }
224
}