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

ActiveRecordTest::testToArrayForArrayable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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

339
            $type->/** @scrutinizer ignore-call */ 
340
                   markAttributeDirty($attribute);
Loading history...
340
        }
341
342
        $this->assertSame(1, $type->update(), 'The record got updated');
343
    }
344
345
    public function testToArray(): void
346
    {
347
        $this->checkFixture($this->db, 'customer', true);
348
349
        $customerQuery = new ActiveQuery(Customer::class, $this->db);
350
        $customer = $customerQuery->findOne(1);
351
352
        $this->assertSame(
353
            [
354
                'id' => 1,
355
                'email' => '[email protected]',
356
                'name' => 'user1',
357
                'address' => 'address1',
358
                'status' => 1,
359
                'bool_status' => true,
360
                'profile_id' => 1,
361
            ],
362
            $customer->toArray(),
363
        );
364
    }
365
366
    public function testToArrayWithClosure(): void
367
    {
368
        $this->checkFixture($this->db, 'customer', true);
369
370
        $customerQuery = new ActiveQuery(CustomerClosureField::class, $this->db);
371
        $customer = $customerQuery->findOne(1);
372
373
        $this->assertSame(
374
            [
375
                'id' => 1,
376
                'email' => '[email protected]',
377
                'name' => 'user1',
378
                'address' => 'address1',
379
                'status' => 'active',
380
                'bool_status' => true,
381
                'profile_id' => 1,
382
            ],
383
            $customer->toArray(),
384
        );
385
    }
386
387
    public function testToArrayForArrayable(): void
388
    {
389
        $this->checkFixture($this->db, 'customer', true);
390
391
        $customerQuery = new ActiveQuery(CustomerForArrayable::class, $this->db);
392
        $customer = $customerQuery->findOne(1);
393
394
        $this->assertSame(
395
            [
396
                'id' => 1,
397
                'email' => '[email protected]',
398
                'name' => 'user1',
399
                'address' => 'address1',
400
                'status' => 'active',
401
                'profile_id' => 1,
402
            ],
403
            ArrayHelper::toArray($customer),
404
        );
405
    }
406
}
407