Passed
Pull Request — master (#752)
by Sergei
03:20 queued 01:02
created

AbstractSchema::createColumnSchema()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 12
c 0
b 0
f 0
nc 2
nop 3
dl 0
loc 19
rs 8.8333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Schema;
6
7
use Psr\SimpleCache\InvalidArgumentException;
8
use Throwable;
9
use Yiisoft\Db\Cache\SchemaCache;
10
use Yiisoft\Db\Command\DataType;
11
use Yiisoft\Db\Connection\ConnectionInterface;
12
use Yiisoft\Db\Constraint\Constraint;
13
use Yiisoft\Db\Exception\NotSupportedException;
14
use Yiisoft\Db\Schema\Column\BinaryColumnSchema;
15
use Yiisoft\Db\Schema\Column\BooleanColumnSchema;
16
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Yiisoft\Db\Schema\ColumnSchemaInterface. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
17
use Yiisoft\Db\Schema\Column\DoubleColumnSchema;
18
use Yiisoft\Db\Schema\Column\IntegerColumnSchema;
19
use Yiisoft\Db\Schema\Column\JsonColumnSchema;
20
use Yiisoft\Db\Schema\Column\StringColumnSchema;
21
use Yiisoft\Db\Schema\Column\BigIntColumnSchema;
22
23
use function array_change_key_case;
24
use function array_map;
25
use function gettype;
26
use function is_array;
27
use function preg_match;
28
use function preg_replace;
29
use function str_contains;
30
use function str_replace;
31
32
/**
33
 * Provides a set of methods for working with database schemas such as creating, modifying, and inspecting tables,
34
 * columns, and other database objects.
35
 *
36
 * It's a powerful and flexible tool that allows you to perform a wide range of database operations in a
37
 * database-agnostic way.
38
 */
39
abstract class AbstractSchema implements SchemaInterface
40
{
41
    /**
42
     * Schema cache version, to detect incompatibilities in cached values when the data format of the cache changes.
43
     */
44
    protected const SCHEMA_CACHE_VERSION = 1;
45
    protected const CACHE_VERSION = 'cacheVersion';
46
    /**
47
     * @var string|null $defaultSchema The default schema name used for the current session.
48
     */
49
    protected string|null $defaultSchema = null;
50
    protected array $viewNames = [];
51
    private array $schemaNames = [];
52
    /** @psalm-var string[]|array */
53
    private array $tableNames = [];
54
    private array $tableMetadata = [];
55
56
    public function __construct(protected ConnectionInterface $db, private SchemaCache $schemaCache)
57
    {
58
    }
59
60
    /**
61
     * @param string $name The table name.
62
     *
63
     * @return array The cache key for the specified table name.
64
     */
65
    abstract protected function getCacheKey(string $name): array;
66
67
    /**
68
     * @return string The cache tag name.
69
     *
70
     * This allows {@see refresh()} to invalidate all cached table schemas.
71
     */
72
    abstract protected function getCacheTag(): string;
73
74
    /**
75
     * Loads all check constraints for the given table.
76
     *
77
     * @param string $tableName The table name.
78
     *
79
     * @return array The check constraints for the given table.
80
     */
81
    abstract protected function loadTableChecks(string $tableName): array;
82
83
    /**
84
     * Loads all default value constraints for the given table.
85
     *
86
     * @param string $tableName The table name.
87
     *
88
     * @return array The default value constraints for the given table.
89
     */
90
    abstract protected function loadTableDefaultValues(string $tableName): array;
91
92
    /**
93
     * Loads all foreign keys for the given table.
94
     *
95
     * @param string $tableName The table name.
96
     *
97
     * @return array The foreign keys for the given table.
98
     */
99
    abstract protected function loadTableForeignKeys(string $tableName): array;
100
101
    /**
102
     * Loads all indexes for the given table.
103
     *
104
     * @param string $tableName The table name.
105
     *
106
     * @return array The indexes for the given table.
107
     */
108
    abstract protected function loadTableIndexes(string $tableName): array;
109
110
    /**
111
     * Loads a primary key for the given table.
112
     *
113
     * @param string $tableName The table name.
114
     *
115
     * @return Constraint|null The primary key for the given table. `null` if the table has no primary key.
116
     */
117
    abstract protected function loadTablePrimaryKey(string $tableName): Constraint|null;
118
119
    /**
120
     * Loads all unique constraints for the given table.
121
     *
122
     * @param string $tableName The table name.
123
     *
124
     * @return array The unique constraints for the given table.
125
     */
126
    abstract protected function loadTableUniques(string $tableName): array;
127
128
    /**
129
     * Loads the metadata for the specified table.
130
     *
131
     * @param string $name The table name.
132
     *
133
     * @return TableSchemaInterface|null DBMS-dependent table metadata, `null` if the table doesn't exist.
134
     */
135
    abstract protected function loadTableSchema(string $name): TableSchemaInterface|null;
136
137
    public function getDefaultSchema(): string|null
138
    {
139
        return $this->defaultSchema;
140
    }
141
142
    public function getDataType(mixed $data): int
143
    {
144
        /** @psalm-var array<string, int> $typeMap */
145
        $typeMap = [
146
            // php type => SQL data type
147
            SchemaInterface::PHP_TYPE_BOOLEAN => DataType::BOOLEAN,
148
            SchemaInterface::PHP_TYPE_INTEGER => DataType::INTEGER,
149
            SchemaInterface::PHP_TYPE_STRING => DataType::STRING,
150
            SchemaInterface::PHP_TYPE_RESOURCE => DataType::LOB,
151
            SchemaInterface::PHP_TYPE_NULL => DataType::NULL,
152
        ];
153
154
        $type = gettype($data);
155
156
        return $typeMap[$type] ?? DataType::STRING;
157
    }
158
159
    public function getRawTableName(string $name): string
160
    {
161
        if (str_contains($name, '{{')) {
162
            $name = preg_replace('/{{(.*?)}}/', '\1', $name);
163
164
            return str_replace('%', $this->db->getTablePrefix(), $name);
165
        }
166
167
        return $name;
168
    }
169
170
    /**
171
     * @throws InvalidArgumentException
172
     * @throws NotSupportedException
173
     */
174
    public function getSchemaChecks(string $schema = '', bool $refresh = false): array
175
    {
176
        return $this->getSchemaMetadata($schema, SchemaInterface::CHECKS, $refresh);
177
    }
178
179
    /**
180
     * @throws InvalidArgumentException
181
     * @throws NotSupportedException
182
     */
183
    public function getSchemaDefaultValues(string $schema = '', bool $refresh = false): array
184
    {
185
        return $this->getSchemaMetadata($schema, SchemaInterface::DEFAULT_VALUES, $refresh);
186
    }
187
188
    /**
189
     * @throws InvalidArgumentException
190
     * @throws NotSupportedException
191
     */
192
    public function getSchemaForeignKeys(string $schema = '', bool $refresh = false): array
193
    {
194
        return $this->getSchemaMetadata($schema, SchemaInterface::FOREIGN_KEYS, $refresh);
195
    }
196
197
    /**
198
     * @throws InvalidArgumentException
199
     * @throws NotSupportedException
200
     */
201
    public function getSchemaIndexes(string $schema = '', bool $refresh = false): array
202
    {
203
        return $this->getSchemaMetadata($schema, SchemaInterface::INDEXES, $refresh);
204
    }
205
206
    /**
207
     * @throws NotSupportedException If this method isn't supported by the underlying DBMS.
208
     */
209
    public function getSchemaNames(bool $refresh = false): array
210
    {
211
        if (empty($this->schemaNames) || $refresh) {
212
            $this->schemaNames = $this->findSchemaNames();
213
        }
214
215
        return $this->schemaNames;
216
    }
217
218
    /**
219
     * @throws InvalidArgumentException
220
     * @throws NotSupportedException
221
     */
222
    public function getSchemaPrimaryKeys(string $schema = '', bool $refresh = false): array
223
    {
224
        /** @psalm-var list<Constraint> */
225
        return $this->getSchemaMetadata($schema, SchemaInterface::PRIMARY_KEY, $refresh);
226
    }
227
228
    /**
229
     * @throws NotSupportedException
230
     * @throws InvalidArgumentException
231
     */
232
    public function getSchemaUniques(string $schema = '', bool $refresh = false): array
233
    {
234
        return $this->getSchemaMetadata($schema, SchemaInterface::UNIQUES, $refresh);
235
    }
236
237
    /**
238
     * @throws InvalidArgumentException
239
     */
240
    public function getTableChecks(string $name, bool $refresh = false): array
241
    {
242
        /** @psalm-var mixed $tableChecks */
243
        $tableChecks = $this->getTableMetadata($name, SchemaInterface::CHECKS, $refresh);
244
        return is_array($tableChecks) ? $tableChecks : [];
245
    }
246
247
    /**
248
     * @throws InvalidArgumentException
249
     */
250
    public function getTableDefaultValues(string $name, bool $refresh = false): array
251
    {
252
        /** @psalm-var mixed $tableDefaultValues */
253
        $tableDefaultValues = $this->getTableMetadata($name, SchemaInterface::DEFAULT_VALUES, $refresh);
254
        return is_array($tableDefaultValues) ? $tableDefaultValues : [];
255
    }
256
257
    /**
258
     * @throws InvalidArgumentException
259
     */
260
    public function getTableForeignKeys(string $name, bool $refresh = false): array
261
    {
262
        /** @psalm-var mixed $tableForeignKeys */
263
        $tableForeignKeys = $this->getTableMetadata($name, SchemaInterface::FOREIGN_KEYS, $refresh);
264
        return is_array($tableForeignKeys) ? $tableForeignKeys : [];
265
    }
266
267
    /**
268
     * @throws InvalidArgumentException
269
     */
270
    public function getTableIndexes(string $name, bool $refresh = false): array
271
    {
272
        /** @psalm-var mixed $tableIndexes */
273
        $tableIndexes = $this->getTableMetadata($name, SchemaInterface::INDEXES, $refresh);
274
        return is_array($tableIndexes) ? $tableIndexes : [];
275
    }
276
277
    /**
278
     * @throws NotSupportedException If this method isn't supported by the underlying DBMS.
279
     */
280
    public function getTableNames(string $schema = '', bool $refresh = false): array
281
    {
282
        if (!isset($this->tableNames[$schema]) || $refresh) {
283
            $this->tableNames[$schema] = $this->findTableNames($schema);
284
        }
285
286
        return is_array($this->tableNames[$schema]) ? $this->tableNames[$schema] : [];
287
    }
288
289
    /**
290
     * @throws InvalidArgumentException
291
     */
292
    public function getTablePrimaryKey(string $name, bool $refresh = false): Constraint|null
293
    {
294
        /** @psalm-var mixed $tablePrimaryKey */
295
        $tablePrimaryKey = $this->getTableMetadata($name, SchemaInterface::PRIMARY_KEY, $refresh);
296
        return $tablePrimaryKey instanceof Constraint ? $tablePrimaryKey : null;
297
    }
298
299
    /**
300
     * @throws InvalidArgumentException
301
     */
302
    public function getTableSchema(string $name, bool $refresh = false): TableSchemaInterface|null
303
    {
304
        /** @psalm-var mixed $tableSchema */
305
        $tableSchema = $this->getTableMetadata($name, SchemaInterface::SCHEMA, $refresh);
306
        return $tableSchema instanceof TableSchemaInterface ? $tableSchema : null;
307
    }
308
309
    /**
310
     * @throws NotSupportedException
311
     * @throws InvalidArgumentException
312
     */
313
    public function getTableSchemas(string $schema = '', bool $refresh = false): array
314
    {
315
        /** @psalm-var list<TableSchemaInterface> */
316
        return $this->getSchemaMetadata($schema, SchemaInterface::SCHEMA, $refresh);
317
    }
318
319
    /**
320
     * @throws InvalidArgumentException
321
     *
322
     * @return array The metadata for table unique constraints.
323
     */
324
    public function getTableUniques(string $name, bool $refresh = false): array
325
    {
326
        /** @psalm-var mixed $tableUniques */
327
        $tableUniques = $this->getTableMetadata($name, SchemaInterface::UNIQUES, $refresh);
328
        return is_array($tableUniques) ? $tableUniques : [];
329
    }
330
331
    public function isReadQuery(string $sql): bool
332
    {
333
        $pattern = '/^\s*(SELECT|SHOW|DESCRIBE)\b/i';
334
335
        return preg_match($pattern, $sql) > 0;
336
    }
337
338
    /**
339
     * @throws InvalidArgumentException
340
     */
341
    public function refresh(): void
342
    {
343
        if ($this->schemaCache->isEnabled()) {
344
            $this->schemaCache->invalidate($this->getCacheTag());
345
        }
346
347
        $this->tableNames = [];
348
        $this->tableMetadata = [];
349
    }
350
351
    /**
352
     * @throws InvalidArgumentException
353
     */
354
    public function refreshTableSchema(string $name): void
355
    {
356
        $rawName = $this->getRawTableName($name);
357
358
        unset($this->tableMetadata[$rawName]);
359
360
        $this->tableNames = [];
361
362
        if ($this->schemaCache->isEnabled()) {
363
            $this->schemaCache->remove($this->getCacheKey($rawName));
364
        }
365
    }
366
367
    public function enableCache(bool $value): void
368
    {
369
        $this->schemaCache->setEnabled($value);
370
    }
371
372
    /**
373
     * Returns all schema names in the database, including the default one but not system schemas.
374
     *
375
     * This method should be overridden by child classes to support this feature because the default
376
     * implementation simply throws an exception.
377
     *
378
     * @throws NotSupportedException If the DBMS doesn't support this method.
379
     *
380
     * @return array All schemas name in the database, except system schemas.
381
     */
382
    protected function findSchemaNames(): array
383
    {
384
        throw new NotSupportedException(static::class . ' does not support fetching all schema names.');
385
    }
386
387
    /**
388
     * Returns all table names in the database.
389
     *
390
     * This method should be overridden by child classes to support this feature because the default
391
     * implementation simply throws an exception.
392
     *
393
     * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema.
394
     *
395
     * @throws NotSupportedException If the DBMS doesn't support this method.
396
     *
397
     * @return array All tables name in the database. The names have NO schema name prefix.
398
     */
399
    protected function findTableNames(string $schema): array
0 ignored issues
show
Unused Code introduced by
The parameter $schema is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

399
    protected function findTableNames(/** @scrutinizer ignore-unused */ string $schema): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
400
    {
401
        throw new NotSupportedException(static::class . ' does not support fetching all table names.');
402
    }
403
404
    /**
405
     * Creates a column schema for the database.
406
     *
407
     * This method may be overridden by child classes to create a DBMS-specific column schema.
408
     *
409
     * @param string $type The abstract data type.
410
     * @param string $name The column name.
411
     * @param array $info The column information.
412
     * @psalm-param array{unsigned?: bool, dimension?: int} $info
413
     * Parameter `dimension` is for PgSQL only
414
     *
415
     * @return ColumnSchemaInterface
416
     */
417
    protected function createColumnSchema(string $type, string $name, bool|int ...$info): ColumnSchemaInterface
418
    {
419
        $phpType = $this->getColumnPhpType($type);
420
        $isUnsigned = !empty($info['unsigned']);
421
422
        if (
423
            $isUnsigned && PHP_INT_SIZE === 4 && $type === SchemaInterface::TYPE_INTEGER
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($isUnsigned && Yiisoft\...aInterface::TYPE_BIGINT, Probably Intended Meaning: $isUnsigned && Yiisoft\D...Interface::TYPE_BIGINT)
Loading history...
424
            || ($isUnsigned || PHP_INT_SIZE !== 8) && $type === SchemaInterface::TYPE_BIGINT
425
        ) {
426
            $column = new BigIntColumnSchema($name);
427
        } else {
428
            $column = $this->createPhpTypeColumnSchema($phpType, $name);
429
        }
430
431
        $column->type($type);
432
        $column->phpType($phpType);
433
        $column->unsigned($isUnsigned);
434
435
        return $column;
436
    }
437
438
    /**
439
     * Get the PHP type from an abstract database type.
440
     *
441
     * @param string $type The abstract database type.
442
     *
443
     * @return string The PHP type name.
444
     */
445
    protected function getColumnPhpType(string $type): string
446
    {
447
        return match ($type) {
448
            // abstract type => php type
449
            SchemaInterface::TYPE_TINYINT => SchemaInterface::PHP_TYPE_INTEGER,
450
            SchemaInterface::TYPE_SMALLINT => SchemaInterface::PHP_TYPE_INTEGER,
451
            SchemaInterface::TYPE_INTEGER => SchemaInterface::PHP_TYPE_INTEGER,
452
            SchemaInterface::TYPE_BIGINT => SchemaInterface::PHP_TYPE_INTEGER,
453
            SchemaInterface::TYPE_BOOLEAN => SchemaInterface::PHP_TYPE_BOOLEAN,
454
            SchemaInterface::TYPE_DECIMAL => SchemaInterface::PHP_TYPE_DOUBLE,
455
            SchemaInterface::TYPE_FLOAT => SchemaInterface::PHP_TYPE_DOUBLE,
456
            SchemaInterface::TYPE_DOUBLE => SchemaInterface::PHP_TYPE_DOUBLE,
457
            SchemaInterface::TYPE_BINARY => SchemaInterface::PHP_TYPE_RESOURCE,
458
            SchemaInterface::TYPE_JSON => SchemaInterface::PHP_TYPE_ARRAY,
459
            default => SchemaInterface::PHP_TYPE_STRING,
460
        };
461
    }
462
463
    protected function createPhpTypeColumnSchema(string $phpType, string $name): ColumnSchemaInterface
464
    {
465
        return match ($phpType) {
466
            SchemaInterface::PHP_TYPE_INTEGER => new IntegerColumnSchema($name),
467
            SchemaInterface::PHP_TYPE_DOUBLE => new DoubleColumnSchema($name),
468
            SchemaInterface::PHP_TYPE_BOOLEAN => new BooleanColumnSchema($name),
469
            SchemaInterface::PHP_TYPE_RESOURCE => new BinaryColumnSchema($name),
470
            SchemaInterface::PHP_TYPE_ARRAY => new JsonColumnSchema($name),
471
            default => new StringColumnSchema($name),
472
        };
473
    }
474
475
    /**
476
     * Returns the metadata of the given type for all tables in the given schema.
477
     *
478
     * @param string $schema The schema of the metadata. Defaults to empty string, meaning the current or default schema
479
     * name.
480
     * @param string $type The metadata type.
481
     * @param bool $refresh Whether to fetch the latest available table metadata. If this is `false`, cached data may be
482
     * returned if available.
483
     *
484
     * @throws InvalidArgumentException
485
     * @throws NotSupportedException
486
     *
487
     * @return array The metadata of the given type for all tables in the given schema.
488
     *
489
     * @psalm-return list<Constraint|TableSchemaInterface|array>
490
     */
491
    protected function getSchemaMetadata(string $schema, string $type, bool $refresh): array
492
    {
493
        $metadata = [];
494
        /** @psalm-var string[] $tableNames */
495
        $tableNames = $this->getTableNames($schema, $refresh);
496
497
        foreach ($tableNames as $name) {
498
            $name = $this->db->getQuoter()->quoteSimpleTableName($name);
499
500
            if ($schema !== '') {
501
                $name = $schema . '.' . $name;
502
            }
503
504
            $tableMetadata = $this->getTableTypeMetadata($type, $name, $refresh);
505
506
            if ($tableMetadata !== null) {
507
                $metadata[] = $tableMetadata;
508
            }
509
        }
510
511
        return $metadata;
512
    }
513
514
    /**
515
     * Returns the metadata of the given type for the given table.
516
     *
517
     * @param string $name The table name. The table name may contain a schema name if any.
518
     * Don't quote the table name.
519
     * @param string $type The metadata type.
520
     * @param bool $refresh whether to reload the table metadata even if it's found in the cache.
521
     *
522
     * @throws InvalidArgumentException
523
     *
524
     * @return mixed The metadata of the given type for the given table.
525
     */
526
    protected function getTableMetadata(string $name, string $type, bool $refresh = false): mixed
527
    {
528
        $rawName = $this->getRawTableName($name);
529
530
        if (!isset($this->tableMetadata[$rawName])) {
531
            $this->loadTableMetadataFromCache($rawName);
532
        }
533
534
        if ($refresh || !isset($this->tableMetadata[$rawName][$type])) {
535
            /** @psalm-suppress MixedArrayAssignment */
536
            $this->tableMetadata[$rawName][$type] = $this->loadTableTypeMetadata($type, $rawName);
537
            $this->saveTableMetadataToCache($rawName);
538
        }
539
540
        /** @psalm-suppress MixedArrayAccess */
541
        return $this->tableMetadata[$rawName][$type];
542
    }
543
544
    /**
545
     * This method returns the desired metadata type for the table name.
546
     */
547
    protected function loadTableTypeMetadata(string $type, string $name): Constraint|array|TableSchemaInterface|null
548
    {
549
        return match ($type) {
550
            SchemaInterface::SCHEMA => $this->loadTableSchema($name),
551
            SchemaInterface::PRIMARY_KEY => $this->loadTablePrimaryKey($name),
552
            SchemaInterface::UNIQUES => $this->loadTableUniques($name),
553
            SchemaInterface::FOREIGN_KEYS => $this->loadTableForeignKeys($name),
554
            SchemaInterface::INDEXES => $this->loadTableIndexes($name),
555
            SchemaInterface::DEFAULT_VALUES => $this->loadTableDefaultValues($name),
556
            SchemaInterface::CHECKS => $this->loadTableChecks($name),
557
            default => null,
558
        };
559
    }
560
561
    /**
562
     * This method returns the desired metadata type for table name (with refresh if needed).
563
     *
564
     * @throws InvalidArgumentException
565
     */
566
    protected function getTableTypeMetadata(
567
        string $type,
568
        string $name,
569
        bool $refresh = false
570
    ): Constraint|array|null|TableSchemaInterface {
571
        return match ($type) {
572
            SchemaInterface::SCHEMA => $this->getTableSchema($name, $refresh),
573
            SchemaInterface::PRIMARY_KEY => $this->getTablePrimaryKey($name, $refresh),
574
            SchemaInterface::UNIQUES => $this->getTableUniques($name, $refresh),
575
            SchemaInterface::FOREIGN_KEYS => $this->getTableForeignKeys($name, $refresh),
576
            SchemaInterface::INDEXES => $this->getTableIndexes($name, $refresh),
577
            SchemaInterface::DEFAULT_VALUES => $this->getTableDefaultValues($name, $refresh),
578
            SchemaInterface::CHECKS => $this->getTableChecks($name, $refresh),
579
            default => null,
580
        };
581
    }
582
583
    /**
584
     * Change row's array key case to lower.
585
     *
586
     * @param array $row Thew row's array or an array of row arrays.
587
     * @param bool $multiple Whether many rows or a single row passed.
588
     *
589
     * @return array The normalized row or rows.
590
     */
591
    protected function normalizeRowKeyCase(array $row, bool $multiple): array
592
    {
593
        if ($multiple) {
594
            return array_map(static fn (array $row) => array_change_key_case($row), $row);
595
        }
596
597
        return array_change_key_case($row);
598
    }
599
600
    /**
601
     * Resolves the table name and schema name (if any).
602
     *
603
     * @param string $name The table name.
604
     *
605
     * @throws NotSupportedException If the DBMS doesn't support this method.
606
     *
607
     * @return TableSchemaInterface The with resolved table, schema, etc. names.
608
     *
609
     * @see TableSchemaInterface
610
     */
611
    protected function resolveTableName(string $name): TableSchemaInterface
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

611
    protected function resolveTableName(/** @scrutinizer ignore-unused */ string $name): TableSchemaInterface

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
612
    {
613
        throw new NotSupportedException(static::class . ' does not support resolving table names.');
614
    }
615
616
    /**
617
     * Sets the metadata of the given type for the given table.
618
     *
619
     * @param string $name The table name.
620
     * @param string $type The metadata type.
621
     * @param mixed $data The metadata to set.
622
     */
623
    protected function setTableMetadata(string $name, string $type, mixed $data): void
624
    {
625
        /** @psalm-suppress MixedArrayAssignment  */
626
        $this->tableMetadata[$this->getRawTableName($name)][$type] = $data;
627
    }
628
629
    /**
630
     * Tries to load and populate table metadata from cache.
631
     *
632
     * @throws InvalidArgumentException
633
     */
634
    private function loadTableMetadataFromCache(string $rawName): void
635
    {
636
        if (!$this->schemaCache->isEnabled() || $this->schemaCache->isExcluded($rawName)) {
637
            $this->tableMetadata[$rawName] = [];
638
            return;
639
        }
640
641
        $metadata = $this->schemaCache->get($this->getCacheKey($rawName));
642
643
        if (
644
            !is_array($metadata) ||
645
            !isset($metadata[self::CACHE_VERSION]) ||
646
            $metadata[self::CACHE_VERSION] !== static::SCHEMA_CACHE_VERSION
647
        ) {
648
            $this->tableMetadata[$rawName] = [];
649
            return;
650
        }
651
652
        unset($metadata[self::CACHE_VERSION]);
653
        $this->tableMetadata[$rawName] = $metadata;
654
    }
655
656
    /**
657
     * Saves table metadata to cache.
658
     *
659
     * @throws InvalidArgumentException
660
     */
661
    private function saveTableMetadataToCache(string $rawName): void
662
    {
663
        if ($this->schemaCache->isEnabled() === false || $this->schemaCache->isExcluded($rawName) === true) {
664
            return;
665
        }
666
667
        /** @psalm-var array<string, array<TableSchemaInterface|int>> $metadata */
668
        $metadata = $this->tableMetadata[$rawName];
669
        /** @psalm-var int */
670
        $metadata[self::CACHE_VERSION] = static::SCHEMA_CACHE_VERSION;
671
672
        $this->schemaCache->set($this->getCacheKey($rawName), $metadata, $this->getCacheTag());
673
    }
674
675
    /**
676
     * Find the view names for the database.
677
     *
678
     * @param string $schema The schema of the views.
679
     * Defaults to empty string, meaning the current or default schema.
680
     *
681
     * @return array The names of all views in the database.
682
     */
683
    protected function findViewNames(string $schema = ''): array
0 ignored issues
show
Unused Code introduced by
The parameter $schema is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

683
    protected function findViewNames(/** @scrutinizer ignore-unused */ string $schema = ''): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
684
    {
685
        return [];
686
    }
687
688
    /**
689
     * @throws Throwable
690
     *
691
     * @return array The view names for the database.
692
     */
693
    public function getViewNames(string $schema = '', bool $refresh = false): array
694
    {
695
        if (!isset($this->viewNames[$schema]) || $refresh) {
696
            $this->viewNames[$schema] = $this->findViewNames($schema);
697
        }
698
699
        return (array) $this->viewNames[$schema];
700
    }
701
}
702