Completed
Push — 2.x ( c394f3...5e9c18 )
by Aleksei
18s queued 14s
created

Database::withoutCache()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 6
nop 0
dl 0
loc 17
ccs 0
cts 0
cp 0
crap 30
rs 9.6111
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;
13
14
use Cycle\Database\Driver\Driver;
15
use Cycle\Database\Driver\DriverInterface;
16
use Cycle\Database\Query\DeleteQuery;
17
use Cycle\Database\Query\InsertQuery;
18
use Cycle\Database\Query\SelectQuery;
19
use Cycle\Database\Query\UpdateQuery;
20
use Throwable;
21
22
/**
23
 * Database class is high level abstraction at top of Driver. Databases usually linked to real
24
 * database or logical portion of database (filtered by prefix).
25
 */
26
final class Database implements DatabaseInterface
27
{
28
    // Isolation levels for transactions
29
    public const ISOLATION_SERIALIZABLE = DriverInterface::ISOLATION_SERIALIZABLE;
30
    public const ISOLATION_REPEATABLE_READ = DriverInterface::ISOLATION_REPEATABLE_READ;
31
    public const ISOLATION_READ_COMMITTED = DriverInterface::ISOLATION_READ_COMMITTED;
32
    public const ISOLATION_READ_UNCOMMITTED = DriverInterface::ISOLATION_READ_UNCOMMITTED;
33
34
    /**
35
     * @psalm-param non-empty-string $name Internal database name/id.
36
     *
37
     * @param string $prefix Default database table prefix, will be used for all table identifiers.
38
     * @param DriverInterface $driver Driver instance responsible for database connection.
39
     * @param DriverInterface|null $readDriver Read-only driver connection.
40 3746
     */
41
    public function __construct(
42
        private string $name,
43
        private string $prefix,
44
        private DriverInterface $driver,
45
        private ?DriverInterface $readDriver = null
46 3746
    ) {
47
    }
48
49
    /**
50
     * Shortcut to get table abstraction.
51
     *
52
     * @psalm-param non-empty-string $name Table name without prefix.
53 138
     */
54
    public function __get(string $name): TableInterface
55 138
    {
56
        return $this->table($name);
57
    }
58
59
    /**
60
     * @psalm-return non-empty-string
61 14
     */
62
    public function getName(): string
63 14
    {
64
        return $this->name;
65
    }
66
67
    /**
68
     * @psalm-return non-empty-string
69 8
     */
70
    public function getType(): string
71 8
    {
72
        return $this->getDriver(self::WRITE)->getType();
73
    }
74 3738
75
    public function getDriver(int $type = DatabaseInterface::WRITE): DriverInterface
76 3738
    {
77
        return $type === self::READ && $this->readDriver !== null ? $this->readDriver : $this->driver;
78
    }
79 8
80
    public function withPrefix(string $prefix, bool $add = true): DatabaseInterface
81 8
    {
82
        $database = clone $this;
83 8
84
        $add ? $database->prefix .= $prefix : $database->prefix = $prefix;
85 8
86
        return $database;
87
    }
88 1974
89
    public function getPrefix(): string
90 1974
    {
91
        return $this->prefix;
92
    }
93
94
    /**
95
     * @psalm-param non-empty-string $name
96 10
     */
97
    public function hasTable(string $name): bool
98 10
    {
99
        return $this->getDriver()->getSchemaHandler()->hasTable($this->prefix . $name);
100
    }
101
102
    /**
103
     * @return Table[]
104 3636
     */
105
    public function getTables(): array
106 3636
    {
107
        $schemaHandler = $this->getDriver(self::READ)->getSchemaHandler();
108 3636
109 3636
        $result = [];
110 1826
        foreach ($schemaHandler->getTableNames($this->prefix) as $table) {
111 478
            $table = str_contains($table, '.')
112 1348
                ? str_replace('.' . $this->prefix, '.', $table)
113
                : substr($table, strlen($this->prefix));
114 1826
115
            $result[] = new Table($this, $table);
116
        }
117 3636
118
        return $result;
119
    }
120
121
    /**
122
     * @psalm-param non-empty-string $name
123 2042
     */
124
    public function table(string $name): Table
125 2042
    {
126
        return new Table($this, $name);
127
    }
128
129
    /**
130
     * @psalm-param non-empty-string $query
131 16
     */
132
    public function execute(string $query, array $parameters = []): int
133 16
    {
134 16
        return $this->getDriver(self::WRITE)
135
            ->execute($query, $parameters);
136
    }
137
138
    /**
139
     * @psalm-param non-empty-string $query
140 26
     */
141
    public function query(string $query, array $parameters = []): StatementInterface
142 26
    {
143 26
        return $this->getDriver(self::READ)
144
            ->query($query, $parameters);
145
    }
146 464
147
    public function insert(string $table = null): InsertQuery
148 464
    {
149 464
        return $this->getDriver(self::WRITE)
150 464
            ->getQueryBuilder()
151
            ->insertQuery($this->prefix, $table);
152
    }
153 128
154
    public function update(string $table = null, array $values = [], array $where = []): UpdateQuery
155 128
    {
156 128
        return $this->getDriver(self::WRITE)
157 128
            ->getQueryBuilder()
158
            ->updateQuery($this->prefix, $table, $where, $values);
159
    }
160 80
161
    public function delete(string $table = null, array $where = []): DeleteQuery
162 80
    {
163 80
        return $this->getDriver(self::WRITE)
164 80
            ->getQueryBuilder()
165
            ->deleteQuery($this->prefix, $table, $where);
166
    }
167 1888
168
    public function select(mixed $columns = '*'): SelectQuery
169 1888
    {
170 1888
        $arguments = \func_get_args();
171
        if (isset($arguments[0]) && \is_array($arguments[0])) {
172 20
            //Can be required in some cases while collecting data from Table->select(), stupid bug.
173
            $arguments = $arguments[0];
174
        }
175 1888
176 1888
        return $this->getDriver(self::READ)
177 1888
            ->getQueryBuilder()
178
            ->selectQuery($this->prefix, [], $arguments);
179
    }
180 48
181
    public function transaction(
182
        callable $callback,
183
        string $isolationLevel = null
184 48
    ): mixed {
185
        $this->begin($isolationLevel);
186
187 48
        try {
188 40
            $result = $callback($this);
189
            $this->commit();
190 40
191 8
            return $result;
192 8
        } catch (Throwable $e) {
193 8
            $this->rollback();
194
            throw $e;
195
        }
196
    }
197 106
198
    public function begin(string $isolationLevel = null): bool
199 106
    {
200
        return $this->getDriver(self::WRITE)->beginTransaction($isolationLevel);
201
    }
202 80
203
    public function commit(): bool
204 80
    {
205
        return $this->getDriver(self::WRITE)->commitTransaction();
206
    }
207 40
208
    public function rollback(): bool
209 40
    {
210
        return $this->getDriver(self::WRITE)->rollbackTransaction();
211
    }
212
213
    public function withoutCache(): self
214
    {
215
        $database = clone $this;
216
217
        if ($this->readDriver instanceof Driver && $database->readDriver !== $database->driver) {
218
            $database->readDriver = $database->readDriver->withoutCache();
0 ignored issues
show
Bug introduced by
The method withoutCache() 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

218
            /** @scrutinizer ignore-call */ 
219
            $database->readDriver = $database->readDriver->withoutCache();

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...
Bug introduced by
The method withoutCache() 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

218
            /** @scrutinizer ignore-call */ 
219
            $database->readDriver = $database->readDriver->withoutCache();
Loading history...
219
        }
220
221
        if ($this->driver instanceof Driver) {
222
            $database->driver = $database->readDriver === $database->driver
223
                ? ($database->readDriver = $database->driver->withoutCache())
224
                : $database->driver->withoutCache();
225
226
            return $database;
227
        }
228
229
        return $this;
230
    }
231
}
232