Passed
Pull Request — master (#467)
by Alexander
10:48 queued 08:17
created

AbstractSchema::getDefaultSchema()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

385
    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...
386
    {
387
        throw new NotSupportedException(static::class . ' does not support fetching all table names.');
388
    }
389
390
    /**
391
     * Extracts the PHP type from abstract DB type.
392
     *
393
     * @param ColumnSchemaInterface $column The column schema information.
394
     *
395
     * @return string The PHP type name.
396
     */
397
    protected function getColumnPhpType(ColumnSchemaInterface $column): string
398
    {
399
        /** @psalm-var string[] $typeMap */
400
        $typeMap = [
401
            // abstract type => php type
402
            self::TYPE_TINYINT => self::PHP_TYPE_INTEGER,
403
            self::TYPE_SMALLINT => self::PHP_TYPE_INTEGER,
404
            self::TYPE_INTEGER => self::PHP_TYPE_INTEGER,
405
            self::TYPE_BIGINT => self::PHP_TYPE_INTEGER,
406
            self::TYPE_BOOLEAN => self::PHP_TYPE_BOOLEAN,
407
            self::TYPE_FLOAT => self::PHP_TYPE_DOUBLE,
408
            self::TYPE_DOUBLE => self::PHP_TYPE_DOUBLE,
409
            self::TYPE_BINARY => self::PHP_TYPE_RESOURCE,
410
            self::TYPE_JSON => self::PHP_TYPE_ARRAY,
411
        ];
412
413
        if (isset($typeMap[$column->getType()])) {
414
            if ($column->getType() === self::TYPE_BIGINT) {
415
                return PHP_INT_SIZE === 8 && !$column->isUnsigned() ? self::PHP_TYPE_INTEGER : self::PHP_TYPE_STRING;
416
            }
417
418
            if ($column->getType() === self::TYPE_INTEGER) {
419
                return PHP_INT_SIZE === 4 && $column->isUnsigned() ? self::PHP_TYPE_STRING : self::PHP_TYPE_INTEGER;
420
            }
421
422
            return $typeMap[$column->getType()];
423
        }
424
425
        return self::PHP_TYPE_STRING;
426
    }
427
428
    /**
429
     * Returns the metadata of the given type for all tables in the given schema.
430
     *
431
     * @param string $schema The schema of the metadata. Defaults to empty string, meaning the current or default schema
432
     * name.
433
     * @param string $type The metadata type.
434
     * @param bool $refresh Whether to fetch the latest available table metadata. If this is `false`, cached data may be
435
     * returned if available.
436
     *
437
     * @throws NotSupportedException
438
     *
439
     * @return array The metadata of the given type for all tables in the given schema.
440
     *
441
     * @psalm-return list<Constraint|TableSchemaInterface|array>
442
     */
443
    protected function getSchemaMetadata(string $schema, string $type, bool $refresh): array
444
    {
445
        $metadata = [];
446
        /** @psalm-var string[] $tableNames */
447
        $tableNames = $this->getTableNames($schema, $refresh);
448
449
        foreach ($tableNames as $name) {
450
            if ($schema !== '') {
451
                $name = $schema . '.' . $name;
452
            }
453
454
            $tableMetadata = $this->getTableTypeMetadata($type, $name, $refresh);
455
456
            if ($tableMetadata !== null) {
457
                $metadata[] = $tableMetadata;
458
            }
459
        }
460
461
        return $metadata;
462
    }
463
464
    /**
465
     * Returns the metadata of the given type for the given table.
466
     *
467
     * @param string $name The table name. The table name may contain schema name if any. Do not quote the table name.
468
     * @param string $type The metadata type.
469
     * @param bool $refresh whether to reload the table metadata even if it is found in the cache.
470
     *
471
     * @return mixed metadata.
472
     *
473
     * @psalm-suppress MixedArrayAccess
474
     * @psalm-suppress MixedArrayAssignment
475
     */
476
    protected function getTableMetadata(string $name, string $type, bool $refresh = false): mixed
477
    {
478
        $rawName = $this->getRawTableName($name);
479
480
        if (!isset($this->tableMetadata[$rawName])) {
481
            $this->loadTableMetadataFromCache($rawName);
482
        }
483
484
        if ($refresh || !isset($this->tableMetadata[$rawName][$type])) {
485
            $this->tableMetadata[$rawName][$type] = $this->loadTableTypeMetadata($type, $rawName);
486
            $this->saveTableMetadataToCache($rawName);
487
        }
488
489
        return $this->tableMetadata[$rawName][$type];
490
    }
491
492
    /**
493
     * This method returns the desired metadata type for the table name.
494
     */
495
    protected function loadTableTypeMetadata(string $type, string $name): Constraint|array|TableSchemaInterface|null
496
    {
497
        return match ($type) {
498
            self::SCHEMA => $this->loadTableSchema($name),
499
            self::PRIMARY_KEY => $this->loadTablePrimaryKey($name),
500
            self::UNIQUES => $this->loadTableUniques($name),
501
            self::FOREIGN_KEYS => $this->loadTableForeignKeys($name),
502
            self::INDEXES => $this->loadTableIndexes($name),
503
            self::DEFAULT_VALUES => $this->loadTableDefaultValues($name),
504
            self::CHECKS => $this->loadTableChecks($name),
505
            default => null,
506
        };
507
    }
508
509
    /**
510
     * This method returns the desired metadata type for table name (with refresh if needed)
511
     */
512
    protected function getTableTypeMetadata(
513
        string $type,
514
        string $name,
515
        bool $refresh = false
516
    ): Constraint|array|null|TableSchemaInterface {
517
        return match ($type) {
518
            self::SCHEMA => $this->getTableSchema($name, $refresh),
519
            self::PRIMARY_KEY => $this->getTablePrimaryKey($name, $refresh),
520
            self::UNIQUES => $this->getTableUniques($name, $refresh),
521
            self::FOREIGN_KEYS => $this->getTableForeignKeys($name, $refresh),
522
            self::INDEXES => $this->getTableIndexes($name, $refresh),
523
            self::DEFAULT_VALUES => $this->getTableDefaultValues($name, $refresh),
524
            self::CHECKS => $this->getTableChecks($name, $refresh),
525
            default => null,
526
        };
527
    }
528
529
    /**
530
     * Changes row's array key case to lower.
531
     *
532
     * @param array $row Thew row's array or an array of row's arrays.
533
     * @param bool $multiple Whether multiple rows or a single row passed.
534
     *
535
     * @return array The normalized row or rows.
536
     */
537
    protected function normalizeRowKeyCase(array $row, bool $multiple): array
538
    {
539
        if ($multiple) {
540
            return array_map(static fn (array $row) => array_change_key_case($row), $row);
541
        }
542
543
        return array_change_key_case($row);
544
    }
545
546
    /**
547
     * Resolves the table name and schema name (if any).
548
     *
549
     * @param string $name The table name.
550
     *
551
     * @throws NotSupportedException If this method is not supported by the DBMS.
552
     *
553
     * @return TableSchemaInterface The with resolved table, schema, etc. names.
554
     *
555
     * {@see TableSchemaInterface}
556
     */
557
    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

557
    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...
558
    {
559
        throw new NotSupportedException(static::class . ' does not support resolving table names.');
560
    }
561
562
    /**
563
     * Sets the metadata of the given type for the given table.
564
     *
565
     * @param string $name The table name.
566
     * @param string $type The metadata type.
567
     * @param mixed $data The metadata to be set.
568
     *
569
     * @psalm-suppress MixedArrayAssignment
570
     */
571
    protected function setTableMetadata(string $name, string $type, mixed $data): void
572
    {
573
        $this->tableMetadata[$this->getRawTableName($name)][$type] = $data;
574
    }
575
576
    /**
577
     * Tries to load and populate table metadata from cache.
578
     */
579
    private function loadTableMetadataFromCache(string $rawName): void
580
    {
581
        if (!$this->schemaCache->isEnabled() || $this->schemaCache->isExcluded($rawName)) {
582
            $this->tableMetadata[$rawName] = [];
583
            return;
584
        }
585
586
        $metadata = $this->schemaCache->getOrSet(
587
            $this->getCacheKey($rawName),
588
            null,
589
            $this->schemaCache->getDuration(),
590
            new TagDependency($this->getCacheTag()),
591
        );
592
593
        if (
594
            !is_array($metadata) ||
595
            !isset($metadata[self::CACHE_VERSION]) ||
596
            $metadata[self::CACHE_VERSION] !== static::SCHEMA_CACHE_VERSION
597
        ) {
598
            $this->tableMetadata[$rawName] = [];
599
            return;
600
        }
601
602
        unset($metadata[self::CACHE_VERSION]);
603
        $this->tableMetadata[$rawName] = $metadata;
604
    }
605
606
    /**
607
     * Saves table metadata to cache.
608
     */
609
    private function saveTableMetadataToCache(string $rawName): void
610
    {
611
        if ($this->schemaCache->isEnabled() === false || $this->schemaCache->isExcluded($rawName) === true) {
612
            return;
613
        }
614
615
        /** @psalm-var array<string, array<TableSchemaInterface|int>> $metadata */
616
        $metadata = $this->tableMetadata[$rawName];
617
        /** @var int */
618
        $metadata[self::CACHE_VERSION] = static::SCHEMA_CACHE_VERSION;
619
620
        $this->schemaCache->set(
621
            $this->getCacheKey($rawName),
622
            $metadata,
623
            $this->schemaCache->getDuration(),
624
            new TagDependency($this->getCacheTag()),
625
        );
626
    }
627
628
    /**
629
     * Find the view names for the database.
630
     *
631
     * @param string $schema the schema of the views. Defaults to empty string, meaning the current or default schema.
632
     *
633
     * @return array The names of all views in the database.
634
     */
635
    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

635
    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...
636
    {
637
        return [];
638
    }
639
640
    /**
641
     * @throws Throwable
642
     *
643
     * @return array The view names for the database.
644
     */
645
    public function getViewNames(string $schema = '', bool $refresh = false): array
646
    {
647
        if (!isset($this->viewNames[$schema]) || $refresh) {
648
            $this->viewNames[$schema] = $this->findViewNames($schema);
649
        }
650
651
        return (array) $this->viewNames[$schema];
652
    }
653
}
654