Passed
Pull Request — master (#83)
by Wilmer
24:07 queued 09:08
created

ActiveRecordTest::testArrayValues()   B

Complexity

Conditions 8
Paths 52

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 39
rs 8.4444
c 0
b 0
f 0
cc 8
nc 52
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\ActiveRecord\Tests\Pgsql;
6
7
use Yiisoft\ActiveRecord\BaseActiveRecord;
8
use Yiisoft\ActiveRecord\Tests\ActiveRecordTest as BaseActiveRecordTest;
9
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\ArrayAndJsonTypes;
10
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\BoolAR;
11
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Customer;
12
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\DefaultPk;
13
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\UserAR;
14
use Yiisoft\Db\Expression\ArrayExpression;
15
use Yiisoft\Db\Expression\Expression;
16
use Yiisoft\Db\Expression\JsonExpression;
17
use Yiisoft\Db\Pgsql\Schema\Schema;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Pgsql\Schema\Schema 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...
18
19
/**
20
 * @group pgsql
21
 */
22
final class ActiveRecordTest extends BaseActiveRecordTest
23
{
24
    public ?string $driverName = 'pgsql';
25
26
    public function setUp(): void
27
    {
28
        parent::setUp();
29
30
        BaseActiveRecord::connectionId($this->driverName);
0 ignored issues
show
Bug introduced by
It seems like $this->driverName can also be of type null; however, parameter $value of Yiisoft\ActiveRecord\Bas...eRecord::connectionId() does only seem to accept 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

30
        BaseActiveRecord::connectionId(/** @scrutinizer ignore-type */ $this->driverName);
Loading history...
31
    }
32
33
    protected function tearDown(): void
34
    {
35
        parent::tearDown();
36
37
        $this->pgsqlConnection->close();
0 ignored issues
show
Bug introduced by
The method close() 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
        $this->pgsqlConnection->/** @scrutinizer ignore-call */ 
38
                                close();

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
39
        unset($this->pgsqlConnection);
40
    }
41
42
    public function testBooleanAttribute(): void
43
    {
44
        $this->loadFixture(Customer::getConnection());
45
46
        /** @var $this TestCase|ActiveRecordTestTrait */
47
        $customer = new Customer();
48
        $customer->name = 'boolean customer';
49
        $customer->email = '[email protected]';
50
        $customer->bool_status = false;
0 ignored issues
show
Bug Best Practice introduced by
The property bool_status does not exist on Yiisoft\ActiveRecord\Tes...s\ActiveRecord\Customer. Since you implemented __set, consider adding a @property annotation.
Loading history...
51
52
        $customer->save();
53
        $customer->refresh();
54
        $this->assertFalse($customer->bool_status);
0 ignored issues
show
Bug Best Practice introduced by
The property bool_status does not exist on Yiisoft\ActiveRecord\Tes...s\ActiveRecord\Customer. Since you implemented __get, consider adding a @property annotation.
Loading history...
55
56
        $customer->bool_status = true;
57
58
        $customer->save();
59
        $customer->refresh();
60
        $this->assertTrue($customer->bool_status);
61
62
        $customers = Customer::find()->where(['bool_status' => true])->all();
63
        $this->assertCount(3, $customers);
64
65
        $customers = Customer::find()->where(['bool_status' => false])->all();
66
        $this->assertCount(1, $customers);
67
    }
68
69
    public function testFindAsArray(): void
70
    {
71
        $this->loadFixture(Customer::getConnection());
72
73
        /** asArray */
74
        $customer = Customer::find()->where(['id' => 2])->asArray()->one();
75
        $this->assertEquals([
76
            'id' => 2,
77
            'email' => '[email protected]',
78
            'name' => 'user2',
79
            'address' => 'address2',
80
            'status' => 1,
81
            'bool_status' => true,
82
            'profile_id' => null,
83
        ], $customer);
84
85
        /** find all asArray */
86
        $customers = Customer::find()->asArray()->all();
87
        $this->assertCount(3, $customers);
88
        $this->assertArrayHasKey('id', $customers[0]);
89
        $this->assertArrayHasKey('name', $customers[0]);
90
        $this->assertArrayHasKey('email', $customers[0]);
91
        $this->assertArrayHasKey('address', $customers[0]);
92
        $this->assertArrayHasKey('status', $customers[0]);
93
        $this->assertArrayHasKey('bool_status', $customers[0]);
94
        $this->assertArrayHasKey('id', $customers[1]);
95
        $this->assertArrayHasKey('name', $customers[1]);
96
        $this->assertArrayHasKey('email', $customers[1]);
97
        $this->assertArrayHasKey('address', $customers[1]);
98
        $this->assertArrayHasKey('status', $customers[1]);
99
        $this->assertArrayHasKey('bool_status', $customers[1]);
100
        $this->assertArrayHasKey('id', $customers[2]);
101
        $this->assertArrayHasKey('name', $customers[2]);
102
        $this->assertArrayHasKey('email', $customers[2]);
103
        $this->assertArrayHasKey('address', $customers[2]);
104
        $this->assertArrayHasKey('status', $customers[2]);
105
        $this->assertArrayHasKey('bool_status', $customers[2]);
106
    }
107
108
    public function testBooleanValues(): void
109
    {
110
        $db = BoolAR::getConnection();
111
        $command = $db->createCommand();
112
        $command->batchInsert('bool_values', ['bool_col'], [[true], [false]])->execute();
113
114
        $this->assertEquals(1, BoolAR::find()->where('bool_col = TRUE')->count('*', $db));
0 ignored issues
show
Unused Code introduced by
The call to Yiisoft\Db\Query\Query::count() has too many arguments starting with $db. ( Ignorable by Annotation )

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

114
        $this->assertEquals(1, BoolAR::find()->where('bool_col = TRUE')->/** @scrutinizer ignore-call */ count('*', $db));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
115
        $this->assertEquals(1, BoolAR::find()->where('bool_col = FALSE')->count('*', $db));
116
        $this->assertEquals(2, BoolAR::find()->where('bool_col IN (TRUE, FALSE)')->count('*', $db));
117
118
        $this->assertEquals(1, BoolAR::find()->where(['bool_col' => true])->count('*', $db));
119
        $this->assertEquals(1, BoolAR::find()->where(['bool_col' => false])->count('*', $db));
120
        $this->assertEquals(2, BoolAR::find()->where(['bool_col' => [true, false]])->count('*', $db));
121
122
        $this->assertEquals(1, BoolAR::find()->where('bool_col = :bool_col', ['bool_col' => true])->count('*', $db));
123
        $this->assertEquals(1, BoolAR::find()->where('bool_col = :bool_col', ['bool_col' => false])->count('*', $db));
124
125
        $this->assertTrue(BoolAR::find()->where(['bool_col' => true])->one($db)->bool_col);
0 ignored issues
show
Unused Code introduced by
The call to Yiisoft\ActiveRecord\ActiveQuery::one() has too many arguments starting with $db. ( Ignorable by Annotation )

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

125
        $this->assertTrue(BoolAR::find()->where(['bool_col' => true])->/** @scrutinizer ignore-call */ one($db)->bool_col);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
126
        $this->assertFalse(BoolAR::find()->where(['bool_col' => false])->one($db)->bool_col);
127
    }
128
129
    /**
130
     * {@see https://github.com/yiisoft/yii2/issues/4672}
131
     */
132
    public function testBooleanValues2(): void
133
    {
134
        $db = UserAR::getConnection();
135
136
        $db->setCharset('utf8');
137
        $db->createCommand('DROP TABLE IF EXISTS bool_user;')->execute();
138
        $db->createCommand()->createTable('bool_user', [
139
            'id' => Schema::TYPE_PK,
140
            'username' => Schema::TYPE_STRING . ' NOT NULL',
141
            'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL',
142
            'password_hash' => Schema::TYPE_STRING . ' NOT NULL',
143
            'password_reset_token' => Schema::TYPE_STRING,
144
            'email' => Schema::TYPE_STRING . ' NOT NULL',
145
            'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
146
            'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
147
            'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
148
            'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
149
        ])->execute();
150
        $db->createCommand()->addColumn('bool_user', 'is_deleted', Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT FALSE')
151
            ->execute();
152
153
        $user = new UserAR();
154
        $user->username = 'test';
0 ignored issues
show
Bug Best Practice introduced by
The property username does not exist on Yiisoft\ActiveRecord\Tes...ubs\ActiveRecord\UserAR. Since you implemented __set, consider adding a @property annotation.
Loading history...
155
        $user->auth_key = 'test';
0 ignored issues
show
Bug Best Practice introduced by
The property auth_key does not exist on Yiisoft\ActiveRecord\Tes...ubs\ActiveRecord\UserAR. Since you implemented __set, consider adding a @property annotation.
Loading history...
156
        $user->password_hash = 'test';
0 ignored issues
show
Bug Best Practice introduced by
The property password_hash does not exist on Yiisoft\ActiveRecord\Tes...ubs\ActiveRecord\UserAR. Since you implemented __set, consider adding a @property annotation.
Loading history...
157
        $user->email = '[email protected]';
0 ignored issues
show
Bug Best Practice introduced by
The property email does not exist on Yiisoft\ActiveRecord\Tes...ubs\ActiveRecord\UserAR. Since you implemented __set, consider adding a @property annotation.
Loading history...
158
        $user->created_at = time();
0 ignored issues
show
Bug Best Practice introduced by
The property created_at does not exist on Yiisoft\ActiveRecord\Tes...ubs\ActiveRecord\UserAR. Since you implemented __set, consider adding a @property annotation.
Loading history...
159
        $user->updated_at = time();
0 ignored issues
show
Bug Best Practice introduced by
The property updated_at does not exist on Yiisoft\ActiveRecord\Tes...ubs\ActiveRecord\UserAR. Since you implemented __set, consider adding a @property annotation.
Loading history...
160
161
        $user->save();
162
163
        $this->assertCount(1, UserAR::find()->where(['is_deleted' => false])->all($db));
0 ignored issues
show
Unused Code introduced by
The call to Yiisoft\ActiveRecord\ActiveQuery::all() has too many arguments starting with $db. ( Ignorable by Annotation )

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

163
        $this->assertCount(1, UserAR::find()->where(['is_deleted' => false])->/** @scrutinizer ignore-call */ all($db));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
164
        $this->assertCount(0, UserAR::find()->where(['is_deleted' => true])->all($db));
165
        $this->assertCount(1, UserAR::find()->where(['is_deleted' => [true, false]])->all($db));
166
    }
167
168
    public function testBooleanDefaultValues(): void
169
    {
170
        $model = new BoolAR();
171
        $this->assertNull($model->bool_col);
0 ignored issues
show
Bug Best Practice introduced by
The property bool_col does not exist on Yiisoft\ActiveRecord\Tes...ubs\ActiveRecord\BoolAR. Since you implemented __get, consider adding a @property annotation.
Loading history...
172
        $this->assertNull($model->default_true);
0 ignored issues
show
Bug Best Practice introduced by
The property default_true does not exist on Yiisoft\ActiveRecord\Tes...ubs\ActiveRecord\BoolAR. Since you implemented __get, consider adding a @property annotation.
Loading history...
173
        $this->assertNull($model->default_false);
0 ignored issues
show
Bug Best Practice introduced by
The property default_false does not exist on Yiisoft\ActiveRecord\Tes...ubs\ActiveRecord\BoolAR. Since you implemented __get, consider adding a @property annotation.
Loading history...
174
175
        $model->loadDefaultValues();
176
        $this->assertNull($model->bool_col);
177
        $this->assertTrue($model->default_true);
178
        $this->assertFalse($model->default_false);
179
        $this->assertTrue($model->save());
180
    }
181
182
    public function testPrimaryKeyAfterSave(): void
183
    {
184
        $record = new DefaultPk();
185
186
        $record->type = 'type';
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist on Yiisoft\ActiveRecord\Tes...\ActiveRecord\DefaultPk. Since you implemented __set, consider adding a @property annotation.
Loading history...
187
        $record->save();
188
        $this->assertEquals(5, $record->primaryKey);
189
    }
190
191
    /**
192
     * @dataProvider arrayValuesProvider $attributes
193
     */
194
    public function testArrayValues($attributes): void
195
    {
196
        $this->loadFixture(ArrayAndJsonTypes::getConnection());
197
198
        $type = new ArrayAndJsonTypes();
199
200
        foreach ($attributes as $attribute => $expected) {
201
            $type->$attribute = $expected[0];
202
        }
203
204
        $type->save();
205
206
        $type = ArrayAndJsonTypes::find()->one();
207
208
        foreach ($attributes as $attribute => $expected) {
209
            $expected = isset($expected[1]) ? $expected[1] : $expected[0];
210
            $value = $type->$attribute;
211
212
            if ($expected instanceof ArrayExpression) {
213
                $expected = $expected->getValue();
214
            }
215
216
            $this->assertEquals($expected, $value, 'In column ' . $attribute);
217
218
            if ($value instanceof ArrayExpression) {
219
                $this->assertInstanceOf('\ArrayAccess', $value);
220
                $this->assertInstanceOf('\Traversable', $value);
221
                foreach ($type->$attribute as $key => $v) { // testing arrayaccess
222
                    $this->assertSame($expected[$key], $value[$key]);
223
                }
224
            }
225
        }
226
227
        /** Testing UPDATE */
228
        foreach ($attributes as $attribute => $expected) {
229
            $type->markAttributeDirty($attribute);
230
        }
231
232
        $this->assertSame(1, $type->update(), 'The record got updated');
233
    }
234
235
    public function arrayValuesProvider(): array
236
    {
237
        return [
238
            'simple arrays values' => [[
239
                'intarray_col' => [
240
                    new ArrayExpression([1,-2,null,'42'], 'int4', 1),
241
                    new ArrayExpression([1,-2,null,42], 'int4', 1),
242
                ],
243
                'textarray2_col' => [
244
                    new ArrayExpression([['text'], [null], [1]], 'text', 2),
245
                    new ArrayExpression([['text'], [null], ['1']], 'text', 2),
246
                ],
247
                'json_col' => [['a' => 1, 'b' => null, 'c' => [1,3,5]]],
248
                'jsonb_col' => [[null, 'a', 'b', '\"', '{"af"}']],
249
                'jsonarray_col' => [new ArrayExpression([[',', 'null', true, 'false', 'f']], 'json')],
250
            ]],
251
            'null arrays values' => [[
252
                'intarray_col' => [
253
                    null,
254
                ],
255
                'textarray2_col' => [
256
                    [null, null],
257
                    new ArrayExpression([null, null], 'text', 2),
258
                ],
259
                'json_col' => [
260
                    null
261
                ],
262
                'jsonarray_col' => [
263
                    null
264
                ],
265
            ]],
266
            'empty arrays values' => [[
267
                'textarray2_col' => [
268
                    [[], []],
269
                    new ArrayExpression([], 'text', 2),
270
                ],
271
            ]],
272
            'nested objects' => [[
273
                'intarray_col' => [
274
                    new ArrayExpression(new ArrayExpression([1,2,3]), 'int', 1),
275
                    new ArrayExpression([1,2,3], 'int4', 1),
276
                ],
277
                'textarray2_col' => [
278
                    new ArrayExpression([new ArrayExpression(['text']), [null], [1]], 'text', 2),
279
                    new ArrayExpression([['text'], [null], ['1']], 'text', 2),
280
                ],
281
                'json_col' => [
282
                    new JsonExpression(new JsonExpression(new JsonExpression(['a' => 1, 'b' => null, 'c' => new JsonExpression([1,3,5])]))),
283
                    ['a' => 1, 'b' => null, 'c' => [1,3,5]]
284
                ],
285
                'jsonb_col' => [
286
                    new JsonExpression(new ArrayExpression([1,2,3])),
287
                    [1,2,3]
288
                ],
289
                'jsonarray_col' => [
290
                    new ArrayExpression([new JsonExpression(['1', 2]), [3,4,5]], 'json'),
291
                    new ArrayExpression([['1', 2], [3,4,5]], 'json')
292
                ]
293
            ]],
294
            'arrays packed in classes' => [[
295
                'intarray_col' => [
296
                    new ArrayExpression([1,-2,null,'42'], 'int', 1),
297
                    new ArrayExpression([1,-2,null,42], 'int4', 1),
298
                ],
299
                'textarray2_col' => [
300
                    new ArrayExpression([['text'], [null], [1]], 'text', 2),
301
                    new ArrayExpression([['text'], [null], ['1']], 'text', 2),
302
                ],
303
                'json_col' => [
304
                    new JsonExpression(['a' => 1, 'b' => null, 'c' => [1,3,5]]),
305
                    ['a' => 1, 'b' => null, 'c' => [1,3,5]]
306
                ],
307
                'jsonb_col' => [
308
                    new JsonExpression([null, 'a', 'b', '\"', '{"af"}']),
309
                    [null, 'a', 'b', '\"', '{"af"}']
310
                ],
311
                'jsonarray_col' => [
312
                    new Expression("array['[\",\",\"null\",true,\"false\",\"f\"]'::json]::json[]"),
313
                    new ArrayExpression([[',', 'null', true, 'false', 'f']], 'json'),
314
                ]
315
            ]],
316
            'scalars' => [[
317
                'json_col' => [
318
                    '5.8',
319
                ],
320
                'jsonb_col' => [
321
                    pi()
322
                ],
323
            ]],
324
        ];
325
    }
326
}
327