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

TableState::findIndex()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 1
dl 0
loc 10
rs 9.4285
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
     * @param string $name
149
     *
150
     * @return bool
151
     */
152
    public function knowsColumn(string $name): bool
153
    {
154
        return isset($this->columns[$name]);
155
    }
156
157
    /**
158
     * @param string $name
159
     *
160
     * @return bool
161
     */
162
    public function knowsIndex(string $name): bool
163
    {
164
        return isset($this->indexes[$name]);
165
    }
166
167
    /**
168
     * @param string $name
169
     *
170
     * @return bool
171
     */
172
    public function knowsForeign(string $name): bool
173
    {
174
        return isset($this->foreigns[$name]);
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     *
180
     * Lookup is performed based on initial column name.
181
     */
182
    public function hasColumn(string $name): bool
183
    {
184
        return !empty($this->findColumn($name));
185
    }
186
187
    /**
188
     * {@inheritdoc}
189
     */
190
    public function hasIndex(array $columns = []): bool
191
    {
192
        return !empty($this->findIndex($columns));
193
    }
194
195
    /**
196
     * {@inheritdoc}
197
     */
198
    public function hasForeign($column): bool
199
    {
200
        return !empty($this->findForeign($column));
201
    }
202
203
    /**
204
     * Register new column element.
205
     *
206
     * @param AbstractColumn $column
207
     *
208
     * @return AbstractColumn
209
     */
210
    public function registerColumn(AbstractColumn $column): AbstractColumn
211
    {
212
        $this->columns[$column->getName()] = $column;
213
214
        return $column;
215
    }
216
217
    /**
218
     * Register new index element.
219
     *
220
     * @param AbstractIndex $index
221
     *
222
     * @return AbstractIndex
223
     */
224
    public function registerIndex(AbstractIndex $index): AbstractIndex
225
    {
226
        $this->indexes[$index->getName()] = $index;
227
228
        return $index;
229
    }
230
231
    /**
232
     * Register new foreign key element.
233
     *
234
     * @param AbstractReference $foreign
235
     *
236
     * @return AbstractReference
237
     */
238
    public function registerReference(AbstractReference $foreign): AbstractReference
239
    {
240
        $this->foreigns[$foreign->getName()] = $foreign;
241
242
        return $foreign;
243
    }
244
245
    /**
246
     * Drop column from table schema.
247
     *
248
     * @param AbstractColumn $column
249
     *
250
     * @return self
251
     */
252
    public function forgetColumn(AbstractColumn $column): TableState
253
    {
254
        foreach ($this->columns as $name => $columnSchema) {
255
            if ($columnSchema == $column) {
256
                unset($this->columns[$name]);
257
                break;
258
            }
259
        }
260
261
        return $this;
262
    }
263
264
    /**
265
     * Drop index from table schema using it's name or forming columns.
266
     *
267
     * @param AbstractIndex $index
268
     *
269
     * @return self
270
     */
271
    public function forgetIndex(AbstractIndex $index): TableState
272
    {
273
        foreach ($this->indexes as $name => $indexSchema) {
274
            if ($indexSchema == $index) {
275
                unset($this->indexes[$name]);
276
                break;
277
            }
278
        }
279
280
        return $this;
281
    }
282
283
    /**
284
     * Drop foreign key from table schema using it's forming column.
285
     *
286
     * @param AbstractReference $foreign
287
     *
288
     * @return self
289
     */
290
    public function forgetForeign(AbstractReference $foreign): TableState
291
    {
292
        foreach ($this->foreigns as $name => $foreignSchema) {
293
            if ($foreignSchema == $foreign) {
294
                unset($this->foreigns[$name]);
295
                break;
296
            }
297
        }
298
299
        return $this;
300
    }
301
302
    /**
303
     * Find column by it's name or return null.
304
     *
305
     * @param string $name
306
     *
307
     * @return null|AbstractColumn
308
     */
309
    public function findColumn(string $name)
310
    {
311
        foreach ($this->columns as $column) {
312
            if ($column->getName() == $name) {
313
                return $column;
314
            }
315
        }
316
317
        return null;
318
    }
319
320
    /**
321
     * Find index by it's columns or return null.
322
     *
323
     * @param array $columns
324
     *
325
     * @return null|AbstractIndex
326
     */
327
    public function findIndex(array $columns)
328
    {
329
        foreach ($this->indexes as $index) {
330
            if ($index->getColumns() == $columns) {
331
                return $index;
332
            }
333
        }
334
335
        return null;
336
    }
337
338
    /**
339
     * Find foreign key by it's column or return null.
340
     *
341
     * @param string $column
342
     *
343
     * @return null|AbstractReference
344
     */
345
    public function findForeign(string $column)
346
    {
347
        foreach ($this->foreigns as $reference) {
348
            if ($reference->getColumn() == $column) {
349
                return $reference;
350
            }
351
        }
352
353
        return null;
354
    }
355
356
    /**
357
     * Remount elements under their current name.
358
     */
359
    public function remountElements()
360
    {
361
        $columns = [];
362
        foreach ($this->columns as $column) {
363
            $columns[$column->getName()] = $column;
364
        }
365
366
        $indexes = [];
367
        foreach ($this->indexes as $index) {
368
            $indexes[$index->getName()] = $index;
369
        }
370
371
        $references = [];
372
        foreach ($this->foreigns as $reference) {
373
            $references[$reference->getName()] = $reference;
374
        }
375
376
        $this->columns = $columns;
377
        $this->indexes = $indexes;
378
        $this->foreigns = $references;
379
    }
380
381
    /**
382
     * Re-populate schema elements using other state as source. Elements will be cloned under their
383
     * schema name.
384
     *
385
     * @param self $source
386
     *
387
     * @return self
388
     */
389
    public function syncState(self $source): self
390
    {
391
        $this->name = $source->name;
392
        $this->primaryKeys = $source->primaryKeys;
393
394
        $this->columns = [];
395
        foreach ($source->columns as $name => $column) {
396
            $this->columns[$name] = clone $column;
397
        }
398
399
        $this->indexes = [];
400
        foreach ($source->indexes as $name => $index) {
401
            $this->indexes[$name] = clone $index;
402
        }
403
404
        $this->foreigns = [];
405
        foreach ($source->foreigns as $name => $reference) {
406
            $this->foreigns[$name] = clone $reference;
407
        }
408
409
        return $this;
410
    }
411
}
412