Add return type `static` for `@return $this`
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / database / table / DatabaseTable.class.php
1 <?php
2
3 namespace wcf\system\database\table;
4
5 use wcf\system\application\ApplicationHandler;
6 use wcf\system\database\editor\DatabaseEditor;
7 use wcf\system\database\table\column\IDatabaseTableColumn;
8 use wcf\system\database\table\index\DatabaseTableForeignKey;
9 use wcf\system\database\table\index\DatabaseTableIndex;
10
11 /**
12 * PHP representation of an existing database table or the intended layout of an non-existing or
13 * existing database table.
14 *
15 * @author Alexander Ebert, Matthias Schmidt
16 * @copyright 2001-2019 WoltLab GmbH
17 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
18 * @package WoltLabSuite\Core\System\Database\Table
19 * @since 5.2
20 */
21 class DatabaseTable
22 {
23 use TDroppableDatabaseComponent;
24
25 /**
26 * intended database table's columns
27 * @var IDatabaseTableColumn[]
28 */
29 protected array $columns = [];
30
31 /**
32 * intended database table's foreign keys
33 * @var DatabaseTableForeignKey[]
34 */
35 protected array $foreignKeys = [];
36
37 /**
38 * intended database table's indices
39 * @var DatabaseTableIndex[]
40 */
41 protected array $indices = [];
42
43 /**
44 * name of the database table
45 */
46 protected string $name;
47
48 /**
49 * Creates a new instance of `DatabaseTable`.
50 *
51 * @param string $name name of the database table
52 */
53 protected function __construct(string $name)
54 {
55 $this->name = ApplicationHandler::insertRealDatabaseTableNames($name, true);
56 }
57
58 /**
59 * Sets the columns of the database table.
60 *
61 * @param IDatabaseTableColumn[] $columns added/dropped columns
62 * @return $this this database table
63 * @throws \InvalidArgumentException if any column is invalid or duplicate column names exist
64 */
65 public function columns(array $columns): static
66 {
67 $this->columns = [];
68 foreach ($columns as $column) {
69 if (!($column instanceof IDatabaseTableColumn)) {
70 throw new \InvalidArgumentException(
71 "Added columns have to be instances of '" . IDatabaseTableColumn::class . "'."
72 );
73 }
74
75 if (isset($this->columns[$column->getName()])) {
76 throw new \InvalidArgumentException("Duplicate column with name '{$column->getName()}'.");
77 }
78
79 $this->columns[$column->getName()] = $column;
80 }
81
82 return $this;
83 }
84
85 /**
86 * Sets the foreign keys of the database table.
87 *
88 * @param DatabaseTableForeignKey[] $foreignKeys added/dropped foreign keys
89 * @return $this this database table
90 * @throws \InvalidArgumentException if any foreign key is invalid or duplicate foreign key names exist
91 */
92 public function foreignKeys(array $foreignKeys): static
93 {
94 $this->foreignKeys = [];
95 foreach ($foreignKeys as $foreignKey) {
96 if (!($foreignKey instanceof DatabaseTableForeignKey)) {
97 throw new \InvalidArgumentException(
98 "Added foreign keys have to be instances of '" . DatabaseTableForeignKey::class . "'."
99 );
100 }
101
102 if ($foreignKey->getColumns() === []) {
103 throw new \InvalidArgumentException("Missing columns for foreign key.");
104 }
105
106 if ($foreignKey->getName() === '') {
107 $foreignKey->name(\md5($this->getName() . '_' . $foreignKey->getColumns()[0]) . '_fk');
108 }
109
110 if (isset($this->foreignKeys[$foreignKey->getName()])) {
111 throw new \InvalidArgumentException("Duplicate foreign key with name '{$foreignKey->getName()}'.");
112 }
113
114 if ($foreignKey->getOnDelete() === null && $foreignKey->getOnUpdate() === null) {
115 throw new \InvalidArgumentException("Missing action for foreign key '{$foreignKey->getName()}'.");
116 }
117
118 $this->foreignKeys[$foreignKey->getName()] = $foreignKey;
119 }
120
121 return $this;
122 }
123
124 /**
125 * Returns the columns of the table.
126 *
127 * @return IDatabaseTableColumn[]
128 */
129 public function getColumns(): array
130 {
131 return $this->columns;
132 }
133
134 /**
135 * Returns the foreign keys of the table.
136 *
137 * @return DatabaseTableForeignKey[]
138 */
139 public function getForeignKeys(): array
140 {
141 return $this->foreignKeys;
142 }
143
144 /**
145 * Returns the indices of the table.
146 *
147 * @return DatabaseTableIndex[]
148 */
149 public function getIndices(): array
150 {
151 return $this->indices;
152 }
153
154 /**
155 * Returns the name of the database table.
156 *
157 * @return string database table name
158 */
159 public function getName(): string
160 {
161 return $this->name;
162 }
163
164 /**
165 * Returns a `DatabaseTable` object with the given name.
166 */
167 public static function create(string $tableName): static
168 {
169 return new static($tableName);
170 }
171
172 /**
173 * Returns a `DatabaseTable` object for an existing database table with the given name.
174 */
175 public static function createFromExistingTable(DatabaseEditor $dbEditor, string $tableName): static
176 {
177 $table = new static($tableName);
178
179 $columns = [];
180 foreach ($dbEditor->getColumns($tableName) as $columnData) {
181 $className = 'wcf\system\database\table\column\\' . \ucfirst(\strtolower($columnData['data']['type'])) . 'DatabaseTableColumn';
182 if (!\class_exists($className)) {
183 throw new \InvalidArgumentException(
184 "Unknown database table column type '{$columnData['data']['type']}'."
185 );
186 }
187
188 $columns[$columnData['name']] = $className::createFromData($columnData['name'], $columnData['data']);
189 }
190 $table->columns($columns);
191
192 $foreignKeys = [];
193 foreach ($dbEditor->getForeignKeys($tableName) as $foreignKeysName => $foreignKeyData) {
194 $foreignKeys[$foreignKeysName] = DatabaseTableForeignKey::createFromData(
195 $foreignKeysName,
196 $foreignKeyData
197 );
198 }
199 $table->foreignKeys($foreignKeys);
200
201 $indices = [];
202 foreach ($dbEditor->getIndexInformation($tableName) as $indexName => $indexData) {
203 if (!isset($foreignKeys[$indexName])) {
204 $indices[$indexName] = DatabaseTableIndex::createFromData($indexName, $indexData);
205 }
206 }
207 $table->indices($indices);
208
209 return $table;
210 }
211
212 /**
213 * Sets the indices of the database table.
214 *
215 * @param DatabaseTableIndex[] $indices added/dropped indices
216 * @return $this this database table
217 * @throws \InvalidArgumentException if any index is invalid or duplicate index key names exist
218 */
219 public function indices(array $indices): static
220 {
221 $this->indices = [];
222 foreach ($indices as $index) {
223 if (!($index instanceof DatabaseTableIndex)) {
224 throw new \InvalidArgumentException(
225 "Added indices have to be instances of '" . DatabaseTableIndex::class . "'."
226 );
227 }
228
229 if ($index->getName() === '') {
230 $index->generatedName(\md5($this->getName() . '_' . $index->getColumns()[0]));
231 }
232
233 if (isset($this->indices[$index->getName()])) {
234 throw new \InvalidArgumentException("Duplicate index with name '{$index->getName()}'.");
235 }
236
237 $this->indices[$index->getName()] = $index;
238 }
239
240 return $this;
241 }
242 }