SQLServerHandler::eraseTable()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of Cycle ORM package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Database\Driver\SQLServer;
13
14
use Cycle\Database\Driver\Handler;
15
use Cycle\Database\Driver\SQLServer\Schema\SQLServerColumn;
16
use Cycle\Database\Driver\SQLServer\Schema\SQLServerTable;
17
use Cycle\Database\Exception\SchemaException;
18
use Cycle\Database\Schema\AbstractColumn;
0 ignored issues
show
Bug introduced by
The type Cycle\Database\Schema\AbstractColumn was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use Cycle\Database\Schema\AbstractIndex;
20
use Cycle\Database\Schema\AbstractTable;
21
22
class SQLServerHandler extends Handler
23
{
24
    /**
25
     * @psalm-param non-empty-string $table
26
     */
27
    public function getSchema(string $table, ?string $prefix = null): AbstractTable
28 486
    {
29
        return new SQLServerTable($this->driver, $table, $prefix ?? '');
0 ignored issues
show
Bug introduced by
It seems like $this->driver can also be of type null; however, parameter $driver of Cycle\Database\Driver\SQ...verTable::__construct() does only seem to accept Cycle\Database\Driver\DriverInterface, 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

29
        return new SQLServerTable(/** @scrutinizer ignore-type */ $this->driver, $table, $prefix ?? '');
Loading history...
30 486
    }
31
32
    public function getTableNames(string $prefix = ''): array
33 906
    {
34
        $query = "SELECT [table_name] FROM [information_schema].[tables] WHERE [table_type] = 'BASE TABLE'";
35 906
36
        $tables = [];
37 906
        foreach ($this->driver->query($query)->fetchAll(\PDO::FETCH_NUM) as $name) {
0 ignored issues
show
Bug introduced by
The method query() does not exist on null. ( Ignorable by Annotation )

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

37
        foreach ($this->driver->/** @scrutinizer ignore-call */ query($query)->fetchAll(\PDO::FETCH_NUM) as $name) {

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...
38 906
            if ($prefix !== '' && !\str_starts_with($name[0], $prefix)) {
39 454
                continue;
40 2
            }
41
42
            $tables[] = $name[0];
43 454
        }
44
45
        return $tables;
46 906
    }
47
48
    /**
49
     * @psalm-param non-empty-string $table
50
     */
51
    public function hasTable(string $table): bool
52 486
    {
53
        $query = "SELECT COUNT(*) FROM [information_schema].[tables]
54 486
            WHERE [table_type] = 'BASE TABLE' AND [table_name] = ?";
55
56
        return (bool) $this->driver->query($query, [$table])->fetchColumn();
57 486
    }
58
59
    public function eraseTable(AbstractTable $table): void
60 4
    {
61
        $this->driver->execute(
62 4
            "TRUNCATE TABLE {$this->driver->identifier($table->getFullName())}",
0 ignored issues
show
Bug introduced by
The method identifier() does not exist on Cycle\Database\Driver\DriverInterface. It seems like you code against a sub-type of Cycle\Database\Driver\DriverInterface such as Cycle\Database\Driver\Driver. ( Ignorable by Annotation )

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

62
            "TRUNCATE TABLE {$this->driver->/** @scrutinizer ignore-call */ identifier($table->getFullName())}",
Loading history...
63 4
        );
64
    }
65 2
66
    /**
67
     * @psalm-param non-empty-string $table
68
     * @psalm-param non-empty-string $name
69
     */
70
    public function renameTable(string $table, string $name): void
71 2
    {
72
        $this->run(
73 2
            'sp_rename @objname = ?, @newname = ?',
74 2
            [$table, $name],
75 2
        );
76
    }
77 2
78
    public function createColumn(AbstractTable $table, AbstractColumn $column): void
79 40
    {
80
        $this->run(
81 40
            "ALTER TABLE {$this->identify($table)} ADD {$column->sqlStatement($this->driver)}",
82 40
        );
83
    }
84 40
85
    /**
86
     * Driver specific column alter command.
87
     *
88
     * @throws SchemaException
89
     */
90
    public function alterColumn(
91 38
        AbstractTable $table,
92
        AbstractColumn $initial,
93
        AbstractColumn $column,
94
    ): void {
95
        if (!$initial instanceof SQLServerColumn || !$column instanceof SQLServerColumn) {
96 38
            throw new SchemaException('SQlServer handler can work only with SQLServer columns');
97
        }
98
99
        //In SQLServer we have to drop ALL related indexes and foreign keys while
100
        //applying type change... yeah...
101
102
        $indexesBackup = [];
103 38
        $foreignBackup = [];
104 38
        foreach ($table->getIndexes() as $index) {
105 38
            if (\in_array($column->getName(), $index->getColumns(), true)) {
106 6
                $indexesBackup[] = $index;
107 4
                $this->dropIndex($table, $index);
108 4
            }
109
        }
110
111
        foreach ($table->getForeignKeys() as $foreign) {
112 38
            if ($column->getName() === $foreign->getColumns()) {
113 2
                $foreignBackup[] = $foreign;
114
                $this->dropForeignKey($table, $foreign);
115
            }
116
        }
117
118
        //Column will recreate needed constraints
119
        foreach ($column->getConstraints() as $constraint) {
120 38
            $this->dropConstrain($table, $constraint);
121 18
        }
122
123
        //Rename is separate operation
124
        if ($column->getName() !== $initial->getName()) {
125 38
            $this->renameColumn($table, $initial, $column);
126 18
127
            //This call is required to correctly built set of alter operations
128
            $initial->setName($column->getName());
129 18
        }
130
131
        foreach ($column->alterOperations($this->driver, $initial) as $operation) {
0 ignored issues
show
Bug introduced by
It seems like $this->driver can also be of type null; however, parameter $driver of Cycle\Database\Driver\SQ...lumn::alterOperations() does only seem to accept Cycle\Database\Driver\DriverInterface, 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

131
        foreach ($column->alterOperations(/** @scrutinizer ignore-type */ $this->driver, $initial) as $operation) {
Loading history...
132 38
            $this->run("ALTER TABLE {$this->identify($table)} {$operation}");
133 26
        }
134
135
        //Restoring indexes and foreign keys
136
        foreach ($indexesBackup as $index) {
137 38
            $this->createIndex($table, $index);
138 4
        }
139
140
        foreach ($foreignBackup as $foreign) {
141 38
            $this->createForeignKey($table, $foreign);
142
        }
143
    }
144 38
145
    public function dropIndex(AbstractTable $table, AbstractIndex $index): void
146 16
    {
147
        $this->run("DROP INDEX {$this->identify($index)} ON {$this->identify($table)}");
148 16
    }
149 16
150
    public function enableForeignKeyConstraints(): void
151 18
    {
152
        foreach ($this->getTableNames() as $table) {
153
            $this->run("ALTER TABLE {$this->identify($table)} WITH CHECK CHECK CONSTRAINT ALL");
154
        }
155
    }
156 18
157 18
    public function disableForeignKeyConstraints(): void
158
    {
159 18
        foreach ($this->getTableNames() as $table) {
160 18
            $this->run("ALTER TABLE {$this->identify($table)} NOCHECK CONSTRAINT ALL");
161
        }
162
    }
163 18
164
    private function renameColumn(
165
        AbstractTable $table,
166
        AbstractColumn $initial,
167
        AbstractColumn $column,
168
    ): void {
169
        $this->run(
170
            "sp_rename ?, ?, 'COLUMN'",
171
            [
172
                $table->getFullName() . '.' . $initial->getName(),
173
                $column->getName(),
174
            ],
175
        );
176
    }
177
}
178