Completed
Branch feature/pre-split (5afa53)
by Anton
13:51
created

TableSchema::createReference()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\Database\Drivers\MySQL\Schemas;
8
9
use Spiral\Database\Exceptions\SchemaException;
10
use Spiral\Database\Schemas\Prototypes\AbstractColumn;
11
use Spiral\Database\Schemas\Prototypes\AbstractIndex;
12
use Spiral\Database\Schemas\Prototypes\AbstractReference;
13
use Spiral\Database\Schemas\Prototypes\AbstractTable;
14
use Spiral\Database\Schemas\TableState;
15
16
class TableSchema extends AbstractTable
17
{
18
    /**
19
     * List of most common MySQL table engines.
20
     */
21
    const ENGINE_INNODB = 'InnoDB';
22
    const ENGINE_MYISAM = 'MyISAM';
23
    const ENGINE_MEMORY = 'Memory';
24
25
    /**
26
     * MySQL table engine.
27
     *
28
     * @var string
29
     */
30
    private $engine = self::ENGINE_INNODB;
31
32
    /**
33
     * Populate table schema with values from database.
34
     *
35
     * @param TableState $state
36
     */
37
    protected function initSchema(TableState $state)
38
    {
39
        parent::initSchema($state);
40
41
        //Reading table schema
42
        $this->engine = $this->driver->query('SHOW TABLE STATUS WHERE `Name` = ?', [
43
            $state->getName()
44
        ])->fetch()['Engine'];
45
    }
46
47
    /**
48
     * Change table engine. Such operation will be applied only at moment of table creation.
49
     *
50
     * @param string $engine
51
     *
52
     * @return $this
53
     *
54
     * @throws SchemaException
55
     */
56
    public function setEngine($engine)
57
    {
58
        if ($this->exists()) {
59
            throw new SchemaException('Table engine can be set only at moment of creation');
60
        }
61
62
        $this->engine = $engine;
63
64
        return $this;
65
    }
66
67
    /**
68
     * @return string
69
     */
70
    public function getEngine()
71
    {
72
        return $this->engine;
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78
    protected function fetchColumns(): array
79
    {
80
        $query = "SHOW FULL COLUMNS FROM {$this->driver->identifier($this->getName())}";
81
82
        $result = [];
83
        foreach ($this->driver->query($query) as $schema) {
84
            $result[] = ColumnSchema::createInstance($this->getName(), $schema);
85
        }
86
87
        return $result;
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    protected function fetchIndexes(): array
94
    {
95
        $query = "SHOW INDEXES FROM {$this->driver->identifier($this->getName())}";
96
97
        //Gluing all index definitions together
98
        $schemas = [];
99
        foreach ($this->driver->query($query) as $index) {
100
            if ($index['Key_name'] == 'PRIMARY') {
101
                //Skipping PRIMARY index
102
                continue;
103
            }
104
105
            $schemas[$index['Key_name']][] = $index;
106
        }
107
108
        $result = [];
109
        foreach ($schemas as $name => $index) {
110
            $result[] = IndexSchema::createInstance($this->getName(), $name, $index);
111
        }
112
113
        return $result;
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    protected function fetchReferences(): array
120
    {
121
        $references = $this->driver->query(
122
            'SELECT * FROM `information_schema`.`referential_constraints` WHERE `constraint_schema` = ? AND `table_name` = ?',
123
            [$this->driver->getSource(), $this->getName()]
124
        );
125
126
        $result = [];
127
        foreach ($references as $schema) {
0 ignored issues
show
Bug introduced by
The expression $references of type object<Spiral\Database\E...Query\PDOResult>|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
128
            $references = 'SELECT * FROM `information_schema`.`key_column_usage` WHERE `constraint_name` = ? AND `table_schema` = ? AND `table_name` = ?';
129
130
            $column = $this->driver->query(
131
                $references,
132
                [$schema['CONSTRAINT_NAME'], $this->driver->getSource(), $this->getName()]
133
            )->fetch();
134
135
            $result[] = ReferenceSchema::createInstance(
136
                $this->getName(),
137
                $this->getPrefix(),
138
                $schema + $column
139
            );
140
        }
141
142
        return $result;
143
    }
144
145
    /**
146
     * Fetching primary keys from table.
147
     *
148
     * @return array
149
     */
150
    protected function fetchPrimaryKeys(): array
151
    {
152
        $query = "SHOW INDEXES FROM {$this->driver->identifier($this->getName())}";
153
154
        $primaryKeys = [];
155
        foreach ($this->driver->query($query) as $index) {
156
            if ($index['Key_name'] == 'PRIMARY') {
157
                $primaryKeys[] = $index['Column_name'];
158
            }
159
        }
160
161
        return $primaryKeys;
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    protected function createColumn(string $name): AbstractColumn
168
    {
169
        return new ColumnSchema($this->getName(), $name);
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    protected function createIndex(string $name): AbstractIndex
176
    {
177
        return new IndexSchema($this->getName(), $name);
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183
    protected function createReference(string $column): AbstractReference
184
    {
185
        return new ReferenceSchema($this->getName(), $this->getPrefix(), $column);
186
    }
187
}