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

testEagerLoadingUsingStringIdentifiers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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

337
            $type->/** @scrutinizer ignore-call */ 
338
                   markAttributeDirty($attribute);
Loading history...
338
        }
339
340
        $this->assertSame(1, $type->update(), 'The record got updated');
341
    }
342
343
    public function testToArray(): void
344
    {
345
        $this->checkFixture($this->db, 'customer', true);
346
347
        $customerQuery = new ActiveQuery(Customer::class, $this->db);
348
        $customer = $customerQuery->findOne(1);
349
350
        $this->assertSame(
351
            [
352
                'id' => 1,
353
                'email' => '[email protected]',
354
                'name' => 'user1',
355
                'address' => 'address1',
356
                'status' => 1,
357
                'bool_status' => true,
358
                'profile_id' => 1,
359
            ],
360
            $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

360
            $customer->/** @scrutinizer ignore-call */ 
361
                       toArray(),
Loading history...
361
        );
362
    }
363
364
    public function testToArrayWithClosure(): void
365
    {
366
        $this->checkFixture($this->db, 'customer', true);
367
368
        $customerQuery = new ActiveQuery(CustomerClosureField::class, $this->db);
369
        $customer = $customerQuery->findOne(1);
370
371
        $this->assertSame(
372
            [
373
                'id' => 1,
374
                'email' => '[email protected]',
375
                'name' => 'user1',
376
                'address' => 'address1',
377
                'status' => 'active',
378
                'bool_status' => true,
379
                'profile_id' => 1,
380
            ],
381
            $customer->toArray(),
382
        );
383
    }
384
}
385