Passed
Push — master ( 914087...c6011d )
by Alexander
11:22
created

TestTrait::createProfiler()   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
     * Asserting two strings equality ignoring line endings.
32
     *
33
     * @param string $expected
34
     * @param string $actual
35
     * @param string $message
36
     */
37
    protected function assertEqualsWithoutLE(string $expected, string $actual, string $message = ''): void
38
    {
39
        $expected = str_replace("\r\n", "\n", $expected);
40
        $actual = str_replace("\r\n", "\n", $actual);
41
42
        $this->assertEquals($expected, $actual, $message);
0 ignored issues
show
Bug introduced by
The method assertEquals() does not exist on Yiisoft\Db\TestSupport\TestTrait. Did you maybe mean assertEqualsWithoutLE()? ( Ignorable by Annotation )

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

42
        $this->/** @scrutinizer ignore-call */ 
43
               assertEquals($expected, $actual, $message);

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...
43
    }
44
45
    /**
46
     * Asserts that value is one of expected values.
47
     *
48
     * @param mixed $actual
49
     * @param array $expected
50
     * @param string $message
51
     */
52
    protected function assertIsOneOf(mixed $actual, array $expected, string $message = ''): void
53
    {
54
        self::assertThat($actual, new IsOneOfAssert($expected), $message);
55
    }
56
57
    protected function createCache(): CacheInterface
58
    {
59
        if ($this->cache === null) {
60
            $this->cache = new Cache(new ArrayCache());
61
        }
62
        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...
63
    }
64
65
    protected function createLogger(): LoggerInterface
66
    {
67
        if ($this->logger === null) {
68
            $this->logger = new Logger();
69
        }
70
        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...
71
    }
72
73
    protected function createProfiler(): ProfilerInterface
74
    {
75
        if ($this->profiler === null) {
76
            $this->profiler = new Profiler($this->createLogger());
77
        }
78
        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...
79
    }
80
81
    protected function createQueryCache(): QueryCache
82
    {
83
        if ($this->queryCache === null) {
84
            $this->queryCache = new QueryCache($this->createCache());
85
        }
86
        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...
87
    }
88
89
    protected function createSchemaCache(): SchemaCache
90
    {
91
        if ($this->schemaCache === null) {
92
            $this->schemaCache = new SchemaCache($this->createCache());
93
        }
94
        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...
95
    }
96
97
    /**
98
     * Gets an inaccessible object property.
99
     *
100
     * @param object $object
101
     * @param string $propertyName
102
     * @param bool $revoke whether to make property inaccessible after getting.
103
     *
104
     * @return mixed
105
     */
106
    protected function getInaccessibleProperty(object $object, string $propertyName, bool $revoke = true): mixed
107
    {
108
        $class = new ReflectionClass($object);
109
110
        while (!$class->hasProperty($propertyName)) {
111
            $class = $class->getParentClass();
112
        }
113
114
        $property = $class->getProperty($propertyName);
115
116
        $property->setAccessible(true);
117
118
        $result = $property->getValue($object);
119
120
        if ($revoke) {
121
            $property->setAccessible(false);
122
        }
123
124
        return $result;
125
    }
126
127
    /**
128
     * Invokes an inaccessible method.
129
     *
130
     * @param object $object
131
     * @param string $method
132
     * @param array $args
133
     * @param bool $revoke whether to make method inaccessible after execution.
134
     *
135
     * @throws ReflectionException
136
     *
137
     * @return mixed
138
     */
139
    protected function invokeMethod(object $object, string $method, array $args = [], bool $revoke = true): mixed
140
    {
141
        $reflection = new ReflectionObject($object);
142
143
        $method = $reflection->getMethod($method);
144
145
        $method->setAccessible(true);
146
147
        $result = $method->invokeArgs($object, $args);
148
149
        if ($revoke) {
150
            $method->setAccessible(false);
151
        }
152
        return $result;
153
    }
154
155
    protected function prepareDatabase(ConnectionPDOInterface $db, string $fixture): void
156
    {
157
        $db->open();
158
159
        if ($this->drivername === 'oci') {
160
            [$drops, $creates] = explode('/* STATEMENTS */', file_get_contents($fixture), 2);
161
            [$statements, $triggers, $data] = explode('/* TRIGGERS */', $creates, 3);
162
            $lines = array_merge(
163
                explode('--', $drops),
164
                explode(';', $statements),
165
                explode('/', $triggers),
166
                explode(';', $data)
167
            );
168
        } else {
169
            $lines = explode(';', file_get_contents($fixture));
170
        }
171
172
        foreach ($lines as $line) {
173
            if (trim($line) !== '') {
174
                $db->getPDO()?->exec($line);
175
            }
176
        }
177
    }
178
179
    /**
180
     * Adjust dbms specific escaping.
181
     *
182
     * @param $sql
183
     *
184
     * @return array|string|null
185
     */
186
    protected function replaceQuotes($sql): string|array|null
187
    {
188
        return match ($this->drivername) {
189
            'mysql', 'sqlite' => str_replace(['[[', ']]'], '`', $sql),
190
            'oci' => str_replace(['[[', ']]'], '"', $sql),
191
            'pgsql' => str_replace(['\\[', '\\]'], ['[', ']'], preg_replace('/(\[\[)|((?<!(\[))]])/', '"', $sql)),
192
            'sqlsrv' => str_replace(['[[', ']]'], ['[', ']'], $sql),
193
            default => $sql,
194
        };
195
    }
196
197
    /**
198
     * Sets an inaccessible object property to a designated value.
199
     *
200
     * @param object $object
201
     * @param string $propertyName
202
     * @param $value
203
     * @param bool $revoke whether to make property inaccessible after setting
204
     */
205
    protected function setInaccessibleProperty(object $object, string $propertyName, $value, bool $revoke = true): void
206
    {
207
        $class = new ReflectionClass($object);
208
209
        while (!$class->hasProperty($propertyName)) {
210
            $class = $class->getParentClass();
211
        }
212
213
        $property = $class->getProperty($propertyName);
214
215
        $property->setAccessible(true);
216
217
        $property->setValue($object, $value);
218
219
        if ($revoke) {
220
            $property->setAccessible(false);
221
        }
222
    }
223
}
224