TableDef::addIndex()   B
last analyzed

Complexity

Conditions 7
Paths 9

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7.0099

Importance

Changes 0
Metric Value
cc 7
eloc 18
nc 9
nop 2
dl 0
loc 31
ccs 16
cts 17
cp 0.9412
crap 7.0099
rs 8.8333
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Todd Burry <[email protected]>
4
 * @copyright 2009-2014 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
namespace Garden\Db;
9
10
/**
11
 * A helper class for creating database tables.
12
 */
13
class TableDef implements \JsonSerializable {
14
    /// Properties ///
15
16
    /**
17
     * @var array The columns that need to be set in the table.
18
     */
19
    private $columns;
20
21
    /**
22
     *
23
     * @var string The name of the currently working table.
24
     */
25
    private $table;
26
27
    /**
28
     * @var array An array of indexes.
29
     */
30
    private $indexes;
31
32
    /// Methods ///
33
34
    /**
35
     * Initialize an instance of the {@link TableDef} class.
36
     *
37
     * @param string $name The name of the table.
38
     */
39 48
    public function __construct($name = '') {
40 48
        $this->reset();
41 48
        $this->table = $name;
42 48
    }
43
44
    /**
45
     * Reset the internal state of this object so that it can be re-used.
46
     *
47
     * @return TableDef Returns $this for fluent calls.
48
     */
49 48
    public function reset() {
50 48
        $this->table = '';
51 48
        $this->columns = [];
52 48
        $this->indexes = [];
53
//        $this->options = [];
54
55 48
        return $this;
56
    }
57
58
    /**
59
     * Define a column.
60
     *
61
     * @param string $name The column name.
62
     * @param string $type The column type.
63
     * @param mixed $nullDefault Whether the column is required or it's default.
64
     *
65
     * null|true
66
     * : The column is not required.
67
     * false
68
     * : The column is required.
69
     * Anything else
70
     * : The column is required and this is its default.
71
     * @return TableDef
72
     */
73 48
    public function setColumn($name, $type, $nullDefault = false) {
74 48
        $this->columns[$name] = $this->createColumnDef($type, $nullDefault);
75
76 48
        return $this;
77
    }
78
79
    /**
80
     * Get an array column def from a structured function call.
81
     *
82
     * @param string $dbtype The database type of the column.
83
     * @param mixed $nullDefault Whether or not to allow null or the default value.
84
     *
85
     * null|true
86
     * : The column is not required.
87
     * false
88
     * : The column is required.
89
     * Anything else
90
     * : The column is required and this is its default.
91
     *
92
     * @return array Returns the column def as an array.
93
     */
94 48
    private function createColumnDef($dbtype, $nullDefault = false) {
95 48
        $column = Db::typeDef($dbtype);
96
97 48
        if ($column === null) {
98
            throw new \InvalidArgumentException("Unknown type '$dbtype'.", 500);
99
        }
100
101 48
        if ($column['dbtype'] === 'bool' && in_array($nullDefault, [true, false], true)) {
102
            // Booleans have a special meaning.
103 2
            $column['allowNull'] = false;
104 2
            $column['default'] = $nullDefault;
105 48
        } elseif ($column['dbtype'] === 'timestamp' && empty($column['default'])) {
106 2
            $column['default'] = 'current_timestamp';
107 46
        } elseif ($nullDefault === null || $nullDefault === true) {
108 4
            $column['allowNull'] = true;
109 44
        } elseif ($nullDefault === false) {
110 44
            $column['allowNull'] = false;
111
        } else {
112 28
            $column['allowNull'] = false;
113 28
            $column['default'] = $nullDefault;
114
        }
115
116 48
        return $column;
117
    }
118
119
    /**
120
     * Define the primary key in the database.
121
     *
122
     * @param string $name The name of the column.
123
     * @param string $type The datatype for the column.
124
     * @return TableDef
125
     */
126 22
    public function setPrimaryKey($name, $type = 'int') {
127 22
        $column = $this->createColumnDef($type, false);
128 22
        $column['autoIncrement'] = true;
129 22
        $column['primary'] = true;
130
131 22
        $this->columns[$name] = $column;
132
133
        // Add the pk index.
134 22
        $this->addIndex(Db::INDEX_PK, $name);
135
136 22
        return $this;
137
    }
138
139
    /**
140
     * Add or update an index.
141
     *
142
     * @param string $type One of the `Db::INDEX_*` constants.
143
     * @param string ...$columns The columns in the index.
144
     * @return $this
145
     */
146 36
    public function addIndex($type, ...$columns) {
147 36
        if (empty($columns)) {
148
            throw new \InvalidArgumentException("An index must contain at least one column.", 500);
149
        }
150
151 36
        $type = strtolower($type);
152
153
        // Look for a current index row.
154 36
        $currentIndex = null;
155 36
        foreach ($this->indexes as $i => $index) {
156 28
            if ($type !== $index['type']) {
157 20
                continue;
158
            }
159
160 8
            if ($type === Db::INDEX_PK || array_diff($index['columns'], $columns) == []) {
161 6
                $currentIndex =& $this->indexes[$i];
162 6
                break;
163
            }
164
        }
165
166 36
        if ($currentIndex) {
167 6
            $currentIndex['columns'] = $columns;
168
        } else {
169
            $indexDef = [
170 36
                'type' => $type,
171 36
                'columns' => $columns,
172
            ];
173 36
            $this->indexes[] = $indexDef;
174
        }
175
176 36
        return $this;
177
    }
178
179
    /**
180
     * Get the table.
181
     *
182
     * @return string Returns the table.
183
     */
184 2
    public function getTable() {
185 2
        return $this->table;
186
    }
187
188
    /**
189
     * Set the name of the table.
190
     *
191
     * @param string|null $name The name of the table.
192
     * @return TableDef|string Returns $this for fluent calls.
193
     */
194 8
    public function setTable($name) {
195 8
        $this->table = $name;
196 8
        return $this;
197
    }
198
199
    /**
200
     * Specify data which should be serialized to JSON.
201
     *
202
     * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
203
     * @return mixed data which can be serialized by {@link json_encode()},
204
     * which is a value of any type other than a resource.
205
     */
206
    public function jsonSerialize() {
207
        return $this->toArray();
208
    }
209
210
    /**
211
     * Get the array representation of the table definition.
212
     *
213
     * @return array Returns a definition array.
214
     */
215 48
    public function toArray() {
216
        return [
217 48
            'name' => $this->table,
218 48
            'columns' => $this->columns,
219 48
            'indexes' => $this->indexes
220
        ];
221
    }
222
223
    /**
224
     * Execute this table definition on a database.
225
     *
226
     * @param Db $db The database to query.
227
     * @param array $options Additional options. See {@link Db::defineTable()}.
228
     */
229 38
    public function exec(Db $db, array $options = []) {
230 38
        $db->defineTable($this->toArray(), $options);
231 38
    }
232
}
233