Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
100.00% |
124 / 124 |
|
95.79% |
91 / 95 |
|
61.76% |
42 / 68 |
|
91.30% |
21 / 23 |
CRAP | |
0.00% |
0 / 1 |
| Config | |
100.00% |
124 / 124 |
|
95.79% |
91 / 95 |
|
61.76% |
42 / 68 |
|
100.00% |
23 / 23 |
269.00 | |
100.00% |
1 / 1 |
| __construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setCredentials | |
100.00% |
1 / 1 |
n/a |
0 / 0 |
n/a |
0 / 0 |
|
100.00% |
1 / 1 |
1 | |||||
| setPdoOptions | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setPdoOption | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setFetchMode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setPlaceholders | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| addSqlDirs | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setMigrations | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| addMigrationDir | |
100.00% |
6 / 6 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| setMigrationNamespace | |
100.00% |
11 / 11 |
|
100.00% |
13 / 13 |
|
36.36% |
4 / 11 |
|
100.00% |
1 / 1 |
15.28 | |||
| setMigrationsTable | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setMigrationsColumnMigration | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setMigrationsColumnApplied | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| preparePath | |
100.00% |
4 / 4 |
|
100.00% |
5 / 5 |
|
50.00% |
2 / 4 |
|
100.00% |
1 / 1 |
4.12 | |||
| readDriver | |
100.00% |
4 / 4 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| readFlatDirs | |
100.00% |
19 / 19 |
|
100.00% |
19 / 19 |
|
45.45% |
5 / 11 |
|
100.00% |
1 / 1 |
22.15 | |||
| readAssocDirs | |
100.00% |
8 / 8 |
|
100.00% |
5 / 5 |
|
75.00% |
3 / 4 |
|
100.00% |
1 / 1 |
3.14 | |||
| readDirsEntry | |
100.00% |
26 / 26 |
|
100.00% |
5 / 5 |
|
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
7 | |||
| readMigrationDirs | |
100.00% |
7 / 7 |
|
100.00% |
9 / 9 |
|
66.67% |
4 / 6 |
|
100.00% |
1 / 1 |
5.93 | |||
| isDriverConfig | |
100.00% |
1 / 1 |
|
100.00% |
3 / 3 |
|
50.00% |
1 / 2 |
|
100.00% |
1 / 1 |
2.50 | |||
| readNamespacedDirs | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
5 | |||
| getMigrationsTableName | |
100.00% |
6 / 6 |
|
76.92% |
10 / 13 |
|
37.50% |
3 / 8 |
|
100.00% |
1 / 1 |
7.91 | |||
| getColumnName | |
100.00% |
3 / 3 |
|
83.33% |
5 / 6 |
|
50.00% |
2 / 4 |
|
100.00% |
1 / 1 |
2.50 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Celemas\Quma; |
| 6 | |
| 7 | use PDO; |
| 8 | use RuntimeException; |
| 9 | use ValueError; |
| 10 | |
| 11 | /** |
| 12 | * @api |
| 13 | * |
| 14 | * @psalm-type SqlDirs = list<non-empty-string> |
| 15 | * @psalm-type SqlAssoc = array<non-empty-string, non-empty-string|list<non-empty-string>> |
| 16 | * @psalm-type SqlMixed = list<non-empty-string|SqlAssoc> |
| 17 | * @psalm-type SqlConfig = non-empty-string|SqlAssoc|SqlMixed |
| 18 | * @psalm-type MigrationDirsFlat = list<non-empty-string> |
| 19 | * @psalm-type MigrationDirsNamespaced = array<non-empty-string, non-empty-string|list<non-empty-string>> |
| 20 | * @psalm-type MigrationDirs = MigrationDirsFlat|MigrationDirsNamespaced |
| 21 | * @psalm-type PlaceholderMap = array<non-empty-string, string> |
| 22 | * @psalm-type PlaceholderConfig = array<non-empty-string, PlaceholderMap> |
| 23 | */ |
| 24 | final class Config |
| 25 | { |
| 26 | /** @var non-empty-string */ |
| 27 | public readonly string $driver; |
| 28 | |
| 29 | /** @psalm-var SqlDirs */ |
| 30 | public private(set) array $sql; |
| 31 | |
| 32 | /** @psalm-var MigrationDirs */ |
| 33 | public private(set) array $migrations = []; |
| 34 | |
| 35 | public private(set) PdoConfig $pdo; |
| 36 | public private(set) ?Placeholders $placeholders = null; |
| 37 | |
| 38 | public private(set) string $migrationsTable = 'migrations'; |
| 39 | public private(set) string $migrationsColumnMigration = 'migration'; |
| 40 | public private(set) string $migrationsColumnApplied = 'applied'; |
| 41 | |
| 42 | /** @psalm-param SqlConfig $sql */ |
| 43 | public function __construct( |
| 44 | public readonly string $dsn, |
| 45 | string|array $sql, |
| 46 | ) { |
| 47 | $this->driver = $this->readDriver($this->dsn); |
| 48 | $this->sql = $this->readFlatDirs($sql); |
| 49 | $this->pdo = new PdoConfig(); |
| 50 | } |
| 51 | |
| 52 | public function setCredentials( |
| 53 | string $username, |
| 54 | #[\SensitiveParameter] |
| 55 | ?string $password = null, |
| 56 | ): void { |
| 57 | $this->pdo = $this->pdo->credentials($username, $password); |
| 58 | } |
| 59 | |
| 60 | /** @param array<array-key, mixed> $options */ |
| 61 | public function setPdoOptions(array $options): void |
| 62 | { |
| 63 | $this->pdo = $this->pdo->options($options); |
| 64 | } |
| 65 | |
| 66 | public function setPdoOption(int $attribute, mixed $value): void |
| 67 | { |
| 68 | $this->pdo = $this->pdo->option($attribute, $value); |
| 69 | } |
| 70 | |
| 71 | public function setFetchMode(int $fetchMode): void |
| 72 | { |
| 73 | $this->pdo = $this->pdo->fetch($fetchMode); |
| 74 | } |
| 75 | |
| 76 | /** @psalm-param PlaceholderConfig $placeholders */ |
| 77 | public function setPlaceholders(Delimiters $delimiters, array $placeholders): void |
| 78 | { |
| 79 | $this->placeholders = new Placeholders($this->driver, $placeholders, $delimiters); |
| 80 | } |
| 81 | |
| 82 | /** @psalm-param SqlConfig $sql */ |
| 83 | public function addSqlDirs(array|string $sql): void |
| 84 | { |
| 85 | $dirs = $this->readFlatDirs($sql); |
| 86 | $this->sql = array_merge($dirs, $this->sql); |
| 87 | } |
| 88 | |
| 89 | /** @psalm-param SqlConfig $migrations */ |
| 90 | public function setMigrations(array|string $migrations): void |
| 91 | { |
| 92 | $this->migrations = $this->readMigrationDirs($migrations); |
| 93 | } |
| 94 | |
| 95 | /** @param non-empty-string $migrations */ |
| 96 | public function addMigrationDir(string $migrations): void |
| 97 | { |
| 98 | if (!array_is_list($this->migrations)) { |
| 99 | throw new ValueError( |
| 100 | 'Cannot add a flat migration directory when migrations are namespaced. Use migrationNamespace().', |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | $dirs = $this->readFlatDirs($migrations); |
| 105 | $this->migrations = array_merge($dirs, $this->migrations); |
| 106 | } |
| 107 | |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 111 | throw new ValueError('Migration namespace must not be empty.'); |
| 112 | } |
| 113 | |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 115 | throw new ValueError( |
| 116 | 'Cannot add a namespaced migration directory when migrations are configured as a flat list.', |
| 117 | ); |
| 118 | } |
| 119 | |
| 120 | /** @psalm-var MigrationDirsNamespaced $migrations */ |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 125 | $this->migrations = $migrations; |
| 126 | } |
| 127 | |
| 128 | public function setMigrationsTable(string $table): void |
| 129 | { |
| 130 | $this->migrationsTable = $this->getMigrationsTableName($table); |
| 131 | } |
| 132 | |
| 133 | public function setMigrationsColumnMigration(string $column): void |
| 134 | { |
| 135 | $this->migrationsColumnMigration = $this->getColumnName($column); |
| 136 | } |
| 137 | |
| 138 | public function setMigrationsColumnApplied(string $column): void |
| 139 | { |
| 140 | $this->migrationsColumnApplied = $this->getColumnName($column); |
| 141 | } |
| 142 | |
| 143 | /** @return non-empty-string */ |
| 144 | private function preparePath(string $path): string |
| 145 | { |
| 146 | $result = realpath($path); |
| 147 | |
| 148 | if ($result !== false && $result !== '') { |
| 149 | return $result; |
| 150 | } |
| 151 | |
| 152 | throw new ValueError("Path does not exist: {$path}"); |
| 153 | } |
| 154 | |
| 155 | /** @return non-empty-string */ |
| 156 | private function readDriver(string $dsn): string |
| 157 | { |
| 158 | $driver = explode(':', $dsn)[0]; |
| 159 | |
| 160 | if (in_array($driver, PDO::getAvailableDrivers(), strict: true)) { |
| 161 | assert($driver !== '', 'PDO driver name must not be empty.'); |
| 162 | |
| 163 | return $driver; |
| 164 | } |
| 165 | |
| 166 | throw new RuntimeException('PDO driver not supported: ' . $driver); |
| 167 | } |
| 168 | |
| 169 | /** |
| 170 | * Reads directories from configuration into a flat list. |
| 171 | * |
| 172 | * @psalm-param SqlConfig $config |
| 173 | * |
| 174 | * @return list<non-empty-string> |
| 175 | */ |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 179 | return [$this->preparePath($config)]; |
| 180 | } |
| 181 | |
| 182 | if (count($config) === 0) { |
| 183 | return []; |
| 184 | } |
| 185 | |
| 186 | if (Util::isAssoc($config)) { |
| 187 | return $this->readAssocDirs($config); |
| 188 | } |
| 189 | |
| 190 | $dirs = []; |
| 191 | |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 212 | } |
| 213 | |
| 214 | return $dirs; |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * Reads directories from an associative array config. |
| 219 | * |
| 220 | * @param array<array-key, mixed> $entry |
| 221 | * |
| 222 | * @return list<non-empty-string> |
| 223 | */ |
| 224 | private function readAssocDirs(array $entry): array |
| 225 | { |
| 226 | $hasDriver = array_key_exists($this->driver, $entry); |
| 227 | $hasAll = array_key_exists('all', $entry); |
| 228 | $dirs = []; |
| 229 | |
| 230 | if ($hasDriver) { |
| 231 | $dirs = array_merge($dirs, $this->readDirsEntry($entry[$this->driver])); |
| 232 | } |
| 233 | |
| 234 | if ($hasAll) { |
| 235 | $dirs = array_merge($dirs, $this->readDirsEntry($entry['all'])); |
| 236 | } |
| 237 | |
| 238 | return $dirs; |
| 239 | } |
| 240 | |
| 241 | /** @return list<non-empty-string> */ |
| 242 | private function readDirsEntry(mixed $entry): array |
| 243 | { |
| 244 | if (is_string($entry)) { |
| 245 | return [$this->preparePath($entry)]; |
| 246 | } |
| 247 | |
| 248 | if (!is_array($entry)) { |
| 249 | return []; |
| 250 | } |
| 251 | |
| 252 | $dirs = []; |
| 253 | |
| 254 | array_walk( |
| 255 | $entry, |
| 256 | function (mixed $value) use (&$dirs): void { |
| 257 | if (is_string($value)) { |
| 258 | $dirs[] = $this->preparePath($value); |
| 259 | |
| 260 | return; |
| 261 | } |
| 262 | |
| 263 | if (!is_array($value)) { |
| 264 | return; |
| 265 | } |
| 266 | |
| 267 | if (Util::isAssoc($value)) { |
| 268 | $dirs = array_merge($dirs, $this->readAssocDirs($value)); |
| 269 | |
| 270 | return; |
| 271 | } |
| 272 | |
| 273 | array_walk( |
| 274 | $value, |
| 275 | function (mixed $path) use (&$dirs): void { |
| 276 | if (is_string($path)) { |
| 277 | $dirs[] = $this->preparePath($path); |
| 278 | } |
| 279 | }, |
| 280 | ); |
| 281 | }, |
| 282 | ); |
| 283 | |
| 284 | return $dirs; |
| 285 | } |
| 286 | |
| 287 | /** |
| 288 | * Reads migration directories from configuration. |
| 289 | * |
| 290 | * Migrations can be configured as: |
| 291 | * - A flat list of directories |
| 292 | * - A namespaced structure with string keys mapping to directories |
| 293 | * |
| 294 | * @psalm-param SqlConfig $config |
| 295 | * |
| 296 | * @psalm-return MigrationDirs |
| 297 | */ |
| 298 | private function readMigrationDirs(string|array $config): array |
| 299 | { |
| 300 | if (is_string($config)) { |
| 301 | return [$this->preparePath($config)]; |
| 302 | } |
| 303 | |
| 304 | if (count($config) === 0) { |
| 305 | return []; |
| 306 | } |
| 307 | |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 309 | return $this->readNamespacedDirs($config); |
| 310 | } |
| 311 | |
| 312 | return $this->readFlatDirs($config); |
| 313 | } |
| 314 | |
| 315 | /** @param array<array-key, mixed> $config */ |
| 316 | private function isDriverConfig(array $config): bool |
| 317 | { |
| 318 | return array_key_exists($this->driver, $config) || array_key_exists('all', $config); |
| 319 | } |
| 320 | |
| 321 | /** |
| 322 | * Reads namespaced migration directories. |
| 323 | * |
| 324 | * @param array<array-key, mixed> $config |
| 325 | * |
| 326 | * @psalm-return MigrationDirsNamespaced |
| 327 | */ |
| 328 | private function readNamespacedDirs(array $config): array |
| 329 | { |
| 330 | $result = []; |
| 331 | |
| 332 | array_walk( |
| 333 | $config, |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 336 | return; |
| 337 | } |
| 338 | |
| 339 | if (is_string($dirs)) { |
| 340 | $result[$namespace] = $this->preparePath($dirs); |
| 341 | |
| 342 | return; |
| 343 | } |
| 344 | |
| 345 | if (!is_array($dirs)) { |
| 346 | return; |
| 347 | } |
| 348 | |
| 349 | $result[$namespace] = $this->readDirsEntry($dirs); |
| 350 | }, |
| 351 | ); |
| 352 | |
| 353 | return $result; |
| 354 | } |
| 355 | |
| 356 | private function getMigrationsTableName(string $table): string |
| 357 | { |
| 358 | if ($this->driver === 'pgsql') { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 360 | return $table; |
| 361 | } |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 363 | return $table; |
| 364 | } |
| 365 | |
| 366 | throw new ValueError('Invalid migrations table name: ' . $table); |
| 367 | } |
| 368 | |
| 369 | private function getColumnName(string $column): string |
| 370 | { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 372 | return $column; |
| 373 | } |
| 374 | |
| 375 | throw new ValueError('Invalid migrations table column name: ' . $column); |
| 376 | } |
| 377 | } |
Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not
necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once.
Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 44 | public readonly string $dsn, |
| 45 | string|array $sql, |
| 46 | ) { |
| 47 | $this->driver = $this->readDriver($this->dsn); |
| 48 | $this->sql = $this->readFlatDirs($sql); |
| 49 | $this->pdo = new PdoConfig(); |
| 50 | } |
| 96 | public function addMigrationDir(string $migrations): void |
| 97 | { |
| 98 | if (!array_is_list($this->migrations)) { |
| 99 | throw new ValueError( |
| 100 | 'Cannot add a flat migration directory when migrations are namespaced. Use migrationNamespace().', |
| 96 | public function addMigrationDir(string $migrations): void |
| 97 | { |
| 98 | if (!array_is_list($this->migrations)) { |
| 104 | $dirs = $this->readFlatDirs($migrations); |
| 105 | $this->migrations = array_merge($dirs, $this->migrations); |
| 106 | } |
| 83 | public function addSqlDirs(array|string $sql): void |
| 84 | { |
| 85 | $dirs = $this->readFlatDirs($sql); |
| 86 | $this->sql = array_merge($dirs, $this->sql); |
| 87 | } |
| 369 | private function getColumnName(string $column): string |
| 370 | { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 372 | return $column; |
| 369 | private function getColumnName(string $column): string |
| 370 | { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 375 | throw new ValueError('Invalid migrations table column name: ' . $column); |
| 376 | } |
| 369 | private function getColumnName(string $column): string |
| 370 | { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 372 | return $column; |
| 369 | private function getColumnName(string $column): string |
| 370 | { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 371 | if (preg_match('/^[a-zA-Z0-9_]+$/', $column)) { |
| 375 | throw new ValueError('Invalid migrations table column name: ' . $column); |
| 376 | } |
| 356 | private function getMigrationsTableName(string $table): string |
| 357 | { |
| 358 | if ($this->driver === 'pgsql') { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 360 | return $table; |
| 356 | private function getMigrationsTableName(string $table): string |
| 357 | { |
| 358 | if ($this->driver === 'pgsql') { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 358 | if ($this->driver === 'pgsql') { |
| 366 | throw new ValueError('Invalid migrations table name: ' . $table); |
| 367 | } |
| 356 | private function getMigrationsTableName(string $table): string |
| 357 | { |
| 358 | if ($this->driver === 'pgsql') { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 360 | return $table; |
| 356 | private function getMigrationsTableName(string $table): string |
| 357 | { |
| 358 | if ($this->driver === 'pgsql') { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 359 | if (preg_match('/^([a-zA-Z0-9_]+\.)?[a-zA-Z0-9_]+$/', $table)) { |
| 358 | if ($this->driver === 'pgsql') { |
| 366 | throw new ValueError('Invalid migrations table name: ' . $table); |
| 367 | } |
| 356 | private function getMigrationsTableName(string $table): string |
| 357 | { |
| 358 | if ($this->driver === 'pgsql') { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 363 | return $table; |
| 356 | private function getMigrationsTableName(string $table): string |
| 357 | { |
| 358 | if ($this->driver === 'pgsql') { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 366 | throw new ValueError('Invalid migrations table name: ' . $table); |
| 367 | } |
| 356 | private function getMigrationsTableName(string $table): string |
| 357 | { |
| 358 | if ($this->driver === 'pgsql') { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 363 | return $table; |
| 356 | private function getMigrationsTableName(string $table): string |
| 357 | { |
| 358 | if ($this->driver === 'pgsql') { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 362 | } elseif (preg_match('/^[a-zA-Z0-9_]+$/', $table)) { |
| 366 | throw new ValueError('Invalid migrations table name: ' . $table); |
| 367 | } |
| 316 | private function isDriverConfig(array $config): bool |
| 317 | { |
| 318 | return array_key_exists($this->driver, $config) || array_key_exists('all', $config); |
| 318 | return array_key_exists($this->driver, $config) || array_key_exists('all', $config); |
| 318 | return array_key_exists($this->driver, $config) || array_key_exists('all', $config); |
| 319 | } |
| 316 | private function isDriverConfig(array $config): bool |
| 317 | { |
| 318 | return array_key_exists($this->driver, $config) || array_key_exists('all', $config); |
| 318 | return array_key_exists($this->driver, $config) || array_key_exists('all', $config); |
| 319 | } |
| 144 | private function preparePath(string $path): string |
| 145 | { |
| 146 | $result = realpath($path); |
| 147 | |
| 148 | if ($result !== false && $result !== '') { |
| 148 | if ($result !== false && $result !== '') { |
| 148 | if ($result !== false && $result !== '') { |
| 149 | return $result; |
| 144 | private function preparePath(string $path): string |
| 145 | { |
| 146 | $result = realpath($path); |
| 147 | |
| 148 | if ($result !== false && $result !== '') { |
| 148 | if ($result !== false && $result !== '') { |
| 148 | if ($result !== false && $result !== '') { |
| 152 | throw new ValueError("Path does not exist: {$path}"); |
| 153 | } |
| 144 | private function preparePath(string $path): string |
| 145 | { |
| 146 | $result = realpath($path); |
| 147 | |
| 148 | if ($result !== false && $result !== '') { |
| 148 | if ($result !== false && $result !== '') { |
| 149 | return $result; |
| 144 | private function preparePath(string $path): string |
| 145 | { |
| 146 | $result = realpath($path); |
| 147 | |
| 148 | if ($result !== false && $result !== '') { |
| 148 | if ($result !== false && $result !== '') { |
| 152 | throw new ValueError("Path does not exist: {$path}"); |
| 153 | } |
| 224 | private function readAssocDirs(array $entry): array |
| 225 | { |
| 226 | $hasDriver = array_key_exists($this->driver, $entry); |
| 227 | $hasAll = array_key_exists('all', $entry); |
| 228 | $dirs = []; |
| 229 | |
| 230 | if ($hasDriver) { |
| 231 | $dirs = array_merge($dirs, $this->readDirsEntry($entry[$this->driver])); |
| 232 | } |
| 233 | |
| 234 | if ($hasAll) { |
| 234 | if ($hasAll) { |
| 235 | $dirs = array_merge($dirs, $this->readDirsEntry($entry['all'])); |
| 236 | } |
| 237 | |
| 238 | return $dirs; |
| 238 | return $dirs; |
| 239 | } |
| 224 | private function readAssocDirs(array $entry): array |
| 225 | { |
| 226 | $hasDriver = array_key_exists($this->driver, $entry); |
| 227 | $hasAll = array_key_exists('all', $entry); |
| 228 | $dirs = []; |
| 229 | |
| 230 | if ($hasDriver) { |
| 231 | $dirs = array_merge($dirs, $this->readDirsEntry($entry[$this->driver])); |
| 232 | } |
| 233 | |
| 234 | if ($hasAll) { |
| 234 | if ($hasAll) { |
| 238 | return $dirs; |
| 239 | } |
| 224 | private function readAssocDirs(array $entry): array |
| 225 | { |
| 226 | $hasDriver = array_key_exists($this->driver, $entry); |
| 227 | $hasAll = array_key_exists('all', $entry); |
| 228 | $dirs = []; |
| 229 | |
| 230 | if ($hasDriver) { |
| 234 | if ($hasAll) { |
| 235 | $dirs = array_merge($dirs, $this->readDirsEntry($entry['all'])); |
| 236 | } |
| 237 | |
| 238 | return $dirs; |
| 238 | return $dirs; |
| 239 | } |
| 224 | private function readAssocDirs(array $entry): array |
| 225 | { |
| 226 | $hasDriver = array_key_exists($this->driver, $entry); |
| 227 | $hasAll = array_key_exists('all', $entry); |
| 228 | $dirs = []; |
| 229 | |
| 230 | if ($hasDriver) { |
| 234 | if ($hasAll) { |
| 238 | return $dirs; |
| 239 | } |
| 242 | private function readDirsEntry(mixed $entry): array |
| 243 | { |
| 244 | if (is_string($entry)) { |
| 245 | return [$this->preparePath($entry)]; |
| 242 | private function readDirsEntry(mixed $entry): array |
| 243 | { |
| 244 | if (is_string($entry)) { |
| 248 | if (!is_array($entry)) { |
| 249 | return []; |
| 242 | private function readDirsEntry(mixed $entry): array |
| 243 | { |
| 244 | if (is_string($entry)) { |
| 248 | if (!is_array($entry)) { |
| 252 | $dirs = []; |
| 253 | |
| 254 | array_walk( |
| 255 | $entry, |
| 256 | function (mixed $value) use (&$dirs): void { |
| 257 | if (is_string($value)) { |
| 258 | $dirs[] = $this->preparePath($value); |
| 259 | |
| 260 | return; |
| 261 | } |
| 262 | |
| 263 | if (!is_array($value)) { |
| 264 | return; |
| 265 | } |
| 266 | |
| 267 | if (Util::isAssoc($value)) { |
| 268 | $dirs = array_merge($dirs, $this->readAssocDirs($value)); |
| 269 | |
| 270 | return; |
| 271 | } |
| 272 | |
| 273 | array_walk( |
| 274 | $value, |
| 275 | function (mixed $path) use (&$dirs): void { |
| 276 | if (is_string($path)) { |
| 277 | $dirs[] = $this->preparePath($path); |
| 278 | } |
| 279 | }, |
| 280 | ); |
| 281 | }, |
| 282 | ); |
| 283 | |
| 284 | return $dirs; |
| 285 | } |
| 156 | private function readDriver(string $dsn): string |
| 157 | { |
| 158 | $driver = explode(':', $dsn)[0]; |
| 159 | |
| 160 | if (in_array($driver, PDO::getAvailableDrivers(), strict: true)) { |
| 161 | assert($driver !== '', 'PDO driver name must not be empty.'); |
| 162 | |
| 163 | return $driver; |
| 156 | private function readDriver(string $dsn): string |
| 157 | { |
| 158 | $driver = explode(':', $dsn)[0]; |
| 159 | |
| 160 | if (in_array($driver, PDO::getAvailableDrivers(), strict: true)) { |
| 166 | throw new RuntimeException('PDO driver not supported: ' . $driver); |
| 167 | } |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 179 | return [$this->preparePath($config)]; |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 183 | return []; |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 186 | if (Util::isAssoc($config)) { |
| 187 | return $this->readAssocDirs($config); |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 186 | if (Util::isAssoc($config)) { |
| 190 | $dirs = []; |
| 191 | |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 212 | } |
| 213 | |
| 214 | return $dirs; |
| 215 | } |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 186 | if (Util::isAssoc($config)) { |
| 190 | $dirs = []; |
| 191 | |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 200 | foreach ($entry as $path) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 212 | } |
| 213 | |
| 214 | return $dirs; |
| 215 | } |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 186 | if (Util::isAssoc($config)) { |
| 190 | $dirs = []; |
| 191 | |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 200 | foreach ($entry as $path) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 212 | } |
| 213 | |
| 214 | return $dirs; |
| 215 | } |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 186 | if (Util::isAssoc($config)) { |
| 190 | $dirs = []; |
| 191 | |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 200 | foreach ($entry as $path) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 212 | } |
| 213 | |
| 214 | return $dirs; |
| 215 | } |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 186 | if (Util::isAssoc($config)) { |
| 190 | $dirs = []; |
| 191 | |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 212 | } |
| 213 | |
| 214 | return $dirs; |
| 215 | } |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 186 | if (Util::isAssoc($config)) { |
| 190 | $dirs = []; |
| 191 | |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 199 | if (array_is_list($entry)) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 212 | } |
| 213 | |
| 214 | return $dirs; |
| 215 | } |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 186 | if (Util::isAssoc($config)) { |
| 190 | $dirs = []; |
| 191 | |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 212 | } |
| 213 | |
| 214 | return $dirs; |
| 215 | } |
| 176 | private function readFlatDirs(string|array $config): array |
| 177 | { |
| 178 | if (is_string($config)) { |
| 182 | if (count($config) === 0) { |
| 186 | if (Util::isAssoc($config)) { |
| 190 | $dirs = []; |
| 191 | |
| 192 | foreach ($config as $entry) { |
| 192 | foreach ($config as $entry) { |
| 193 | if (is_string($entry)) { |
| 194 | array_unshift($dirs, $this->preparePath($entry)); |
| 195 | |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | if (array_is_list($entry)) { |
| 200 | foreach ($entry as $path) { |
| 201 | if (!is_string($path)) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | array_unshift($dirs, $this->preparePath($path)); |
| 206 | } |
| 207 | |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | $dirs = array_merge($this->readAssocDirs($entry), $dirs); |
| 212 | } |
| 213 | |
| 214 | return $dirs; |
| 215 | } |
| 298 | private function readMigrationDirs(string|array $config): array |
| 299 | { |
| 300 | if (is_string($config)) { |
| 301 | return [$this->preparePath($config)]; |
| 298 | private function readMigrationDirs(string|array $config): array |
| 299 | { |
| 300 | if (is_string($config)) { |
| 304 | if (count($config) === 0) { |
| 305 | return []; |
| 298 | private function readMigrationDirs(string|array $config): array |
| 299 | { |
| 300 | if (is_string($config)) { |
| 304 | if (count($config) === 0) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 309 | return $this->readNamespacedDirs($config); |
| 298 | private function readMigrationDirs(string|array $config): array |
| 299 | { |
| 300 | if (is_string($config)) { |
| 304 | if (count($config) === 0) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 312 | return $this->readFlatDirs($config); |
| 313 | } |
| 298 | private function readMigrationDirs(string|array $config): array |
| 299 | { |
| 300 | if (is_string($config)) { |
| 304 | if (count($config) === 0) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 309 | return $this->readNamespacedDirs($config); |
| 298 | private function readMigrationDirs(string|array $config): array |
| 299 | { |
| 300 | if (is_string($config)) { |
| 304 | if (count($config) === 0) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 308 | if (Util::isAssoc($config) && !$this->isDriverConfig($config)) { |
| 312 | return $this->readFlatDirs($config); |
| 313 | } |
| 328 | private function readNamespacedDirs(array $config): array |
| 329 | { |
| 330 | $result = []; |
| 331 | |
| 332 | array_walk( |
| 333 | $config, |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 336 | return; |
| 337 | } |
| 338 | |
| 339 | if (is_string($dirs)) { |
| 340 | $result[$namespace] = $this->preparePath($dirs); |
| 341 | |
| 342 | return; |
| 343 | } |
| 344 | |
| 345 | if (!is_array($dirs)) { |
| 346 | return; |
| 347 | } |
| 348 | |
| 349 | $result[$namespace] = $this->readDirsEntry($dirs); |
| 350 | }, |
| 351 | ); |
| 352 | |
| 353 | return $result; |
| 354 | } |
| 71 | public function setFetchMode(int $fetchMode): void |
| 72 | { |
| 73 | $this->pdo = $this->pdo->fetch($fetchMode); |
| 74 | } |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 111 | throw new ValueError('Migration namespace must not be empty.'); |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 115 | throw new ValueError( |
| 116 | 'Cannot add a namespaced migration directory when migrations are configured as a flat list.', |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 125 | $this->migrations = $migrations; |
| 126 | } |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 125 | $this->migrations = $migrations; |
| 126 | } |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 125 | $this->migrations = $migrations; |
| 126 | } |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 125 | $this->migrations = $migrations; |
| 126 | } |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 115 | throw new ValueError( |
| 116 | 'Cannot add a namespaced migration directory when migrations are configured as a flat list.', |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 125 | $this->migrations = $migrations; |
| 126 | } |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 125 | $this->migrations = $migrations; |
| 126 | } |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 125 | $this->migrations = $migrations; |
| 126 | } |
| 108 | public function setMigrationNamespace(string $namespace, string|array $dirs): void |
| 109 | { |
| 110 | if ($namespace === '') { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 114 | if (array_is_list($this->migrations) && count($this->migrations) > 0) { |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 121 | $migrations = array_is_list($this->migrations) ? [] : $this->migrations; |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 122 | $migrations[$namespace] = is_string($dirs) |
| 123 | ? $this->preparePath($dirs) |
| 124 | : $this->readDirsEntry($dirs); |
| 125 | $this->migrations = $migrations; |
| 126 | } |
| 90 | public function setMigrations(array|string $migrations): void |
| 91 | { |
| 92 | $this->migrations = $this->readMigrationDirs($migrations); |
| 93 | } |
| 138 | public function setMigrationsColumnApplied(string $column): void |
| 139 | { |
| 140 | $this->migrationsColumnApplied = $this->getColumnName($column); |
| 141 | } |
| 133 | public function setMigrationsColumnMigration(string $column): void |
| 134 | { |
| 135 | $this->migrationsColumnMigration = $this->getColumnName($column); |
| 136 | } |
| 128 | public function setMigrationsTable(string $table): void |
| 129 | { |
| 130 | $this->migrationsTable = $this->getMigrationsTableName($table); |
| 131 | } |
| 66 | public function setPdoOption(int $attribute, mixed $value): void |
| 67 | { |
| 68 | $this->pdo = $this->pdo->option($attribute, $value); |
| 69 | } |
| 61 | public function setPdoOptions(array $options): void |
| 62 | { |
| 63 | $this->pdo = $this->pdo->options($options); |
| 64 | } |
| 77 | public function setPlaceholders(Delimiters $delimiters, array $placeholders): void |
| 78 | { |
| 79 | $this->placeholders = new Placeholders($this->driver, $placeholders, $delimiters); |
| 80 | } |
| 256 | function (mixed $value) use (&$dirs): void { |
| 257 | if (is_string($value)) { |
| 258 | $dirs[] = $this->preparePath($value); |
| 259 | |
| 260 | return; |
| 256 | function (mixed $value) use (&$dirs): void { |
| 257 | if (is_string($value)) { |
| 263 | if (!is_array($value)) { |
| 264 | return; |
| 256 | function (mixed $value) use (&$dirs): void { |
| 257 | if (is_string($value)) { |
| 263 | if (!is_array($value)) { |
| 267 | if (Util::isAssoc($value)) { |
| 268 | $dirs = array_merge($dirs, $this->readAssocDirs($value)); |
| 269 | |
| 270 | return; |
| 256 | function (mixed $value) use (&$dirs): void { |
| 257 | if (is_string($value)) { |
| 263 | if (!is_array($value)) { |
| 267 | if (Util::isAssoc($value)) { |
| 273 | array_walk( |
| 274 | $value, |
| 275 | function (mixed $path) use (&$dirs): void { |
| 276 | if (is_string($path)) { |
| 277 | $dirs[] = $this->preparePath($path); |
| 278 | } |
| 279 | }, |
| 280 | ); |
| 281 | }, |
| 275 | function (mixed $path) use (&$dirs): void { |
| 276 | if (is_string($path)) { |
| 277 | $dirs[] = $this->preparePath($path); |
| 278 | } |
| 279 | }, |
| 279 | }, |
| 275 | function (mixed $path) use (&$dirs): void { |
| 276 | if (is_string($path)) { |
| 279 | }, |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 336 | return; |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 339 | if (is_string($dirs)) { |
| 340 | $result[$namespace] = $this->preparePath($dirs); |
| 341 | |
| 342 | return; |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 339 | if (is_string($dirs)) { |
| 345 | if (!is_array($dirs)) { |
| 346 | return; |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 339 | if (is_string($dirs)) { |
| 345 | if (!is_array($dirs)) { |
| 349 | $result[$namespace] = $this->readDirsEntry($dirs); |
| 350 | }, |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 336 | return; |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 339 | if (is_string($dirs)) { |
| 340 | $result[$namespace] = $this->preparePath($dirs); |
| 341 | |
| 342 | return; |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 339 | if (is_string($dirs)) { |
| 345 | if (!is_array($dirs)) { |
| 346 | return; |
| 334 | function (mixed $dirs, int|string $namespace) use (&$result): void { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 335 | if (!is_string($namespace) || $namespace === '') { |
| 339 | if (is_string($dirs)) { |
| 345 | if (!is_array($dirs)) { |
| 349 | $result[$namespace] = $this->readDirsEntry($dirs); |
| 350 | }, |