Passed
Push — master ( bc8b6f...7a9b1f )
by Sergei
02:57
created

ActiveRecordTest::testCastValues()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 29
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 29
rs 9.584
c 0
b 0
f 0
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\Driver\Pgsql\Stubs\Type;
11
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\ArrayAndJsonTypes;
12
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Beta;
13
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\BoolAR;
14
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Customer;
15
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerClosureField;
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;
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 testDefaultValues(): void
44
    {
45
        $this->checkFixture($this->db, 'type');
46
47
        $arClass = new Type($this->db);
48
49
        $arClass->loadDefaultValues();
50
51
        $this->assertEquals(1, $arClass->int_col2);
52
        $this->assertEquals('something', $arClass->char_col2);
53
        $this->assertEquals(1.23, $arClass->float_col2);
54
        $this->assertEquals(33.22, $arClass->numeric_col);
55
        $this->assertEquals(true, $arClass->bool_col2);
56
        $this->assertEquals('2002-01-01 00:00:00', $arClass->time);
57
58
        $arClass = new Type($this->db);
59
        $arClass->char_col2 = 'not something';
60
61
        $arClass->loadDefaultValues();
62
        $this->assertEquals('not something', $arClass->char_col2);
63
64
        $arClass = new Type($this->db);
65
        $arClass->char_col2 = 'not something';
66
67
        $arClass->loadDefaultValues(false);
68
        $this->assertEquals('something', $arClass->char_col2);
69
    }
70
71
    public function testCastValues(): void
72
    {
73
        $this->checkFixture($this->db, 'type');
74
75
        $arClass = new Type($this->db);
76
77
        $arClass->int_col = 123;
78
        $arClass->int_col2 = 456;
79
        $arClass->smallint_col = 42;
80
        $arClass->char_col = '1337';
81
        $arClass->char_col2 = 'test';
82
        $arClass->char_col3 = 'test123';
83
        $arClass->float_col = 3.742;
84
        $arClass->float_col2 = 42.1337;
85
        $arClass->bool_col = true;
86
        $arClass->bool_col2 = false;
87
88
        $arClass->save();
89
90
        /** @var $model Type */
91
        $aqClass = new ActiveQuery(Type::class, $this->db);
92
        $query = $aqClass->onePopulate();
93
94
        $this->assertSame(123, $query->int_col);
0 ignored issues
show
Bug introduced by
Accessing int_col on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
95
        $this->assertSame(456, $query->int_col2);
0 ignored issues
show
Bug introduced by
Accessing int_col2 on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
96
        $this->assertSame(42, $query->smallint_col);
0 ignored issues
show
Bug introduced by
Accessing smallint_col on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
97
        $this->assertSame('1337', trim($query->char_col));
0 ignored issues
show
Bug introduced by
Accessing char_col on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
98
        $this->assertSame('test', $query->char_col2);
0 ignored issues
show
Bug introduced by
Accessing char_col2 on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
99
        $this->assertSame('test123', $query->char_col3);
0 ignored issues
show
Bug introduced by
Accessing char_col3 on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
100
    }
101
102
    public function testExplicitPkOnAutoIncrement(): void
103
    {
104
        $this->checkFixture($this->db, 'customer');
105
106
        $customer = new Customer($this->db);
107
        $customer->setId(1337);
108
        $customer->setEmail('[email protected]');
109
        $customer->setName('user1337');
110
        $customer->setAddress('address1337');
111
        $this->assertTrue($customer->getIsNewRecord());
112
113
        $customer->save();
114
        $this->assertEquals(1337, $customer->getId());
115
        $this->assertFalse($customer->getIsNewRecord());
116
    }
117
118
    /**
119
     * {@see https://github.com/yiisoft/yii2/issues/15482}
120
     */
121
    public function testEagerLoadingUsingStringIdentifiers(): void
122
    {
123
        $this->checkFixture($this->db, 'beta');
124
125
        $betaQuery = new ActiveQuery(Beta::class, $this->db);
126
        $betas = $betaQuery->with('alpha')->all();
127
        $this->assertNotEmpty($betas);
128
129
        $alphaIdentifiers = [];
130
131
        /** @var Beta[] $betas */
132
        foreach ($betas as $beta) {
133
            $this->assertNotNull($beta->getAlpha());
134
            $this->assertEquals($beta->getAlphaStringIdentifier(), $beta->getAlpha()->getStringIdentifier());
135
            $alphaIdentifiers[] = $beta->getAlpha()->getStringIdentifier();
136
        }
137
138
        $this->assertEquals(['1', '01', '001', '001', '2', '2b', '2b', '02'], $alphaIdentifiers);
139
    }
140
141
    public function testBooleanAttribute(): void
142
    {
143
        $this->checkFixture($this->db, 'customer', true);
144
145
        $customer = new Customer($this->db);
146
        $customer->setName('boolean customer');
147
        $customer->setEmail('[email protected]');
148
        $customer->setBoolStatus(false);
149
        $customer->save();
150
151
        $customer->refresh();
152
        $this->assertFalse($customer->getBoolStatus());
153
154
        $customer->setBoolStatus(true);
155
156
        $customer->save();
157
        $customer->refresh();
158
        $this->assertTrue($customer->getBoolStatus());
159
160
        $customerQuery = new ActiveQuery(Customer::class, $this->db);
161
        $customers = $customerQuery->where(['bool_status' => true])->all();
162
        $this->assertCount(3, $customers);
163
164
        $customers = $customerQuery->where(['bool_status' => false])->all();
165
        $this->assertCount(1, $customers);
166
    }
167
168
    public function testBooleanValues(): void
169
    {
170
        $this->checkFixture($this->db, 'bool_values');
171
172
        $command = $this->db->createCommand();
173
        $command->insertBatch('bool_values', [[true], [false]], ['bool_col'])->execute();
174
        $boolARQuery = new ActiveQuery(BoolAR::class, $this->db);
175
176
        $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...
177
        $this->assertFalse($boolARQuery->where(['bool_col' => false])->onePopulate()->bool_col);
178
179
        $this->assertEquals(1, $boolARQuery->where('bool_col = TRUE')->count('*'));
180
        $this->assertEquals(1, $boolARQuery->where('bool_col = FALSE')->count('*'));
181
        $this->assertEquals(2, $boolARQuery->where('bool_col IN (TRUE, FALSE)')->count('*'));
182
183
        $this->assertEquals(1, $boolARQuery->where(['bool_col' => true])->count('*'));
184
        $this->assertEquals(1, $boolARQuery->where(['bool_col' => false])->count('*'));
185
        $this->assertEquals(2, $boolARQuery->where(['bool_col' => [true, false]])->count('*'));
186
187
        $this->assertEquals(1, $boolARQuery->where('bool_col = :bool_col', ['bool_col' => true])->count('*'));
188
        $this->assertEquals(1, $boolARQuery->where('bool_col = :bool_col', ['bool_col' => false])->count('*'));
189
    }
190
191
    /**
192
     * {@see https://github.com/yiisoft/yii2/issues/4672}
193
     */
194
    public function testBooleanValues2(): void
195
    {
196
        $this->checkFixture($this->db, 'bool_user');
197
198
        //$this->db->setCharset('utf8');
199
        $this->db->createCommand('DROP TABLE IF EXISTS bool_user;')->execute();
200
        $this->db->createCommand()->createTable('bool_user', [
201
            'id' => SchemaPgsql::TYPE_PK,
202
            'username' => SchemaPgsql::TYPE_STRING . ' NOT NULL',
203
            'auth_key' => SchemaPgsql::TYPE_STRING . '(32) NOT NULL',
204
            'password_hash' => SchemaPgsql::TYPE_STRING . ' NOT NULL',
205
            'password_reset_token' => SchemaPgsql::TYPE_STRING,
206
            'email' => SchemaPgsql::TYPE_STRING . ' NOT NULL',
207
            'role' => SchemaPgsql::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
208
            'status' => SchemaPgsql::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
209
            'created_at' => SchemaPgsql::TYPE_INTEGER . ' NOT NULL',
210
            'updated_at' => SchemaPgsql::TYPE_INTEGER . ' NOT NULL',
211
        ])->execute();
212
        $this->db->createCommand()->addColumn(
213
            'bool_user',
214
            'is_deleted',
215
            SchemaPgsql::TYPE_BOOLEAN . ' NOT NULL DEFAULT FALSE'
216
        )->execute();
217
218
        $user = new UserAR($this->db);
219
        $user->username = 'test';
220
        $user->auth_key = 'test';
221
        $user->password_hash = 'test';
222
        $user->email = '[email protected]';
223
        $user->created_at = time();
224
        $user->updated_at = time();
225
        $user->save();
226
227
        $userQuery = new ActiveQuery(UserAR::class, $this->db);
228
        $this->assertCount(1, $userQuery->where(['is_deleted' => false])->all());
229
        $this->assertCount(0, $userQuery->where(['is_deleted' => true])->all());
230
        $this->assertCount(1, $userQuery->where(['is_deleted' => [true, false]])->all());
231
    }
232
233
    public function testBooleanDefaultValues(): void
234
    {
235
        $this->checkFixture($this->db, 'bool_values');
236
237
        $arClass = new BoolAR($this->db);
238
239
        $this->assertNull($arClass->bool_col);
240
        $this->assertTrue($arClass->default_true);
241
        $this->assertFalse($arClass->default_false);
242
243
        $arClass->loadDefaultValues();
244
245
        $this->assertNull($arClass->bool_col);
246
        $this->assertTrue($arClass->default_true);
247
        $this->assertFalse($arClass->default_false);
248
        $this->assertTrue($arClass->save());
249
    }
250
251
    public function testPrimaryKeyAfterSave(): void
252
    {
253
        $this->checkFixture($this->db, 'default_pk');
254
255
        $record = new DefaultPk($this->db);
256
257
        $record->type = 'type';
258
259
        $record->save();
260
261
        $this->assertEquals(5, $record->getPrimaryKey());
262
    }
263
264
    public static function arrayValuesProvider(): array
265
    {
266
        return [
267
            'simple arrays values' => [[
268
                'intarray_col' => [
269
                    new ArrayExpression([1,-2,null,'42'], 'int4', 1),
270
                    new ArrayExpression([1,-2,null,42], 'int4', 1),
271
                ],
272
                'textarray2_col' => [
273
                    new ArrayExpression([['text'], [null], [1]], 'text', 2),
274
                    new ArrayExpression([['text'], [null], ['1']], 'text', 2),
275
                ],
276
                'json_col' => [['a' => 1, 'b' => null, 'c' => [1,3,5]]],
277
                'jsonb_col' => [[null, 'a', 'b', '\"', '{"af"}']],
278
                'jsonarray_col' => [new ArrayExpression([[',', 'null', true, 'false', 'f']], 'json')],
279
            ]],
280
            'null arrays values' => [[
281
                'intarray_col' => [
282
                    null,
283
                ],
284
                'textarray2_col' => [
285
                    [null, null],
286
                    new ArrayExpression([null, null], 'text', 2),
287
                ],
288
                'json_col' => [
289
                    null,
290
                ],
291
                'jsonarray_col' => [
292
                    null,
293
                ],
294
            ]],
295
            'empty arrays values' => [[
296
                'textarray2_col' => [
297
                    [[], []],
298
                    new ArrayExpression([], 'text', 2),
299
                ],
300
            ]],
301
            'nested objects' => [[
302
                'intarray_col' => [
303
                    new ArrayExpression(new ArrayExpression([1,2,3]), 'int', 1),
304
                    new ArrayExpression([1,2,3], 'int4', 1),
305
                ],
306
                'textarray2_col' => [
307
                    new ArrayExpression([new ArrayExpression(['text']), [null], [1]], 'text', 2),
308
                    new ArrayExpression([['text'], [null], ['1']], 'text', 2),
309
                ],
310
                'json_col' => [
311
                    new JsonExpression(new JsonExpression(new JsonExpression(['a' => 1, 'b' => null, 'c' => new JsonExpression([1,3,5])]))),
312
                    ['a' => 1, 'b' => null, 'c' => [1,3,5]],
313
                ],
314
                'jsonb_col' => [
315
                    new JsonExpression(new ArrayExpression([1,2,3])),
316
                    [1,2,3],
317
                ],
318
                'jsonarray_col' => [
319
                    new ArrayExpression([new JsonExpression(['1', 2]), [3,4,5]], 'json'),
320
                    new ArrayExpression([['1', 2], [3,4,5]], 'json'),
321
                ],
322
            ]],
323
            'arrays packed in classes' => [[
324
                'intarray_col' => [
325
                    new ArrayExpression([1,-2,null,'42'], 'int', 1),
326
                    new ArrayExpression([1,-2,null,42], 'int4', 1),
327
                ],
328
                'textarray2_col' => [
329
                    new ArrayExpression([['text'], [null], [1]], 'text', 2),
330
                    new ArrayExpression([['text'], [null], ['1']], 'text', 2),
331
                ],
332
                'json_col' => [
333
                    new JsonExpression(['a' => 1, 'b' => null, 'c' => [1,3,5]]),
334
                    ['a' => 1, 'b' => null, 'c' => [1,3,5]],
335
                ],
336
                'jsonb_col' => [
337
                    new JsonExpression([null, 'a', 'b', '\"', '{"af"}']),
338
                    [null, 'a', 'b', '\"', '{"af"}'],
339
                ],
340
                'jsonarray_col' => [
341
                    new Expression("array['[\",\",\"null\",true,\"false\",\"f\"]'::json]::json[]"),
342
                    new ArrayExpression([[',', 'null', true, 'false', 'f']], 'json'),
343
                ],
344
            ]],
345
            'scalars' => [[
346
                'json_col' => [
347
                    '5.8',
348
                ],
349
                'jsonb_col' => [
350
                    M_PI,
351
                ],
352
            ]],
353
        ];
354
    }
355
356
    /**
357
     * @dataProvider arrayValuesProvider
358
     */
359
    public function testArrayValues($attributes): void
360
    {
361
        $this->checkFixture($this->db, 'array_and_json_types', true);
362
363
        $type = new ArrayAndJsonTypes($this->db);
364
365
        foreach ($attributes as $attribute => $expected) {
366
            $type->setAttribute($attribute, $expected[0]);
367
        }
368
369
        $type->save();
370
371
        $typeQuery = new ActiveQuery($type::class, $this->db);
372
373
        $type = $typeQuery->onePopulate();
374
375
        foreach ($attributes as $attribute => $expected) {
376
            $expected = $expected[1] ?? $expected[0];
377
            $value = $type->getAttribute($attribute);
378
379
            if ($expected instanceof ArrayExpression) {
380
                $expected = $expected->getValue();
381
            }
382
383
            $this->assertEquals($expected, $value, 'In column ' . $attribute);
384
385
            if ($value instanceof ArrayExpression) {
386
                $this->assertInstanceOf(ArrayAccess::class, $value);
387
                $this->assertInstanceOf(Traversable::class, $value);
388
                /** testing arrayaccess */
389
                foreach ($type->getAttribute($attribute) as $key => $v) {
390
                    $this->assertSame($expected[$key], $value[$key]);
391
                }
392
            }
393
        }
394
395
        /** Testing update */
396
        foreach ($attributes as $attribute => $expected) {
397
            $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

397
            $type->/** @scrutinizer ignore-call */ 
398
                   markAttributeDirty($attribute);
Loading history...
398
        }
399
400
        $this->assertSame(1, $type->update(), 'The record got updated');
401
    }
402
403
    public function testToArray(): void
404
    {
405
        $this->checkFixture($this->db, 'customer', true);
406
407
        $customerQuery = new ActiveQuery(Customer::class, $this->db);
408
        $customer = $customerQuery->findOne(1);
409
410
        $this->assertSame(
411
            [
412
                'id' => 1,
413
                'email' => '[email protected]',
414
                'name' => 'user1',
415
                'address' => 'address1',
416
                'status' => 1,
417
                'bool_status' => true,
418
                'profile_id' => 1,
419
            ],
420
            $customer->toArray(),
0 ignored issues
show
Bug introduced by
The method toArray() does not exist on Yiisoft\ActiveRecord\ActiveRecordInterface. It seems like you code against a sub-type of Yiisoft\ActiveRecord\ActiveRecordInterface such as Yiisoft\ActiveRecord\Tests\Stubs\MagicActiveRecord or Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord. ( Ignorable by Annotation )

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

420
            $customer->/** @scrutinizer ignore-call */ 
421
                       toArray(),
Loading history...
421
        );
422
    }
423
424
    public function testToArrayWithClosure(): void
425
    {
426
        $this->checkFixture($this->db, 'customer', true);
427
428
        $customerQuery = new ActiveQuery(CustomerClosureField::class, $this->db);
429
        $customer = $customerQuery->findOne(1);
430
431
        $this->assertSame(
432
            [
433
                'id' => 1,
434
                'email' => '[email protected]',
435
                'name' => 'user1',
436
                'address' => 'address1',
437
                'status' => 'active',
438
                'bool_status' => true,
439
                'profile_id' => 1,
440
            ],
441
            $customer->toArray(),
442
        );
443
    }
444
}
445