Passed
Branch add-rector-actions (5668b1)
by Wilmer
03:26
created

ActiveQueryTest::tearDown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 7
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\ActiveRecord\Tests\Oracle;
6
7
use Throwable;
8
use Yiisoft\ActiveRecord\ActiveQuery;
9
use Yiisoft\ActiveRecord\Tests\ActiveQueryTest as AbstractActiveQueryTest;
10
use Yiisoft\ActiveRecord\Tests\Oracle\Stubs\Order;
11
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\BitValues;
12
use Yiisoft\Db\Connection\ConnectionInterface;
13
use Yiisoft\Db\Exception\Exception;
14
use Yiisoft\Db\Exception\InvalidConfigException;
15
16
/**
17
 * @group oci
18
 */
19
final class ActiveQueryTest extends AbstractActiveQueryTest
20
{
21
    protected string $driverName = 'oci';
22
    protected ConnectionInterface $db;
23
24
    public function setUp(): void
25
    {
26
        parent::setUp();
27
28
        $this->db = $this->ociConnection;
29
    }
30
31
    protected function tearDown(): void
32
    {
33
        parent::tearDown();
34
35
        $this->ociConnection->close();
36
37
        unset($this->ociConnection);
38
    }
39
40
    /**
41
     * @depends testJoinWith
42
     *
43
     * Tests the alias syntax for joinWith: 'alias' => 'relation'.
44
     *
45
     * @dataProvider aliasMethodProvider
46
     *
47
     * @param string $aliasMethod whether alias is specified explicitly or using the query syntax {{@tablename}}
48
     *
49
     * @throws Exception|InvalidConfigException|Throwable
50
     */
51
    public function testJoinWithAlias(string $aliasMethod): void
52
    {
53
        $orders = [];
54
        $this->checkFixture($this->db, 'order');
55
56
        /** left join and eager loading */
57
        $orderQuery = new ActiveQuery(Order::class, $this->db);
58
        $query = $orderQuery->joinWith(['customer c']);
59
60
        if ($aliasMethod === 'explicit') {
61
            $orders = $query->orderBy('c.id DESC, order.id')->all();
62
        } elseif ($aliasMethod === 'querysyntax') {
63
            $orders = $query->orderBy('{{@customer}}.id DESC, {{@order}}.id')->all();
64
        } elseif ($aliasMethod === 'applyAlias') {
65
            $orders = $query->orderBy(
66
                $query->applyAlias('customer', 'id') . ' DESC,' . $query->applyAlias('order', 'id')
0 ignored issues
show
Bug introduced by
The method applyAlias() does not exist on Yiisoft\ActiveRecord\ActiveQuery. ( Ignorable by Annotation )

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

66
                $query->/** @scrutinizer ignore-call */ 
67
                        applyAlias('customer', 'id') . ' DESC,' . $query->applyAlias('order', 'id')

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...
67
            )->all();
68
        }
69
70
        $this->assertCount(3, $orders);
71
        $this->assertEquals(2, $orders[0]->id);
72
        $this->assertEquals(3, $orders[1]->id);
73
        $this->assertEquals(1, $orders[2]->id);
74
        $this->assertTrue($orders[0]->isRelationPopulated('customer'));
75
        $this->assertTrue($orders[1]->isRelationPopulated('customer'));
76
        $this->assertTrue($orders[2]->isRelationPopulated('customer'));
77
78
        /** inner join filtering and eager loading */
79
        $orderQuery = new ActiveQuery(Order::class, $this->db);
80
        $query = $orderQuery->innerJoinWith(['customer c']);
81
82
        if ($aliasMethod === 'explicit') {
83
            $orders = $query->where('{{c}}.[[id]]=2')->orderBy('order.id')->all();
84
        } elseif ($aliasMethod === 'querysyntax') {
85
            $orders = $query->where('{{@customer}}.[[id]]=2')->orderBy('{{@order}}.id')->all();
86
        } elseif ($aliasMethod === 'applyAlias') {
87
            $orders = $query->where(
88
                [$query->applyAlias('customer', 'id') => 2]
89
            )->orderBy($query->applyAlias('order', 'id'))->all();
90
        }
91
92
        $this->assertCount(2, $orders);
93
        $this->assertEquals(2, $orders[0]->id);
94
        $this->assertEquals(3, $orders[1]->id);
95
        $this->assertTrue($orders[0]->isRelationPopulated('customer'));
96
        $this->assertTrue($orders[1]->isRelationPopulated('customer'));
97
98
        /** inner join filtering without eager loading */
99
        $orderQuery = new ActiveQuery(Order::class, $this->db);
100
        $query = $orderQuery->innerJoinWith(['customer c'], false);
101
102
        if ($aliasMethod === 'explicit') {
103
            $orders = $query->where('{{c}}.[[id]]=2')->orderBy('order.id')->all();
104
        } elseif ($aliasMethod === 'querysyntax') {
105
            $orders = $query->where('{{@customer}}.[[id]]=2')->orderBy('{{@order}}.id')->all();
106
        } elseif ($aliasMethod === 'applyAlias') {
107
            $orders = $query->where(
108
                [$query->applyAlias('customer', 'id') => 2]
109
            )->orderBy($query->applyAlias('order', 'id'))->all();
110
        }
111
112
        $this->assertCount(2, $orders);
113
        $this->assertEquals(2, $orders[0]->id);
114
        $this->assertEquals(3, $orders[1]->id);
115
        $this->assertFalse($orders[0]->isRelationPopulated('customer'));
116
        $this->assertFalse($orders[1]->isRelationPopulated('customer'));
117
118
        /** join with via-relation */
119
        $orderQuery = new ActiveQuery(Order::class, $this->db);
120
        $query = $orderQuery->innerJoinWith(['books b']);
121
122
        if ($aliasMethod === 'explicit') {
123
            $orders = $query->where(
124
                ['b.name' => 'Yii 1.1 Application Development Cookbook']
125
            )->orderBy('order.id')->all();
126
        } elseif ($aliasMethod === 'querysyntax') {
127
            $orders = $query->where(
128
                ['{{@item}}.name' => 'Yii 1.1 Application Development Cookbook']
129
            )->orderBy('{{@order}}.id')->all();
130
        } elseif ($aliasMethod === 'applyAlias') {
131
            $orders = $query->where(
132
                [$query->applyAlias('book', 'name') => 'Yii 1.1 Application Development Cookbook']
133
            )->orderBy($query->applyAlias('order', 'id'))->all();
134
        }
135
136
        $this->assertCount(2, $orders);
137
        $this->assertCount(2, $orders[0]->books);
138
        $this->assertCount(1, $orders[1]->books);
139
        $this->assertEquals(1, $orders[0]->id);
140
        $this->assertEquals(3, $orders[1]->id);
141
        $this->assertTrue($orders[0]->isRelationPopulated('books'));
142
        $this->assertTrue($orders[1]->isRelationPopulated('books'));
143
144
        /** joining sub relations */
145
        $orderQuery = new ActiveQuery(Order::class, $this->db);
146
        $query = $orderQuery->innerJoinWith(
147
            [
148
                'items i' => static function ($q) use ($aliasMethod) {
149
                    /** @var $q ActiveQuery */
150
                    if ($aliasMethod === 'explicit') {
151
                        $q->orderBy('{{i}}.id');
152
                    } elseif ($aliasMethod === 'querysyntax') {
153
                        $q->orderBy('{{@item}}.id');
154
                    } elseif ($aliasMethod === 'applyAlias') {
155
                        $q->orderBy($q->applyAlias('item', 'id'));
156
                    }
157
                },
158
                'items.category c' => static function ($q) use ($aliasMethod) {
159
                    /**  @var $q ActiveQuery */
160
                    if ($aliasMethod === 'explicit') {
161
                        $q->where('{{c}}.[[id]] = 2');
162
                    } elseif ($aliasMethod === 'querysyntax') {
163
                        $q->where('{{@category}}.[[id]] = 2');
164
                    } elseif ($aliasMethod === 'applyAlias') {
165
                        $q->where([$q->applyAlias('category', 'id') => 2]);
166
                    }
167
                },
168
            ]
169
        );
170
171
        if ($aliasMethod === 'explicit') {
172
            $orders = $query->orderBy('{{i}}.id')->all();
173
        } elseif ($aliasMethod === 'querysyntax') {
174
            $orders = $query->orderBy('{{@item}}.id')->all();
175
        } elseif ($aliasMethod === 'applyAlias') {
176
            $orders = $query->orderBy($query->applyAlias('item', 'id'))->all();
177
        }
178
179
        $this->assertCount(1, $orders);
180
        $this->assertCount(3, $orders[0]->items);
181
        $this->assertEquals(2, $orders[0]->id);
182
        $this->assertEquals(2, $orders[0]->items[0]->category->id);
183
        $this->assertTrue($orders[0]->isRelationPopulated('items'));
184
        $this->assertTrue($orders[0]->items[0]->isRelationPopulated('category'));
185
186
        /** join with ON condition */
187
        if ($aliasMethod === 'explicit' || $aliasMethod === 'querysyntax') {
188
            $relationName = 'books' . ucfirst($aliasMethod);
189
190
            $orderQuery = new ActiveQuery(Order::class, $this->db);
191
            $orders = $orderQuery->joinWith(["$relationName b"])->orderBy('order.id')->all();
192
193
            $this->assertCount(3, $orders);
194
            $this->assertCount(2, $orders[0]->$relationName);
195
            $this->assertCount(0, $orders[1]->$relationName);
196
            $this->assertCount(1, $orders[2]->$relationName);
197
            $this->assertEquals(1, $orders[0]->id);
0 ignored issues
show
Bug introduced by
Accessing id on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
198
            $this->assertEquals(2, $orders[1]->id);
199
            $this->assertEquals(3, $orders[2]->id);
200
            $this->assertTrue($orders[0]->isRelationPopulated($relationName));
0 ignored issues
show
Bug introduced by
The method isRelationPopulated() 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

200
            $this->assertTrue($orders[0]->/** @scrutinizer ignore-call */ isRelationPopulated($relationName));
Loading history...
201
            $this->assertTrue($orders[1]->isRelationPopulated($relationName));
202
            $this->assertTrue($orders[2]->isRelationPopulated($relationName));
203
        }
204
205
        /** join with ON condition and alias in relation definition */
206
        if ($aliasMethod === 'explicit' || $aliasMethod === 'querysyntax') {
207
            $relationName = 'books' . ucfirst($aliasMethod) . 'A';
208
209
            $orderQuery = new ActiveQuery(Order::class, $this->db);
210
            $orders = $orderQuery->joinWith([(string)$relationName])->orderBy('order.id')->all();
211
212
            $this->assertCount(3, $orders);
213
            $this->assertCount(2, $orders[0]->$relationName);
214
            $this->assertCount(0, $orders[1]->$relationName);
215
            $this->assertCount(1, $orders[2]->$relationName);
216
            $this->assertEquals(1, $orders[0]->id);
217
            $this->assertEquals(2, $orders[1]->id);
218
            $this->assertEquals(3, $orders[2]->id);
219
            $this->assertTrue($orders[0]->isRelationPopulated($relationName));
220
            $this->assertTrue($orders[1]->isRelationPopulated($relationName));
221
            $this->assertTrue($orders[2]->isRelationPopulated($relationName));
222
        }
223
224
        /** join with count and query */
225
        $orderQuery = new ActiveQuery(Order::class, $this->db);
226
        $query = $orderQuery->joinWith(['customer c']);
227
228
        if ($aliasMethod === 'explicit') {
229
            $count = $query->count('{{c}}.[[id]]');
230
        } elseif ($aliasMethod === 'querysyntax') {
231
            $count = $query->count('{{@customer}}.id');
232
        } elseif ($aliasMethod === 'applyAlias') {
233
            $count = $query->count($query->applyAlias('customer', 'id'));
234
        }
235
236
        $this->assertEquals(3, $count);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $count does not seem to be defined for all execution paths leading up to this point.
Loading history...
237
238
        $orders = $query->all();
239
        $this->assertCount(3, $orders);
240
241
        /** relational query */
242
        $orderQuery = new ActiveQuery(Order::class, $this->db);
243
        $order = $orderQuery->findOne(1);
244
245
        $customerQuery = $order->getCustomer()->innerJoinWith(['orders o'], false);
0 ignored issues
show
Bug introduced by
The method getCustomer() does not exist on Yiisoft\ActiveRecord\ActiveRecordInterface. It seems like you code against a sub-type of Yiisoft\ActiveRecord\ActiveRecordInterface such as Yiisoft\ActiveRecord\Tes...tubs\ActiveRecord\Order. ( Ignorable by Annotation )

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

245
        $customerQuery = $order->/** @scrutinizer ignore-call */ getCustomer()->innerJoinWith(['orders o'], false);
Loading history...
246
247
        if ($aliasMethod === 'explicit') {
248
            $customer = $customerQuery->where(['{{o}}.[[id]]' => 1])->one();
249
        } elseif ($aliasMethod === 'querysyntax') {
250
            $customer = $customerQuery->where(['{{@order}}.id' => 1])->one();
251
        } elseif ($aliasMethod === 'applyAlias') {
252
            $customer = $customerQuery->where([$query->applyAlias('order', 'id') => 1])->one();
253
        }
254
255
        $this->assertEquals(1, $customer->id);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $customer does not seem to be defined for all execution paths leading up to this point.
Loading history...
256
        $this->assertNotNull($customer);
257
258
        /** join with sub-relation called inside Closure */
259
        $orderQuery = new ActiveQuery(Order::class, $this->db);
260
        $orders = $orderQuery->joinWith(
261
            [
262
                'items' => static function ($q) use ($aliasMethod) {
263
                    /** @var $q ActiveQuery */
264
                    $q->orderBy('item.id');
265
                    $q->joinWith(['category c']);
266
267
                    if ($aliasMethod === 'explicit') {
268
                        $q->where('{{c}}.[[id]] = 2');
269
                    } elseif ($aliasMethod === 'querysyntax') {
270
                        $q->where('{{@category}}.[[id]] = 2');
271
                    } elseif ($aliasMethod === 'applyAlias') {
272
                        $q->where([$q->applyAlias('category', 'id') => 2]);
273
                    }
274
                },
275
            ]
276
        )->orderBy('order.id')->all();
277
278
        $this->assertCount(1, $orders);
279
        $this->assertCount(3, $orders[0]->items);
0 ignored issues
show
Bug introduced by
Accessing items on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
280
        $this->assertEquals(2, $orders[0]->id);
281
        $this->assertEquals(2, $orders[0]->items[0]->category->id);
282
        $this->assertTrue($orders[0]->isRelationPopulated('items'));
283
        $this->assertTrue($orders[0]->items[0]->isRelationPopulated('category'));
284
    }
285
286
    /**
287
     * @depends testJoinWith
288
     */
289
    public function testJoinWithSameTable(): void
290
    {
291
        $this->checkFixture($this->db, 'order');
292
293
        /**
294
         * join with the same table but different aliases alias is defined in the relation definition without eager
295
         * loading
296
         */
297
        $query = new ActiveQuery(Order::class, $this->db);
298
        $query
299
            ->joinWith('bookItems', false)
300
            ->joinWith('movieItems', false)
301
            ->where(['{{movies}}.[[name]]' => 'Toy Story']);
302
        $orders = $query->all();
303
        $this->assertCount(
304
            1,
305
            $orders,
306
            $query->createCommand()->getRawSql() . print_r($orders, true)
0 ignored issues
show
Bug introduced by
Are you sure print_r($orders, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

306
            $query->createCommand()->getRawSql() . /** @scrutinizer ignore-type */ print_r($orders, true)
Loading history...
307
        );
308
        $this->assertEquals(2, $orders[0]->id);
0 ignored issues
show
Bug introduced by
Accessing id on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
309
        $this->assertFalse($orders[0]->isRelationPopulated('bookItems'));
310
        $this->assertFalse($orders[0]->isRelationPopulated('movieItems'));
311
312
        /** with eager loading */
313
        $query = new ActiveQuery(Order::class, $this->db);
314
        $query->joinWith('bookItems', true)->joinWith('movieItems', true)->where(['{{movies}}.[[name]]' => 'Toy Story']);
315
        $orders = $query->all();
316
        $this->assertCount(
317
            1,
318
            $orders,
319
            $query->createCommand()->getRawSql() . print_r($orders, true)
320
        );
321
        $this->assertCount(0, $orders[0]->bookItems);
0 ignored issues
show
Bug introduced by
Accessing bookItems on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
322
        $this->assertCount(3, $orders[0]->movieItems);
0 ignored issues
show
Bug introduced by
Accessing movieItems on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
323
        $this->assertEquals(2, $orders[0]->id);
324
        $this->assertTrue($orders[0]->isRelationPopulated('bookItems'));
325
        $this->assertTrue($orders[0]->isRelationPopulated('movieItems'));
326
327
        /**
328
         * join with the same table but different aliases alias is defined in the call to joinWith() without eager
329
         * loading
330
         */
331
        $query = new ActiveQuery(Order::class, $this->db);
332
        $query
333
            ->joinWith(
334
                [
335
                    'itemsIndexed books' => static function ($q) {
336
                        $q->onCondition('{{books}}.[[category_id]] = 1');
337
                    },
338
                ],
339
                false
340
            )->joinWith(
341
                [
342
                    'itemsIndexed movies' => static function ($q) {
343
                        $q->onCondition('{{movies}}.[[category_id]] = 2');
344
                    },
345
                ],
346
                false
347
            )->where(['{{movies}}.[[name]]' => 'Toy Story']);
348
        $orders = $query->all();
349
        $this->assertCount(
350
            1,
351
            $orders,
352
            $query->createCommand()->getRawSql() . print_r($orders, true)
353
        );
354
        $this->assertEquals(2, $orders[0]->id);
355
        $this->assertFalse($orders[0]->isRelationPopulated('itemsIndexed'));
356
357
        /** with eager loading, only for one relation as it would be overwritten otherwise. */
358
        $query = new ActiveQuery(Order::class, $this->db);
359
        $query
360
            ->joinWith(
361
                [
362
                    'itemsIndexed books' => static function ($q) {
363
                        $q->onCondition('{{books}}.[[category_id]] = 1');
364
                    },
365
                ],
366
                false
367
            )
368
            ->joinWith(
369
                [
370
                    'itemsIndexed movies' => static function ($q) {
371
                        $q->onCondition('{{movies}}.[[category_id]] = 2');
372
                    },
373
                ],
374
                true
375
            )->where(['{{movies}}.[[name]]' => 'Toy Story']);
376
        $orders = $query->all();
377
        $this->assertCount(1, $orders, $query->createCommand()->getRawSql() . print_r($orders, true));
378
        $this->assertCount(3, $orders[0]->itemsIndexed);
0 ignored issues
show
Bug introduced by
Accessing itemsIndexed on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
379
        $this->assertEquals(2, $orders[0]->id);
380
        $this->assertTrue($orders[0]->isRelationPopulated('itemsIndexed'));
381
382
        /** with eager loading, and the other relation */
383
        $query = new ActiveQuery(Order::class, $this->db);
384
        $query
385
            ->joinWith(
386
                [
387
                    'itemsIndexed books' => static function ($q) {
388
                        $q->onCondition('{{books}}.[[category_id]] = 1');
389
                    },
390
                ],
391
                true
392
            )
393
            ->joinWith(
394
                [
395
                    'itemsIndexed movies' => static function ($q) {
396
                        $q->onCondition('{{movies}}.[[category_id]] = 2');
397
                    },
398
                ],
399
                false
400
            )
401
            ->where(['{{movies}}.[[name]]' => 'Toy Story']);
402
        $orders = $query->all();
403
        $this->assertCount(1, $orders, $query->createCommand()->getRawSql() . print_r($orders, true));
404
        $this->assertCount(0, $orders[0]->itemsIndexed);
405
        $this->assertEquals(2, $orders[0]->id);
406
        $this->assertTrue($orders[0]->isRelationPopulated('itemsIndexed'));
407
    }
408
409
    /**
410
     * @see https://github.com/yiisoft/yii2/issues/9006
411
     */
412
    public function testBit(): void
413
    {
414
        $this->checkFixture($this->db, 'bit_values');
415
416
        $bitValueQuery = new ActiveQuery(BitValues::class, $this->db);
417
        $falseBit = $bitValueQuery->findOne(1);
418
        $this->assertEquals('0', $falseBit->val);
0 ignored issues
show
Bug introduced by
Accessing val on the interface Yiisoft\ActiveRecord\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
419
420
        $bitValueQuery = new ActiveQuery(BitValues::class, $this->db);
421
        $trueBit = $bitValueQuery->findOne(2);
422
        $this->assertEquals('1', $trueBit->val);
423
    }
424
}
425