Passed
Pull Request — master (#370)
by Wilmer
25:50 queued 23:21
created

TestTrait::createQueryCache()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\TestSupport;
6
7
use Psr\Log\LoggerInterface;
8
use ReflectionClass;
9
use ReflectionException;
10
use ReflectionObject;
11
use Yiisoft\Cache\ArrayCache;
12
use Yiisoft\Cache\Cache;
13
use Yiisoft\Cache\CacheInterface;
14
use Yiisoft\Db\Cache\QueryCache;
15
use Yiisoft\Db\Cache\SchemaCache;
16
use Yiisoft\Db\Driver\PDO\ConnectionPDOInterface;
17
use Yiisoft\Log\Logger;
18
use Yiisoft\Profiler\Profiler;
19
use Yiisoft\Profiler\ProfilerInterface;
20
21
trait TestTrait
22
{
23
    protected ?CacheInterface $cache = null;
24
    /** @psalm-var Logger|null  */
25
    protected ?LoggerInterface $logger = null;
26
    protected ?ProfilerInterface $profiler = null;
27
    protected ?QueryCache $queryCache = null;
28
    protected ?SchemaCache $schemaCache = null;
29
30
    /**
31
     * Asserts that value is one of expected values.
32
     */
33
    protected function assertIsOneOf(mixed $actual, array $expected, string $message = ''): void
34
    {
35
        self::assertThat($actual, new IsOneOfAssert($expected), $message);
36
    }
37
38
    protected function createCache(): CacheInterface
39
    {
40
        if ($this->cache === null) {
41
            $this->cache = new Cache(new ArrayCache());
42
        }
43
        return $this->cache;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->cache could return the type null which is incompatible with the type-hinted return Yiisoft\Cache\CacheInterface. Consider adding an additional type-check to rule them out.
Loading history...
44
    }
45
46
    protected function createLogger(): LoggerInterface
47
    {
48
        if ($this->logger === null) {
49
            $this->logger = new Logger();
50
        }
51
        return $this->logger;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->logger could return the type null which is incompatible with the type-hinted return Psr\Log\LoggerInterface. Consider adding an additional type-check to rule them out.
Loading history...
52
    }
53
54
    protected function createProfiler(): ProfilerInterface
55
    {
56
        if ($this->profiler === null) {
57
            $this->profiler = new Profiler($this->createLogger());
58
        }
59
        return $this->profiler;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->profiler could return the type null which is incompatible with the type-hinted return Yiisoft\Profiler\ProfilerInterface. Consider adding an additional type-check to rule them out.
Loading history...
60
    }
61
62
    protected function createQueryCache(): QueryCache
63
    {
64
        if ($this->queryCache === null) {
65
            $this->queryCache = new QueryCache($this->createCache());
66
        }
67
        return $this->queryCache;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->queryCache could return the type null which is incompatible with the type-hinted return Yiisoft\Db\Cache\QueryCache. Consider adding an additional type-check to rule them out.
Loading history...
68
    }
69
70
    protected function createSchemaCache(): SchemaCache
71
    {
72
        if ($this->schemaCache === null) {
73
            $this->schemaCache = new SchemaCache($this->createCache());
74
        }
75
        return $this->schemaCache;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->schemaCache could return the type null which is incompatible with the type-hinted return Yiisoft\Db\Cache\SchemaCache. Consider adding an additional type-check to rule them out.
Loading history...
76
    }
77
78
    /**
79
     * Gets an inaccessible object property.
80
     *
81
     * @param bool $revoke whether to make property inaccessible after getting.
82
     */
83
    protected function getInaccessibleProperty(object $object, string $propertyName, bool $revoke = true): mixed
84
    {
85
        $class = new ReflectionClass($object);
86
87
        while (!$class->hasProperty($propertyName)) {
88
            $class = $class->getParentClass();
89
        }
90
91
        $property = $class->getProperty($propertyName);
92
93
        $property->setAccessible(true);
94
95
        $result = $property->getValue($object);
96
97
        if ($revoke) {
98
            $property->setAccessible(false);
99
        }
100
101
        return $result;
102
    }
103
104
    /**
105
     * Invokes an inaccessible method.
106
     *
107
     * @param bool $revoke whether to make method inaccessible after execution.
108
     *
109
     * @throws ReflectionException
110
     */
111
    protected function invokeMethod(object $object, string $method, array $args = [], bool $revoke = true): mixed
112
    {
113
        $reflection = new ReflectionObject($object);
114
115
        $method = $reflection->getMethod($method);
116
117
        $method->setAccessible(true);
118
119
        $result = $method->invokeArgs($object, $args);
120
121
        if ($revoke) {
122
            $method->setAccessible(false);
123
        }
124
        return $result;
125
    }
126
127
    protected function prepareDatabase(ConnectionPDOInterface $db, string $fixture): void
128
    {
129
        $db->open();
130
131
        if ($this->drivername === 'oci') {
132
            [$drops, $creates] = explode('/* STATEMENTS */', file_get_contents($fixture), 2);
133
            [$statements, $triggers, $data] = explode('/* TRIGGERS */', $creates, 3);
134
            $lines = array_merge(
135
                explode('--', $drops),
136
                explode(';', $statements),
137
                explode('/', $triggers),
138
                explode(';', $data)
139
            );
140
        } else {
141
            $lines = explode(';', file_get_contents($fixture));
142
        }
143
144
        foreach ($lines as $line) {
145
            if (trim($line) !== '') {
146
                $db->getPDO()?->exec($line);
147
            }
148
        }
149
    }
150
151
    /**
152
     * Adjust dbms specific escaping.
153
     */
154
    protected function replaceQuotes($sql): string|array|null
155
    {
156
        return match ($this->drivername) {
157
            'mysql', 'sqlite' => str_replace(['[[', ']]'], '`', $sql),
158
            'oci' => str_replace(['[[', ']]'], '"', $sql),
159
            'pgsql' => str_replace(['\\[', '\\]'], ['[', ']'], preg_replace('/(\[\[)|((?<!(\[))]])/', '"', $sql)),
160
            'sqlsrv' => str_replace(['[[', ']]'], ['[', ']'], $sql),
161
            default => $sql,
162
        };
163
    }
164
165
    /**
166
     * Sets an inaccessible object property to a designated value.
167
     *
168
     * @param $value
169
     * @param bool $revoke whether to make property inaccessible after setting
170
     */
171
    protected function setInaccessibleProperty(object $object, string $propertyName, $value, bool $revoke = true): void
172
    {
173
        $class = new ReflectionClass($object);
174
175
        while (!$class->hasProperty($propertyName)) {
176
            $class = $class->getParentClass();
177
        }
178
179
        $property = $class->getProperty($propertyName);
180
181
        $property->setAccessible(true);
182
183
        $property->setValue($object, $value);
184
185
        if ($revoke) {
186
            $property->setAccessible(false);
187
        }
188
    }
189
}
190