ActiveQueryTest::tearDown()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
rs 10
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\Oracle;
6
7
use Throwable;
8
use Yiisoft\ActiveRecord\ActiveQuery;
9
use Yiisoft\ActiveRecord\Tests\Driver\Oracle\Stubs\Order;
10
use Yiisoft\ActiveRecord\Tests\Driver\Oracle\Stubs\BitValues;
11
use Yiisoft\ActiveRecord\Tests\Support\OracleHelper;
12
use Yiisoft\Db\Exception\Exception;
13
use Yiisoft\Db\Exception\InvalidConfigException;
14
15
final class ActiveQueryTest extends \Yiisoft\ActiveRecord\Tests\ActiveQueryTest
16
{
17
    public function setUp(): void
18
    {
19
        parent::setUp();
20
21
        $oracleHelper = new OracleHelper();
22
        $this->db = $oracleHelper->createConnection();
23
    }
24
25
    protected function tearDown(): void
26
    {
27
        parent::tearDown();
28
29
        $this->db->close();
30
31
        unset($this->db);
32
    }
33
34
    /**
35
     * @depends testJoinWith
36
     *
37
     * Tests the alias syntax for joinWith: 'alias' => 'relation'.
38
     *
39
     * @dataProvider aliasMethodProvider
40
     *
41
     * @param string $aliasMethod whether alias is specified explicitly or using the query syntax {{@tablename}}
42
     *
43
     * @throws Exception|InvalidConfigException|Throwable
44
     */
45
    public function testJoinWithAlias(string $aliasMethod): void
46
    {
47
        $orders = [];
48
        $this->checkFixture($this->db, 'order', true);
49
50
        /** left join and eager loading */
51
        $orderQuery = new ActiveQuery(Order::class, $this->db);
52
        $query = $orderQuery->joinWith(['customer c']);
53
54
        if ($aliasMethod === 'explicit') {
55
            $orders = $query->orderBy('c.id DESC, order.id')->all();
56
        } elseif ($aliasMethod === 'querysyntax') {
57
            $orders = $query->orderBy('{{@customer}}.id DESC, {{@order}}.id')->all();
58
        } elseif ($aliasMethod === 'applyAlias') {
59
            $orders = $query->orderBy(
60
                $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

60
                $query->/** @scrutinizer ignore-call */ 
61
                        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...
61
            )->all();
62
        }
63
64
        $this->assertCount(3, $orders);
65
        $this->assertEquals(2, $orders[0]->getId());
66
        $this->assertEquals(3, $orders[1]->getId());
67
        $this->assertEquals(1, $orders[2]->getId());
68
        $this->assertTrue($orders[0]->isRelationPopulated('customer'));
69
        $this->assertTrue($orders[1]->isRelationPopulated('customer'));
70
        $this->assertTrue($orders[2]->isRelationPopulated('customer'));
71
72
        /** inner join filtering and eager loading */
73
        $orderQuery = new ActiveQuery(Order::class, $this->db);
74
        $query = $orderQuery->innerJoinWith(['customer c']);
75
76
        if ($aliasMethod === 'explicit') {
77
            $orders = $query->where('{{c}}.[[id]]=2')->orderBy('order.id')->all();
78
        } elseif ($aliasMethod === 'querysyntax') {
79
            $orders = $query->where('{{@customer}}.[[id]]=2')->orderBy('{{@order}}.id')->all();
80
        } elseif ($aliasMethod === 'applyAlias') {
81
            $orders = $query->where(
82
                [$query->applyAlias('customer', 'id') => 2]
83
            )->orderBy($query->applyAlias('order', 'id'))->all();
84
        }
85
86
        $this->assertCount(2, $orders);
87
        $this->assertEquals(2, $orders[0]->getId());
88
        $this->assertEquals(3, $orders[1]->getId());
89
        $this->assertTrue($orders[0]->isRelationPopulated('customer'));
90
        $this->assertTrue($orders[1]->isRelationPopulated('customer'));
91
92
        /** inner join filtering without eager loading */
93
        $orderQuery = new ActiveQuery(Order::class, $this->db);
94
        $query = $orderQuery->innerJoinWith(['customer c'], false);
95
96
        if ($aliasMethod === 'explicit') {
97
            $orders = $query->where('{{c}}.[[id]]=2')->orderBy('order.id')->all();
98
        } elseif ($aliasMethod === 'querysyntax') {
99
            $orders = $query->where('{{@customer}}.[[id]]=2')->orderBy('{{@order}}.id')->all();
100
        } elseif ($aliasMethod === 'applyAlias') {
101
            $orders = $query->where(
102
                [$query->applyAlias('customer', 'id') => 2]
103
            )->orderBy($query->applyAlias('order', 'id'))->all();
104
        }
105
106
        $this->assertCount(2, $orders);
107
        $this->assertEquals(2, $orders[0]->getId());
108
        $this->assertEquals(3, $orders[1]->getId());
109
        $this->assertFalse($orders[0]->isRelationPopulated('customer'));
110
        $this->assertFalse($orders[1]->isRelationPopulated('customer'));
111
112
        /** join with via-relation */
113
        $orderQuery = new ActiveQuery(Order::class, $this->db);
114
        $query = $orderQuery->innerJoinWith(['books b']);
115
116
        if ($aliasMethod === 'explicit') {
117
            $orders = $query->where(
118
                ['b.name' => 'Yii 1.1 Application Development Cookbook']
119
            )->orderBy('order.id')->all();
120
        } elseif ($aliasMethod === 'querysyntax') {
121
            $orders = $query->where(
122
                ['{{@item}}.name' => 'Yii 1.1 Application Development Cookbook']
123
            )->orderBy('{{@order}}.id')->all();
124
        } elseif ($aliasMethod === 'applyAlias') {
125
            $orders = $query->where(
126
                [$query->applyAlias('book', 'name') => 'Yii 1.1 Application Development Cookbook']
127
            )->orderBy($query->applyAlias('order', 'id'))->all();
128
        }
129
130
        $this->assertCount(2, $orders);
131
        $this->assertCount(2, $orders[0]->getBooks());
132
        $this->assertCount(1, $orders[1]->getBooks());
133
        $this->assertEquals(1, $orders[0]->getId());
134
        $this->assertEquals(3, $orders[1]->getId());
135
        $this->assertTrue($orders[0]->isRelationPopulated('books'));
136
        $this->assertTrue($orders[1]->isRelationPopulated('books'));
137
138
        /** joining sub relations */
139
        $orderQuery = new ActiveQuery(Order::class, $this->db);
140
        $query = $orderQuery->innerJoinWith(
141
            [
142
                'items i' => static function ($q) use ($aliasMethod) {
143
                    /** @var $q ActiveQuery */
144
                    if ($aliasMethod === 'explicit') {
145
                        $q->orderBy('{{i}}.id');
146
                    } elseif ($aliasMethod === 'querysyntax') {
147
                        $q->orderBy('{{@item}}.id');
148
                    } elseif ($aliasMethod === 'applyAlias') {
149
                        $q->orderBy($q->applyAlias('item', 'id'));
150
                    }
151
                },
152
                'items.category c' => static function ($q) use ($aliasMethod) {
153
                    /**  @var $q ActiveQuery */
154
                    if ($aliasMethod === 'explicit') {
155
                        $q->where('{{c}}.[[id]] = 2');
156
                    } elseif ($aliasMethod === 'querysyntax') {
157
                        $q->where('{{@category}}.[[id]] = 2');
158
                    } elseif ($aliasMethod === 'applyAlias') {
159
                        $q->where([$q->applyAlias('category', 'id') => 2]);
160
                    }
161
                },
162
            ]
163
        );
164
165
        if ($aliasMethod === 'explicit') {
166
            $orders = $query->orderBy('{{i}}.id')->all();
167
        } elseif ($aliasMethod === 'querysyntax') {
168
            $orders = $query->orderBy('{{@item}}.id')->all();
169
        } elseif ($aliasMethod === 'applyAlias') {
170
            $orders = $query->orderBy($query->applyAlias('item', 'id'))->all();
171
        }
172
173
        $this->assertCount(1, $orders);
174
        $this->assertCount(3, $orders[0]->getItems());
175
        $this->assertEquals(2, $orders[0]->getId());
176
        $this->assertEquals(2, $orders[0]->getItems()[0]->getCategory()->getId());
177
        $this->assertTrue($orders[0]->isRelationPopulated('items'));
178
        $this->assertTrue($orders[0]->getItems()[0]->isRelationPopulated('category'));
179
180
        /** join with ON condition */
181
        if ($aliasMethod === 'explicit' || $aliasMethod === 'querysyntax') {
182
            $relationName = 'books' . ucfirst($aliasMethod);
183
184
            $orderQuery = new ActiveQuery(Order::class, $this->db);
185
            $orders = $orderQuery->joinWith(["$relationName b"])->orderBy('order.id')->all();
186
187
            $this->assertCount(3, $orders);
188
            $this->assertCount(2, $orders[0]->relation($relationName));
189
            $this->assertCount(0, $orders[1]->relation($relationName));
190
            $this->assertCount(1, $orders[2]->relation($relationName));
191
            $this->assertEquals(1, $orders[0]->getId());
192
            $this->assertEquals(2, $orders[1]->getId());
193
            $this->assertEquals(3, $orders[2]->getId());
194
            $this->assertTrue($orders[0]->isRelationPopulated($relationName));
195
            $this->assertTrue($orders[1]->isRelationPopulated($relationName));
196
            $this->assertTrue($orders[2]->isRelationPopulated($relationName));
197
        }
198
199
        /** join with ON condition and alias in relation definition */
200
        if ($aliasMethod === 'explicit' || $aliasMethod === 'querysyntax') {
201
            $relationName = 'books' . ucfirst($aliasMethod) . 'A';
202
203
            $orderQuery = new ActiveQuery(Order::class, $this->db);
204
            $orders = $orderQuery->joinWith([(string)$relationName])->orderBy('order.id')->all();
205
206
            $this->assertCount(3, $orders);
207
            $this->assertCount(2, $orders[0]->relation($relationName));
208
            $this->assertCount(0, $orders[1]->relation($relationName));
209
            $this->assertCount(1, $orders[2]->relation($relationName));
210
            $this->assertEquals(1, $orders[0]->getId());
211
            $this->assertEquals(2, $orders[1]->getId());
212
            $this->assertEquals(3, $orders[2]->getId());
213
            $this->assertTrue($orders[0]->isRelationPopulated($relationName));
214
            $this->assertTrue($orders[1]->isRelationPopulated($relationName));
215
            $this->assertTrue($orders[2]->isRelationPopulated($relationName));
216
        }
217
218
        /** join with count and query */
219
        $orderQuery = new ActiveQuery(Order::class, $this->db);
220
        $query = $orderQuery->joinWith(['customer c']);
221
222
        if ($aliasMethod === 'explicit') {
223
            $count = $query->count('{{c}}.[[id]]');
224
        } elseif ($aliasMethod === 'querysyntax') {
225
            $count = $query->count('{{@customer}}.id');
226
        } elseif ($aliasMethod === 'applyAlias') {
227
            $count = $query->count($query->applyAlias('customer', 'id'));
228
        }
229
230
        $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...
231
232
        $orders = $query->all();
233
        $this->assertCount(3, $orders);
234
235
        /** relational query */
236
        $orderQuery = new ActiveQuery(Order::class, $this->db);
237
        $order = $orderQuery->findOne(1);
238
239
        $customerQuery = $order->getCustomerQuery()->innerJoinWith(['orders o'], false);
0 ignored issues
show
Bug introduced by
The method getCustomerQuery() 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...MagicActiveRecord\Order or 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

239
        $customerQuery = $order->/** @scrutinizer ignore-call */ getCustomerQuery()->innerJoinWith(['orders o'], false);
Loading history...
240
241
        if ($aliasMethod === 'explicit') {
242
            $customer = $customerQuery->where(['{{o}}.[[id]]' => 1])->onePopulate();
243
        } elseif ($aliasMethod === 'querysyntax') {
244
            $customer = $customerQuery->where(['{{@order}}.id' => 1])->onePopulate();
245
        } elseif ($aliasMethod === 'applyAlias') {
246
            $customer = $customerQuery->where([$query->applyAlias('order', 'id') => 1])->onePopulate();
247
        }
248
249
        $this->assertEquals(1, $customer->getId());
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...
250
        $this->assertNotNull($customer);
251
252
        /** join with sub-relation called inside Closure */
253
        $orderQuery = new ActiveQuery(Order::class, $this->db);
254
        $orders = $orderQuery->joinWith(
255
            [
256
                'items' => static function ($q) use ($aliasMethod) {
257
                    /** @var $q ActiveQuery */
258
                    $q->orderBy('item.id');
259
                    $q->joinWith(['category c']);
260
261
                    if ($aliasMethod === 'explicit') {
262
                        $q->where('{{c}}.[[id]] = 2');
263
                    } elseif ($aliasMethod === 'querysyntax') {
264
                        $q->where('{{@category}}.[[id]] = 2');
265
                    } elseif ($aliasMethod === 'applyAlias') {
266
                        $q->where([$q->applyAlias('category', 'id') => 2]);
267
                    }
268
                },
269
            ]
270
        )->orderBy('order.id')->all();
271
272
        $this->assertCount(1, $orders);
273
        $this->assertCount(3, $orders[0]->getItems());
274
        $this->assertEquals(2, $orders[0]->getId());
275
        $this->assertEquals(2, $orders[0]->getItems()[0]->getCategory()->getId());
276
        $this->assertTrue($orders[0]->isRelationPopulated('items'));
277
        $this->assertTrue($orders[0]->getItems()[0]->isRelationPopulated('category'));
278
    }
279
280
    /**
281
     * @depends testJoinWith
282
     */
283
    public function testJoinWithSameTable(): void
284
    {
285
        $this->checkFixture($this->db, 'order');
286
287
        /**
288
         * join with the same table but different aliases alias is defined in the relation definition without eager
289
         * loading
290
         */
291
        $query = new ActiveQuery(Order::class, $this->db);
292
        $query
293
            ->joinWith('bookItems', false)
294
            ->joinWith('movieItems', false)
295
            ->where(['{{movies}}.[[name]]' => 'Toy Story']);
296
        $orders = $query->all();
297
        $this->assertCount(
298
            1,
299
            $orders,
300
            $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

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