Passed
Pull Request — master (#245)
by Wilmer
12:54
created

TestSchemaTrait::testGetColumnNoExist()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
ccs 5
cts 5
cp 1
crap 1
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\TestUtility;
6
7
use PDO;
8
use Yiisoft\Db\Constraint\CheckConstraint;
9
use Yiisoft\Db\Constraint\Constraint;
10
use Yiisoft\Db\Constraint\ForeignKeyConstraint;
11
use Yiisoft\Db\Constraint\IndexConstraint;
12
use Yiisoft\Db\Schema\ColumnSchema;
13
use Yiisoft\Db\Schema\Schema;
14
use Yiisoft\Db\Schema\TableSchema;
15
16
use function array_keys;
17
use function fclose;
18
use function fopen;
19
use function gettype;
20
use function is_array;
21
use function json_encode;
22
use function ksort;
23
use function print_r;
24
use function sort;
25
use function sprintf;
26
use function strtolower;
27
28
trait TestSchemaTrait
29
{
30 5
    public function testGetTableSchemasWithAttrCase(): void
31
    {
32 5
        $db = $this->getConnection(false);
0 ignored issues
show
Bug introduced by
It seems like getConnection() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

32
        /** @scrutinizer ignore-call */ 
33
        $db = $this->getConnection(false);
Loading history...
33
34 5
        $db->getSlavePdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
35
36 5
        $this->assertCount(count($db->getSchema()->getTableNames()), $db->getSchema()->getTableSchemas());
0 ignored issues
show
Bug introduced by
It seems like assertCount() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

36
        $this->/** @scrutinizer ignore-call */ 
37
               assertCount(count($db->getSchema()->getTableNames()), $db->getSchema()->getTableSchemas());
Loading history...
37
38 5
        $db->getSlavePdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER);
39
40 5
        $this->assertCount(count($db->getSchema()->getTableNames()), $db->getSchema()->getTableSchemas());
41 5
    }
42
43 5
    public function testGetNonExistingTableSchema(): void
44
    {
45 5
        $this->assertNull($this->getConnection()->getSchema()->getTableSchema('nonexisting_table'));
0 ignored issues
show
Bug introduced by
It seems like assertNull() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

45
        $this->/** @scrutinizer ignore-call */ 
46
               assertNull($this->getConnection()->getSchema()->getTableSchema('nonexisting_table'));
Loading history...
46 5
    }
47
48 5
    public function testSchemaCache(): void
49
    {
50 5
        $db = $this->getConnection();
51
52 5
        $schema = $db->getSchema();
53
54 5
        $this->schemaCache->setEnable(true);
55
56 5
        $noCacheTable = $schema->getTableSchema('type', true);
57 5
        $cachedTable = $schema->getTableSchema('type', false);
58
59 5
        $this->assertEquals($noCacheTable, $cachedTable);
0 ignored issues
show
Bug introduced by
It seems like assertEquals() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

59
        $this->/** @scrutinizer ignore-call */ 
60
               assertEquals($noCacheTable, $cachedTable);
Loading history...
60
61 5
        $db->createCommand()->renameTable('type', 'type_test');
62
63 5
        $noCacheTable = $schema->getTableSchema('type', true);
64
65 5
        $this->assertNotSame($noCacheTable, $cachedTable);
0 ignored issues
show
Bug introduced by
It seems like assertNotSame() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

65
        $this->/** @scrutinizer ignore-call */ 
66
               assertNotSame($noCacheTable, $cachedTable);
Loading history...
66
67 5
        $db->createCommand()->renameTable('type_test', 'type');
68 5
    }
69
70
    /**
71
     * @depends testSchemaCache
72
     */
73 5
    public function testRefreshTableSchema(): void
74
    {
75 5
        $schema = $this->getConnection()->getSchema();
76
77 5
        $this->schemaCache->setEnable(true);
78
79 5
        $noCacheTable = $schema->getTableSchema('type', true);
80
81 5
        $schema->refreshTableSchema('type');
82
83 5
        $refreshedTable = $schema->getTableSchema('type', false);
84
85 5
        $this->assertNotSame($noCacheTable, $refreshedTable);
86 5
    }
87
88 2
    public function testCompositeFk(): void
89
    {
90 2
        $schema = $this->getConnection()->getSchema();
91
92 2
        $table = $schema->getTableSchema('composite_fk');
93
94 2
        $fk = $table->getForeignKeys();
95
96 2
        $this->assertCount(1, $fk);
97 2
        $this->assertTrue(isset($fk['FK_composite_fk_order_item']));
0 ignored issues
show
Bug introduced by
It seems like assertTrue() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

97
        $this->/** @scrutinizer ignore-call */ 
98
               assertTrue(isset($fk['FK_composite_fk_order_item']));
Loading history...
98 2
        $this->assertEquals('order_item', $fk['FK_composite_fk_order_item'][0]);
99 2
        $this->assertEquals('order_id', $fk['FK_composite_fk_order_item']['order_id']);
100 2
        $this->assertEquals('item_id', $fk['FK_composite_fk_order_item']['item_id']);
101 2
    }
102
103 4
    public function testGetPDOType(): void
104
    {
105
        $values = [
106 4
            [null, PDO::PARAM_NULL],
107
            ['', PDO::PARAM_STR],
108
            ['hello', PDO::PARAM_STR],
109
            [0, PDO::PARAM_INT],
110
            [1, PDO::PARAM_INT],
111
            [1337, PDO::PARAM_INT],
112
            [true, PDO::PARAM_BOOL],
113
            [false, PDO::PARAM_BOOL],
114 4
            [$fp = fopen(__FILE__, 'rb'), PDO::PARAM_LOB],
115
        ];
116
117 4
        $schema = $this->getConnection()->getSchema();
118
119 4
        foreach ($values as $value) {
120 4
            $this->assertEquals($value[1], $schema->getPdoType($value[0]), 'type for value ' . print_r($value[0], true) . ' does not match.');
0 ignored issues
show
Bug introduced by
Are you sure print_r($value[0], true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

120
            $this->assertEquals($value[1], $schema->getPdoType($value[0]), 'type for value ' . /** @scrutinizer ignore-type */ print_r($value[0], true) . ' does not match.');
Loading history...
121
        }
122
123 4
        fclose($fp);
124 4
    }
125
126 5
    public function testColumnSchema(): void
127
    {
128 5
        $columns = $this->getExpectedColumns();
0 ignored issues
show
Bug introduced by
It seems like getExpectedColumns() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

128
        /** @scrutinizer ignore-call */ 
129
        $columns = $this->getExpectedColumns();
Loading history...
129
130 5
        $table = $this->getConnection(false)->getSchema()->getTableSchema('type', true);
131
132 5
        $expectedColNames = array_keys($columns);
133
134 5
        sort($expectedColNames);
135
136 5
        $colNames = $table->getColumnNames();
137
138 5
        sort($colNames);
139
140 5
        $this->assertEquals($expectedColNames, $colNames);
141
142 5
        foreach ($table->getColumns() as $name => $column) {
143 5
            $expected = $columns[$name];
144 5
            $this->assertSame(
0 ignored issues
show
Bug introduced by
It seems like assertSame() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

144
            $this->/** @scrutinizer ignore-call */ 
145
                   assertSame(
Loading history...
145 5
                $expected['dbType'],
146 5
                $column->getDbType(),
147 5
                "dbType of column $name does not match. type is {$column->getType()}, dbType is {$column->getDbType()}."
148
            );
149 5
            $this->assertSame(
150 5
                $expected['phpType'],
151 5
                $column->getPhpType(),
152 5
                "phpType of column $name does not match. type is {$column->getType()}, dbType is {$column->getDbType()}."
153
            );
154 5
            $this->assertSame($expected['type'], $column->getType(), "type of column $name does not match.");
155 5
            $this->assertSame(
156 5
                $expected['allowNull'],
157 5
                $column->isAllowNull(),
158 5
                "allowNull of column $name does not match."
159
            );
160 5
            $this->assertSame(
161 5
                $expected['autoIncrement'],
162 5
                $column->isAutoIncrement(),
163 5
                "autoIncrement of column $name does not match."
164
            );
165 5
            $this->assertSame(
166 5
                $expected['enumValues'],
167 5
                $column->getEnumValues(),
168 5
                "enumValues of column $name does not match."
169
            );
170 5
            $this->assertSame($expected['size'], $column->getSize(), "size of column $name does not match.");
171 5
            $this->assertSame(
172 5
                $expected['precision'],
173 5
                $column->getPrecision(),
174 5
                "precision of column $name does not match."
175
            );
176 5
            $this->assertSame($expected['scale'], $column->getScale(), "scale of column $name does not match.");
177 5
            if (\is_object($expected['defaultValue'])) {
178 3
                $this->assertIsObject(
0 ignored issues
show
Bug introduced by
It seems like assertIsObject() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

178
                $this->/** @scrutinizer ignore-call */ 
179
                       assertIsObject(
Loading history...
179 3
                    $column->getDefaultValue(),
180 3
                    "defaultValue of column $name is expected to be an object but it is not."
181
                );
182 3
                $this->assertEquals(
183 3
                    (string) $expected['defaultValue'],
184 3
                    (string) $column->getDefaultValue(),
185 3
                    "defaultValue of column $name does not match."
186
                );
187
            } else {
188 5
                $this->assertEquals(
189 5
                    $expected['defaultValue'],
190 5
                    $column->getDefaultValue(),
191 5
                    "defaultValue of column $name does not match."
192
                );
193
            }
194
            /* Pgsql only */
195 5
            if (isset($expected['dimension'])) {
196 1
                $this->assertSame(
197 1
                    $expected['dimension'],
198 1
                    $column->getDimension(),
199 1
                    "dimension of column $name does not match"
200
                );
201
            }
202
        }
203 5
    }
204
205 5
    public function testColumnSchemaDbTypecastWithEmptyCharType(): void
206
    {
207 5
        $columnSchema = new ColumnSchema();
208
209 5
        $columnSchema->setType(Schema::TYPE_CHAR);
210
211 5
        $this->assertSame('', $columnSchema->dbTypecast(''));
212 5
    }
213
214 5
    public function testNegativeDefaultValues(): void
215
    {
216 5
        $schema = $this->getConnection()->getSchema();
217
218 5
        $table = $schema->getTableSchema('negative_default_values');
219
220 5
        $this->assertEquals(-123, $table->getColumn('tinyint_col')->getDefaultValue());
221 5
        $this->assertEquals(-123, $table->getColumn('smallint_col')->getDefaultValue());
222 5
        $this->assertEquals(-123, $table->getColumn('int_col')->getDefaultValue());
223 5
        $this->assertEquals(-123, $table->getColumn('bigint_col')->getDefaultValue());
224 5
        $this->assertEquals(-12345.6789, $table->getColumn('float_col')->getDefaultValue());
225 5
        $this->assertEquals(-33.22, $table->getColumn('numeric_col')->getDefaultValue());
226 5
    }
227
228 5
    public function testContraintTablesExistance(): void
229
    {
230
        $tableNames = [
231 5
            'T_constraints_1',
232
            'T_constraints_2',
233
            'T_constraints_3',
234
            'T_constraints_4',
235
        ];
236
237 5
        $schema = $this->getConnection()->getSchema();
238
239 5
        foreach ($tableNames as $tableName) {
240 5
            $tableSchema = $schema->getTableSchema($tableName);
241 5
            $this->assertInstanceOf(TableSchema::class, $tableSchema, $tableName);
0 ignored issues
show
Bug introduced by
It seems like assertInstanceOf() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

241
            $this->/** @scrutinizer ignore-call */ 
242
                   assertInstanceOf(TableSchema::class, $tableSchema, $tableName);
Loading history...
242
        }
243 5
    }
244
245 240
    public function testGetColumnNoExist(): void
246
    {
247 240
        $schema = $this->getConnection()->getSchema();
248 240
        $table = $schema->getTableSchema('negative_default_values');
249 45
250 45
        $this->assertNull($table->getColumn('no_exist'));
251 195
    }
252 180
253 180
    private function assertMetadataEquals($expected, $actual): void
254 15
    {
255 15
        switch (strtolower(gettype($expected))) {
256 15
            case 'object':
257
                $this->assertIsObject($actual);
258
                break;
259 240
            case 'array':
260 180
                $this->assertIsArray($actual);
0 ignored issues
show
Bug introduced by
It seems like assertIsArray() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

260
                $this->/** @scrutinizer ignore-call */ 
261
                       assertIsArray($actual);
Loading history...
261 180
                break;
262
            case 'null':
263
                $this->assertNull($actual);
264 240
                break;
265
        }
266 240
267 180
        if (is_array($expected)) {
268 180
            $this->normalizeArrayKeys($expected, false);
269
            $this->normalizeArrayKeys($actual, false);
270
        }
271 240
272 240
        $this->normalizeConstraints($expected, $actual);
273
274 180
        if (is_array($expected)) {
275
            $this->normalizeArrayKeys($expected, true);
276 180
            $this->normalizeArrayKeys($actual, true);
277
        }
278 180
279 117
        $this->assertEquals($expected, $actual);
280 117
    }
281
282 117
    private function normalizeArrayKeys(array &$array, bool $caseSensitive): void
283 117
    {
284
        $newArray = [];
285
286 117
        foreach ($array as $value) {
287 117
            if ($value instanceof Constraint) {
288
                $key = (array) $value;
289 117
                unset(
290
                    $key["\000Yiisoft\Db\Constraint\Constraint\000name"],
291
                    $key["\u0000Yiisoft\\Db\\Constraint\\ForeignKeyConstraint\u0000foreignSchemaName"]
292
                );
293
294 117
                foreach ($key as $keyName => $keyValue) {
295
                    if ($keyValue instanceof AnyCaseValue) {
296 117
                        $key[$keyName] = $keyValue->value;
297 117
                    } elseif ($keyValue instanceof AnyValue) {
298 117
                        $key[$keyName] = '[AnyValue]';
299
                    }
300
                }
301
302
                ksort($key, SORT_STRING);
303
304 180
                $newArray[$caseSensitive
305
                    ? json_encode($key, JSON_THROW_ON_ERROR)
306 180
                    : strtolower(json_encode($key, JSON_THROW_ON_ERROR))] = $value;
307 180
            } else {
308
                $newArray[] = $value;
309 240
            }
310
        }
311 240
312 180
        ksort($newArray, SORT_STRING);
313 117
314
        $array = $newArray;
315
    }
316
317 117
    private function normalizeConstraints(&$expected, &$actual): void
318
    {
319 60
        if (is_array($expected)) {
320 45
            foreach ($expected as $key => $value) {
321
                if (!$value instanceof Constraint || !isset($actual[$key]) || !$actual[$key] instanceof Constraint) {
322 240
                    continue;
323
                }
324 162
325
                $this->normalizeConstraintPair($value, $actual[$key]);
326 162
            }
327
        } elseif ($expected instanceof Constraint && $actual instanceof Constraint) {
328
            $this->normalizeConstraintPair($expected, $actual);
329
        }
330 162
    }
331 162
332 87
    private function normalizeConstraintPair(Constraint $expectedConstraint, Constraint $actualConstraint): void
333 102
    {
334
        if (get_class($expectedConstraint) !== get_class($actualConstraint)) {
335
            return;
336
        }
337 162
338
        foreach (array_keys((array) $expectedConstraint) as $name) {
339
            if ($expectedConstraint->getName() instanceof AnyValue) {
340
                $actualConstraint->name($expectedConstraint->getName());
341
            } elseif ($expectedConstraint->getName() instanceof AnyCaseValue) {
342
                $actualConstraint->name(new AnyCaseValue($actualConstraint->getName()));
0 ignored issues
show
Bug introduced by
It seems like $actualConstraint->getName() can also be of type object; however, parameter $value of Yiisoft\Db\TestUtility\AnyCaseValue::__construct() does only seem to accept string|string[], maybe add an additional type check? ( Ignorable by Annotation )

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

342
                $actualConstraint->name(new AnyCaseValue(/** @scrutinizer ignore-type */ $actualConstraint->getName()));
Loading history...
343
            }
344
        }
345
    }
346
347
    public function constraintsProviderTrait(): array
348
    {
349
        return [
350
            '1: primary key' => [
351
                'T_constraints_1',
352
                'primaryKey',
353
                (new Constraint())
354
                    ->name(AnyValue::getInstance())
355
                    ->columnNames(['C_id']),
356
            ],
357
            '1: check' => [
358
                'T_constraints_1',
359
                'checks',
360
                [
361
                    (new CheckConstraint())
362
                        ->name(AnyValue::getInstance())
363
                        ->columnNames(['C_check'])
364
                        ->expression("C_check <> ''"),
365
                ],
366
            ],
367
            '1: unique' => [
368
                'T_constraints_1',
369
                'uniques',
370
                [
371
                    (new Constraint())
372
                        ->name('CN_unique')
373
                        ->columnNames(['C_unique']),
374
                ],
375
            ],
376
            '1: index' => [
377
                'T_constraints_1',
378
                'indexes',
379
                [
380
                    (new IndexConstraint())
381
                        ->name(AnyValue::getInstance())
382
                        ->columnNames(['C_id'])
383
                        ->unique(true)
384
                        ->primary(true),
385
                    (new IndexConstraint())
386
                        ->name('CN_unique')
387
                        ->columnNames(['C_unique'])
388
                        ->primary(false)
389
                        ->unique(true),
390
                ],
391
            ],
392
            '1: default' => ['T_constraints_1', 'defaultValues', false],
393
394
            '2: primary key' => [
395
                'T_constraints_2',
396
                'primaryKey',
397
                (new Constraint())
398
                    ->name('CN_pk')
399
                    ->columnNames(['C_id_1', 'C_id_2']),
400
            ],
401
            '2: unique' => [
402
                'T_constraints_2',
403
                'uniques',
404
                [
405
                    (new Constraint())
406
                        ->name('CN_constraints_2_multi')
407
                        ->columnNames(['C_index_2_1', 'C_index_2_2']),
408
                ],
409
            ],
410
            '2: index' => [
411
                'T_constraints_2',
412
                'indexes',
413
                [
414
                    (new IndexConstraint())
415
                        ->name(AnyValue::getInstance())
416
                        ->columnNames(['C_id_1', 'C_id_2'])
417
                        ->unique(true)
418
                        ->primary(true),
419
                    (new IndexConstraint())
420
                        ->name('CN_constraints_2_single')
421
                        ->columnNames(['C_index_1'])
422
                        ->primary(false)
423
                        ->unique(false),
424
                    (new IndexConstraint())
425
                        ->name('CN_constraints_2_multi')
426
                        ->columnNames(['C_index_2_1', 'C_index_2_2'])
427
                        ->primary(false)
428
                        ->unique(true),
429
                ],
430
            ],
431
            '2: check' => ['T_constraints_2', 'checks', []],
432
            '2: default' => ['T_constraints_2', 'defaultValues', false],
433
434
            '3: primary key' => ['T_constraints_3', 'primaryKey', null],
435
            '3: foreign key' => [
436
                'T_constraints_3',
437
                'foreignKeys',
438
                [
439
                    (new ForeignKeyConstraint())
440
                        ->name('CN_constraints_3')
441
                        ->columnNames(['C_fk_id_1', 'C_fk_id_2'])
442
                        ->foreignTableName('T_constraints_2')
443
                        ->foreignColumnNames(['C_id_1', 'C_id_2'])
444
                        ->onDelete('CASCADE')
445
                        ->onUpdate('CASCADE'),
446
                ],
447
            ],
448
            '3: unique' => ['T_constraints_3', 'uniques', []],
449
            '3: index' => [
450
                'T_constraints_3',
451
                'indexes',
452
                [
453
                    (new IndexConstraint())
454
                        ->name('CN_constraints_3')
455
                        ->columnNames(['C_fk_id_1', 'C_fk_id_2'])
456
                        ->unique(false)
457
                        ->primary(false),
458
                ],
459
            ],
460
            '3: check' => ['T_constraints_3', 'checks', []],
461
            '3: default' => ['T_constraints_3', 'defaultValues', false],
462
463
            '4: primary key' => [
464
                'T_constraints_4',
465
                'primaryKey',
466
                (new Constraint())
467
                    ->name(AnyValue::getInstance())
468
                    ->columnNames(['C_id']),
469
            ],
470
            '4: unique' => [
471
                'T_constraints_4',
472
                'uniques',
473
                [
474
                    (new Constraint())
475
                        ->name('CN_constraints_4')
476
                        ->columnNames(['C_col_1', 'C_col_2']),
477
                ],
478
            ],
479
            '4: check' => ['T_constraints_4', 'checks', []],
480
            '4: default' => ['T_constraints_4', 'defaultValues', false],
481
        ];
482
    }
483
484
    public function pdoAttributesProviderTrait(): array
485
    {
486
        return [
487
            [[PDO::ATTR_EMULATE_PREPARES => true]],
488
            [[PDO::ATTR_EMULATE_PREPARES => false]],
489
        ];
490
    }
491
492
    public function tableSchemaCachePrefixesProviderTrait(): array
493
    {
494
        $configs = [
495
            [
496
                'prefix' => '',
497
                'name' => 'type',
498
            ],
499
            [
500
                'prefix' => '',
501
                'name' => '{{%type}}',
502
            ],
503
            [
504
                'prefix' => 'ty',
505
                'name' => '{{%pe}}',
506
            ],
507
        ];
508
509
        $data = [];
510
        foreach ($configs as $config) {
511
            foreach ($configs as $testConfig) {
512
                if ($config === $testConfig) {
513
                    continue;
514
                }
515
516
                $description = sprintf(
517
                    "%s (with '%s' prefix) against %s (with '%s' prefix)",
518
                    $config['name'],
519
                    $config['prefix'],
520
                    $testConfig['name'],
521
                    $testConfig['prefix']
522
                );
523
                $data[$description] = [
524
                    $config['prefix'],
525
                    $config['name'],
526
                    $testConfig['prefix'],
527
                    $testConfig['name'],
528
                ];
529
            }
530
        }
531
532
        return $data;
533
    }
534
535
    public function lowercaseConstraintsProviderTrait(): array
536
    {
537
        return $this->constraintsProvider();
0 ignored issues
show
Bug introduced by
The method constraintsProvider() does not exist on Yiisoft\Db\TestUtility\TestSchemaTrait. Did you maybe mean constraintsProviderTrait()? ( Ignorable by Annotation )

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

537
        return $this->/** @scrutinizer ignore-call */ constraintsProvider();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
538
    }
539
540
    public function uppercaseConstraintsProviderTrait(): array
541
    {
542
        return $this->constraintsProvider();
543
    }
544
}
545