Completed
Branch feature/pre-split (f1ffcf)
by Anton
03:59
created

TableState::__clone()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 8
nop 0
dl 0
loc 14
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\Database\Schemas;
10
11
use Spiral\Database\Schemas\Prototypes\AbstractColumn;
12
use Spiral\Database\Schemas\Prototypes\AbstractIndex;
13
use Spiral\Database\Schemas\Prototypes\AbstractReference;
14
15
/**
16
 * TableSchema helper used to store original table elements and run comparation between them.
17
 *
18
 * Attention: this state IS MUTABLE!
19
 */
20
class TableState
21
{
22
    /**
23
     * @var string
24
     */
25
    private $name = '';
26
27
    /**
28
     * @var AbstractColumn[]
29
     */
30
    private $columns = [];
31
32
    /**
33
     * @var AbstractIndex[]
34
     */
35
    private $indexes = [];
36
37
    /**
38
     * @var AbstractReference[]
39
     */
40
    private $foreigns = [];
41
42
    /**
43
     * Primary key columns are stored separately from other indexes and can be modified only during
44
     * table creation.
45
     *
46
     * @var array
47
     */
48
    private $primaryKeys = [];
49
50
    /**
51
     * @param string $name
52
     */
53
    public function __construct(string $name)
54
    {
55
        $this->name = $name;
56
    }
57
58
    /**
59
     * Set table name. Operation will be applied at moment of saving.
60
     *
61
     * @param string $name
62
     */
63
    public function setName(string $name)
64
    {
65
        $this->name = $name;
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function getName()
72
    {
73
        return $this->name;
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     *
79
     * Array key points to initial element name.
80
     *
81
     * @return AbstractColumn[]
82
     */
83
    public function getColumns()
84
    {
85
        return $this->columns;
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     *
91
     * Array key points to initial element name.
92
     *
93
     * @return AbstractIndex[]
94
     */
95
    public function getIndexes()
96
    {
97
        return $this->indexes;
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     *
103
     * Array key points to initial element name.
104
     *
105
     * @return AbstractReference[]
106
     */
107
    public function getForeigns()
108
    {
109
        return $this->foreigns;
110
    }
111
112
    /**
113
     * Set table primary keys.
114
     *
115
     * @param array $columns
116
     *
117
     * @return $this
118
     */
119
    public function setPrimaryKeys(array $columns)
120
    {
121
        $this->primaryKeys = $columns;
122
123
        return $this;
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     *
129
     * Method combines primary keys with primary keys automatically calculated based on registred
130
     * columns.
131
     */
132
    public function getPrimaryKeys()
133
    {
134
        $primaryColumns = [];
135
        foreach ($this->getColumns() as $column) {
136
            if ($column->abstractType() == 'primary' || $column->abstractType() == 'bigPrimary') {
137
                if (!in_array($column->getName(), $this->primaryKeys)) {
138
                    //Only columns not listed as primary keys already
139
                    $primaryColumns[] = $column->getName();
140
                }
141
            }
142
        }
143
144
        return array_unique(array_merge($this->primaryKeys, $primaryColumns));
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     *
150
     * Lookup is performed based on initial column name.
151
     */
152
    public function hasColumn(string $name): bool
153
    {
154
        return !empty($this->findColumn($name));
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160
    public function hasIndex(array $columns = []): bool
161
    {
162
        return !empty($this->findIndex($columns));
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function hasForeign($column): bool
169
    {
170
        return !empty($this->findForeign($column));
171
    }
172
173
    /**
174
     * Register new column element.
175
     *
176
     * @param AbstractColumn $column
177
     *
178
     * @return AbstractColumn
179
     */
180
    public function registerColumn(AbstractColumn $column): AbstractColumn
181
    {
182
        $this->columns[$column->getName()] = $column;
183
184
        return $column;
185
    }
186
187
    /**
188
     * Register new index element.
189
     *
190
     * @param AbstractIndex $index
191
     *
192
     * @return AbstractIndex
193
     */
194
    public function registerIndex(AbstractIndex $index): AbstractIndex
195
    {
196
        $this->indexes[$index->getName()] = $index;
197
198
        return $index;
199
    }
200
201
    /**
202
     * Register new foreign key element.
203
     *
204
     * @param AbstractReference $foreign
205
     *
206
     * @return AbstractReference
207
     */
208
    public function registerForeign(AbstractReference $foreign): AbstractReference
209
    {
210
        $this->foreigns[$foreign->getName()] = $foreign;
211
212
        return $foreign;
213
    }
214
215
    /**
216
     * Drop column from table schema.
217
     *
218
     * @param AbstractColumn $column
219
     *
220
     * @return self
221
     */
222
    public function forgetColumn(AbstractColumn $column): TableState
223
    {
224
        foreach ($this->columns as $name => $columnSchema) {
225
            if ($columnSchema == $column) {
226
                unset($this->columns[$name]);
227
                break;
228
            }
229
        }
230
231
        return $this;
232
    }
233
234
    /**
235
     * Drop index from table schema using it's name or forming columns.
236
     *
237
     * @param AbstractIndex $index
238
     *
239
     * @return self
240
     */
241
    public function forgetIndex(AbstractIndex $index): TableState
242
    {
243
        foreach ($this->indexes as $name => $indexSchema) {
244
            if ($indexSchema == $index) {
245
                unset($this->indexes[$name]);
246
                break;
247
            }
248
        }
249
250
        return $this;
251
    }
252
253
    /**
254
     * Drop foreign key from table schema using it's forming column.
255
     *
256
     * @param AbstractReference $foreign
257
     *
258
     * @return self
259
     */
260
    public function forgetForeign(AbstractReference $foreign): TableState
261
    {
262
        foreach ($this->foreigns as $name => $foreignSchema) {
263
            if ($foreignSchema == $foreign) {
264
                unset($this->foreigns[$name]);
265
                break;
266
            }
267
        }
268
269
        return $this;
270
    }
271
272
    /**
273
     * Find column by it's name or return null.
274
     *
275
     * @param string $name
276
     *
277
     * @return null|AbstractColumn
278
     */
279
    public function findColumn(string $name)
280
    {
281
        foreach ($this->columns as $column) {
282
            if ($column->getName() == $name) {
283
                return $column;
284
            }
285
        }
286
287
        return null;
288
    }
289
290
    /**
291
     * Find index by it's columns or return null.
292
     *
293
     * @param array $columns
294
     *
295
     * @return null|AbstractIndex
296
     */
297
    public function findIndex(array $columns)
298
    {
299
        foreach ($this->indexes as $index) {
300
            if ($index->getColumns() == $columns) {
301
                return $index;
302
            }
303
        }
304
305
        return null;
306
    }
307
308
    /**
309
     * Find foreign key by it's column or return null.
310
     *
311
     * @param string $column
312
     *
313
     * @return null|AbstractReference
314
     */
315
    public function findForeign(string $column)
316
    {
317
        foreach ($this->foreigns as $reference) {
318
            if ($reference->getColumn() == $column) {
319
                return $reference;
320
            }
321
        }
322
323
        return null;
324
    }
325
326
    /**
327
     * Remount elements under their current name.
328
     */
329
    public function remountElements()
330
    {
331
        $columns = [];
332
        foreach ($this->columns as $column) {
333
            $columns[$column->getName()] = $column;
334
        }
335
336
        $indexes = [];
337
        foreach ($this->indexes as $index) {
338
            $indexes[$index->getName()] = $index;
339
        }
340
341
        $references = [];
342
        foreach ($this->foreigns as $reference) {
343
            $references[$reference->getName()] = $reference;
344
        }
345
346
        $this->columns = $columns;
347
        $this->indexes = $indexes;
348
        $this->foreigns = $references;
349
    }
350
351
    /**
352
     * Re-populate schema elements using other state as source. Elements will be cloned under their
353
     * schema name.
354
     *
355
     * @param TableState $source
356
     *
357
     * @return self
358
     */
359
    public function syncState(TableState $source): self
360
    {
361
        $this->name = $source->name;
362
        $this->primaryKeys = $source->primaryKeys;
363
364
        $this->columns = [];
365
        foreach ($source->columns as $name => $column) {
366
            $this->columns[$name] = clone $column;
367
        }
368
369
        $this->indexes = [];
370
        foreach ($source->indexes as $name => $index) {
371
            $this->indexes[$name] = clone $index;
372
        }
373
374
        $this->foreigns = [];
375
        foreach ($source->foreigns as $name => $reference) {
376
            $this->foreigns[$name] = clone $reference;
377
        }
378
379
        $this->remountElements();
380
381
        return $this;
382
    }
383
384
    /**
385
     * Cloning all elements.
386
     */
387
    public function __clone()
388
    {
389
        foreach ($this->columns as $name => $column) {
390
            $this->columns[$name] = clone $column;
391
        }
392
393
        foreach ($this->indexes as $name => $index) {
394
            $this->indexes[$name] = clone $index;
395
        }
396
397
        foreach ($this->foreigns as $name => $foreign) {
398
            $this->foreigns[$name] = clone $foreign;
399
        }
400
    }
401
}
402