Passed
Pull Request — master (#273)
by
unknown
02:59
created

ActiveRecordTest::testToArrayForArrayable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 50
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 3
Metric Value
eloc 35
c 3
b 0
f 3
dl 0
loc 50
rs 9.36
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\ActiveRecord\Tests\Driver\Pgsql;
6
7
use ArrayAccess;
8
use Traversable;
9
use Yiisoft\ActiveRecord\ActiveQuery;
10
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\ArrayAndJsonTypes;
11
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Beta;
12
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\BoolAR;
13
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Customer;
14
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerClosureField;
15
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerForArrayable;
16
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\DefaultPk;
17
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\UserAR;
18
use Yiisoft\ActiveRecord\Tests\Support\PgsqlHelper;
19
use Yiisoft\Db\Expression\ArrayExpression;
20
use Yiisoft\Db\Expression\Expression;
21
use Yiisoft\Db\Expression\JsonExpression;
22
use Yiisoft\Db\Pgsql\Schema as SchemaPgsql;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Pgsql\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...
23
24
final class ActiveRecordTest extends \Yiisoft\ActiveRecord\Tests\ActiveRecordTest
0 ignored issues
show
Bug introduced by
The type Yiisoft\ActiveRecord\Tests\ActiveRecordTest 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...
25
{
26
    public function setUp(): void
27
    {
28
        parent::setUp();
29
30
        $pgsqlHelper = new PgsqlHelper();
31
        $this->db = $pgsqlHelper->createConnection();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
32
    }
33
34
    protected function tearDown(): void
35
    {
36
        parent::tearDown();
37
38
        $this->db->close();
39
40
        unset($this->db);
41
    }
42
43
    public function testExplicitPkOnAutoIncrement(): void
44
    {
45
        $this->checkFixture($this->db, 'customer');
46
47
        $customer = new Customer($this->db);
48
        $customer->id = 1337;
49
        $customer->email = '[email protected]';
50
        $customer->name = 'user1337';
51
        $customer->address = 'address1337';
52
        $this->assertTrue($customer->isNewRecord);
0 ignored issues
show
Bug Best Practice introduced by
The property isNewRecord does not exist on Yiisoft\ActiveRecord\Tes...s\ActiveRecord\Customer. Since you implemented __get, consider adding a @property annotation.
Loading history...
53
54
        $customer->save();
55
        $this->assertEquals(1337, $customer->id);
56
        $this->assertFalse($customer->isNewRecord);
57
    }
58
59
    /**
60
     * {@see https://github.com/yiisoft/yii2/issues/15482}
61
     */
62
    public function testEagerLoadingUsingStringIdentifiers(): void
63
    {
64
        $this->checkFixture($this->db, 'beta');
65
66
        $betaQuery = new ActiveQuery(Beta::class, $this->db);
67
        $betas = $betaQuery->with('alpha')->all();
68
        $this->assertNotEmpty($betas);
69
70
        $alphaIdentifiers = [];
71
72
        /** @var Beta[] $betas */
73
        foreach ($betas as $beta) {
74
            $this->assertNotNull($beta->alpha);
75
            $this->assertEquals($beta->alpha_string_identifier, $beta->alpha->string_identifier);
76
            $alphaIdentifiers[] = $beta->alpha->string_identifier;
77
        }
78
79
        $this->assertEquals(['1', '01', '001', '001', '2', '2b', '2b', '02'], $alphaIdentifiers);
80
    }
81
82
    public function testBooleanAttribute(): void
83
    {
84
        $this->checkFixture($this->db, 'customer', true);
85
86
        $customer = new Customer($this->db);
87
        $customer->name = 'boolean customer';
88
        $customer->email = '[email protected]';
89
        $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...
90
        $customer->save();
91
92
        $customer->refresh();
93
        $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...
94
95
        $customer->bool_status = true;
96
97
        $customer->save();
98
        $customer->refresh();
99
        $this->assertTrue($customer->bool_status);
100
101
        $customerQuery = new ActiveQuery(Customer::class, $this->db);
102
        $customers = $customerQuery->where(['bool_status' => true])->all();
103
        $this->assertCount(3, $customers);
104
105
        $customers = $customerQuery->where(['bool_status' => false])->all();
106
        $this->assertCount(1, $customers);
107
    }
108
109
    public function testBooleanValues(): void
110
    {
111
        $this->checkFixture($this->db, 'bool_values');
112
113
        $command = $this->db->createCommand();
114
        $command->batchInsert('bool_values', ['bool_col'], [[true], [false]])->execute();
115
        $boolARQuery = new ActiveQuery(BoolAR::class, $this->db);
116
117
        $this->assertTrue($boolARQuery->where(['bool_col' => true])->onePopulate()->bool_col);
0 ignored issues
show
Bug introduced by
Accessing bool_col on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
118
        $this->assertFalse($boolARQuery->where(['bool_col' => false])->onePopulate()->bool_col);
119
120
        $this->assertEquals(1, $boolARQuery->where('bool_col = TRUE')->count('*'));
121
        $this->assertEquals(1, $boolARQuery->where('bool_col = FALSE')->count('*'));
122
        $this->assertEquals(2, $boolARQuery->where('bool_col IN (TRUE, FALSE)')->count('*'));
123
124
        $this->assertEquals(1, $boolARQuery->where(['bool_col' => true])->count('*'));
125
        $this->assertEquals(1, $boolARQuery->where(['bool_col' => false])->count('*'));
126
        $this->assertEquals(2, $boolARQuery->where(['bool_col' => [true, false]])->count('*'));
127
128
        $this->assertEquals(1, $boolARQuery->where('bool_col = :bool_col', ['bool_col' => true])->count('*'));
129
        $this->assertEquals(1, $boolARQuery->where('bool_col = :bool_col', ['bool_col' => false])->count('*'));
130
    }
131
132
    /**
133
     * {@see https://github.com/yiisoft/yii2/issues/4672}
134
     */
135
    public function testBooleanValues2(): void
136
    {
137
        $this->checkFixture($this->db, 'bool_user');
138
139
        //$this->db->setCharset('utf8');
140
        $this->db->createCommand('DROP TABLE IF EXISTS bool_user;')->execute();
141
        $this->db->createCommand()->createTable('bool_user', [
142
            'id' => SchemaPgsql::TYPE_PK,
143
            'username' => SchemaPgsql::TYPE_STRING . ' NOT NULL',
144
            'auth_key' => SchemaPgsql::TYPE_STRING . '(32) NOT NULL',
145
            'password_hash' => SchemaPgsql::TYPE_STRING . ' NOT NULL',
146
            'password_reset_token' => SchemaPgsql::TYPE_STRING,
147
            'email' => SchemaPgsql::TYPE_STRING . ' NOT NULL',
148
            'role' => SchemaPgsql::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
149
            'status' => SchemaPgsql::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
150
            'created_at' => SchemaPgsql::TYPE_INTEGER . ' NOT NULL',
151
            'updated_at' => SchemaPgsql::TYPE_INTEGER . ' NOT NULL',
152
        ])->execute();
153
        $this->db->createCommand()->addColumn(
154
            'bool_user',
155
            'is_deleted',
156
            SchemaPgsql::TYPE_BOOLEAN . ' NOT NULL DEFAULT FALSE'
157
        )->execute();
158
159
        $user = new UserAR($this->db);
160
        $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...
161
        $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...
162
        $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...
163
        $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...
164
        $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...
165
        $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...
166
        $user->save();
167
168
        $userQuery = new ActiveQuery(UserAR::class, $this->db);
169
        $this->assertCount(1, $userQuery->where(['is_deleted' => false])->all());
170
        $this->assertCount(0, $userQuery->where(['is_deleted' => true])->all());
171
        $this->assertCount(1, $userQuery->where(['is_deleted' => [true, false]])->all());
172
    }
173
174
    public function testBooleanDefaultValues(): void
175
    {
176
        $this->checkFixture($this->db, 'bool_values');
177
178
        $arClass = new BoolAR($this->db);
179
180
        $this->assertNull($arClass->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...
181
        $this->assertNull($arClass->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...
182
        $this->assertNull($arClass->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...
183
184
        $arClass->loadDefaultValues();
185
186
        $this->assertNull($arClass->bool_col);
187
        $this->assertTrue($arClass->default_true);
188
        $this->assertFalse($arClass->default_false);
189
        $this->assertTrue($arClass->save());
190
    }
191
192
    public function testPrimaryKeyAfterSave(): void
193
    {
194
        $this->checkFixture($this->db, 'default_pk');
195
196
        $record = new DefaultPk($this->db);
197
198
        $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...
199
200
        $record->save();
201
202
        $this->assertEquals(5, $record->primaryKey);
0 ignored issues
show
Bug Best Practice introduced by
The property primaryKey does not exist on Yiisoft\ActiveRecord\Tes...\ActiveRecord\DefaultPk. Since you implemented __get, consider adding a @property annotation.
Loading history...
203
    }
204
205
    public static function arrayValuesProvider(): array
206
    {
207
        return [
208
            'simple arrays values' => [[
209
                'intarray_col' => [
210
                    new ArrayExpression([1,-2,null,'42'], 'int4', 1),
211
                    new ArrayExpression([1,-2,null,42], 'int4', 1),
212
                ],
213
                'textarray2_col' => [
214
                    new ArrayExpression([['text'], [null], [1]], 'text', 2),
215
                    new ArrayExpression([['text'], [null], ['1']], 'text', 2),
216
                ],
217
                'json_col' => [['a' => 1, 'b' => null, 'c' => [1,3,5]]],
218
                'jsonb_col' => [[null, 'a', 'b', '\"', '{"af"}']],
219
                'jsonarray_col' => [new ArrayExpression([[',', 'null', true, 'false', 'f']], 'json')],
220
            ]],
221
            'null arrays values' => [[
222
                'intarray_col' => [
223
                    null,
224
                ],
225
                'textarray2_col' => [
226
                    [null, null],
227
                    new ArrayExpression([null, null], 'text', 2),
228
                ],
229
                'json_col' => [
230
                    null,
231
                ],
232
                'jsonarray_col' => [
233
                    null,
234
                ],
235
            ]],
236
            'empty arrays values' => [[
237
                'textarray2_col' => [
238
                    [[], []],
239
                    new ArrayExpression([], 'text', 2),
240
                ],
241
            ]],
242
            'nested objects' => [[
243
                'intarray_col' => [
244
                    new ArrayExpression(new ArrayExpression([1,2,3]), 'int', 1),
245
                    new ArrayExpression([1,2,3], 'int4', 1),
246
                ],
247
                'textarray2_col' => [
248
                    new ArrayExpression([new ArrayExpression(['text']), [null], [1]], 'text', 2),
249
                    new ArrayExpression([['text'], [null], ['1']], 'text', 2),
250
                ],
251
                'json_col' => [
252
                    new JsonExpression(new JsonExpression(new JsonExpression(['a' => 1, 'b' => null, 'c' => new JsonExpression([1,3,5])]))),
253
                    ['a' => 1, 'b' => null, 'c' => [1,3,5]],
254
                ],
255
                'jsonb_col' => [
256
                    new JsonExpression(new ArrayExpression([1,2,3])),
257
                    [1,2,3],
258
                ],
259
                'jsonarray_col' => [
260
                    new ArrayExpression([new JsonExpression(['1', 2]), [3,4,5]], 'json'),
261
                    new ArrayExpression([['1', 2], [3,4,5]], 'json'),
262
                ],
263
            ]],
264
            'arrays packed in classes' => [[
265
                'intarray_col' => [
266
                    new ArrayExpression([1,-2,null,'42'], 'int', 1),
267
                    new ArrayExpression([1,-2,null,42], 'int4', 1),
268
                ],
269
                'textarray2_col' => [
270
                    new ArrayExpression([['text'], [null], [1]], 'text', 2),
271
                    new ArrayExpression([['text'], [null], ['1']], 'text', 2),
272
                ],
273
                'json_col' => [
274
                    new JsonExpression(['a' => 1, 'b' => null, 'c' => [1,3,5]]),
275
                    ['a' => 1, 'b' => null, 'c' => [1,3,5]],
276
                ],
277
                'jsonb_col' => [
278
                    new JsonExpression([null, 'a', 'b', '\"', '{"af"}']),
279
                    [null, 'a', 'b', '\"', '{"af"}'],
280
                ],
281
                'jsonarray_col' => [
282
                    new Expression("array['[\",\",\"null\",true,\"false\",\"f\"]'::json]::json[]"),
283
                    new ArrayExpression([[',', 'null', true, 'false', 'f']], 'json'),
284
                ],
285
            ]],
286
            'scalars' => [[
287
                'json_col' => [
288
                    '5.8',
289
                ],
290
                'jsonb_col' => [
291
                    M_PI,
292
                ],
293
            ]],
294
        ];
295
    }
296
297
    /**
298
     * @dataProvider arrayValuesProvider
299
     */
300
    public function testArrayValues($attributes): void
301
    {
302
        $this->checkFixture($this->db, 'array_and_json_types', true);
303
304
        $type = new ArrayAndJsonTypes($this->db);
305
306
        foreach ($attributes as $attribute => $expected) {
307
            $type->$attribute = $expected[0];
308
        }
309
310
        $type->save();
311
312
        $typeQuery = new ActiveQuery($type::class, $this->db);
313
314
        $type = $typeQuery->onePopulate();
315
316
        foreach ($attributes as $attribute => $expected) {
317
            $expected = $expected[1] ?? $expected[0];
318
            $value = $type->$attribute;
319
320
            if ($expected instanceof ArrayExpression) {
321
                $expected = $expected->getValue();
322
            }
323
324
            $this->assertEquals($expected, $value, 'In column ' . $attribute);
325
326
            if ($value instanceof ArrayExpression) {
327
                $this->assertInstanceOf(ArrayAccess::class, $value);
328
                $this->assertInstanceOf(Traversable::class, $value);
329
                /** testing arrayaccess */
330
                foreach ($type->$attribute as $key => $v) {
331
                    $this->assertSame($expected[$key], $value[$key]);
332
                }
333
            }
334
        }
335
336
        /** Testing update */
337
        foreach ($attributes as $attribute => $expected) {
338
            $type->markAttributeDirty($attribute);
0 ignored issues
show
Bug introduced by
The method markAttributeDirty() does not exist on Yiisoft\ActiveRecord\ActiveRecordInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\ActiveRecord\ActiveRecordInterface. ( Ignorable by Annotation )

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

338
            $type->/** @scrutinizer ignore-call */ 
339
                   markAttributeDirty($attribute);
Loading history...
339
        }
340
341
        $this->assertSame(1, $type->update(), 'The record got updated');
342
    }
343
344
    public function testToArray(): void
345
    {
346
        $this->checkFixture($this->db, 'customer', true);
347
348
        $customerQuery = new ActiveQuery(Customer::class, $this->db);
349
        $customer = $customerQuery->findOne(1);
350
351
        $this->assertSame(
352
            [
353
                'id' => 1,
354
                'email' => '[email protected]',
355
                'name' => 'user1',
356
                'address' => 'address1',
357
                'status' => 1,
358
                'bool_status' => true,
359
                'profile_id' => 1,
360
            ],
361
            $customer->toArray(),
362
        );
363
    }
364
365
    public function testToArrayWithClosure(): void
366
    {
367
        $this->checkFixture($this->db, 'customer', true);
368
369
        $customerQuery = new ActiveQuery(CustomerClosureField::class, $this->db);
370
        $customer = $customerQuery->findOne(1);
371
372
        $this->assertSame(
373
            [
374
                'id' => 1,
375
                'email' => '[email protected]',
376
                'name' => 'user1',
377
                'address' => 'address1',
378
                'status' => 'active',
379
                'bool_status' => true,
380
                'profile_id' => 1,
381
            ],
382
            $customer->toArray(),
383
        );
384
    }
385
386
    public function testToArrayForArrayable(): void
387
    {
388
        $this->checkFixture($this->db, 'customer', true);
389
390
        $customerQuery = new ActiveQuery(CustomerForArrayable::class, $this->db);
391
392
        /** @var CustomerForArrayable $customer */
393
        $customer = $customerQuery->findOne(1);
394
        /** @var CustomerForArrayable $customer2 */
395
        $customer2 = $customerQuery->findOne(2);
396
        /** @var CustomerForArrayable $customer3 */
397
        $customer3 = $customerQuery->findOne(3);
398
399
        $customer->setItem($customer2);
400
        $customer->setItems($customer3);
401
402
        $this->assertSame(
403
            [
404
                'id' => 1,
405
                'email' => '[email protected]',
406
                'name' => 'user1',
407
                'address' => 'address1',
408
                'status' => 'active',
409
                'item' => [
410
                    'id' => 2,
411
                    'email' => '[email protected]',
412
                    'name' => 'user2',
413
                    'status' => 'active',
414
                ],
415
                'items' => [
416
                    [
417
                        'id' => 3,
418
                        'email' => '[email protected]',
419
                        'name' => 'user3',
420
                        'status' => 'inactive',
421
                    ],
422
                ],
423
            ],
424
            $customer->toArray([
425
                'id',
426
                'name',
427
                'email',
428
                'address',
429
                'status',
430
                'item.id',
431
                'item.email',
432
                'item.name',
433
                'items.0.id',
434
                'items.0.email',
435
                'items.0.name',
436
            ]),
437
        );
438
    }
439
}
440