Passed
Pull Request — master (#368)
by Sergei
02:42
created

ActiveQueryTest::setUp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 6
rs 10
cc 1
nc 1
nop 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A ActiveQueryTest::createConnection() 0 3 1
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\Connection\ConnectionInterface;
13
use Yiisoft\Db\Exception\Exception;
14
use Yiisoft\Db\Exception\InvalidConfigException;
15
16
final class ActiveQueryTest extends \Yiisoft\ActiveRecord\Tests\ActiveQueryTest
17
{
18
    protected function createConnection(): ConnectionInterface
19
    {
20
        return (new OracleHelper())->createConnection();
21
    }
22
23
    /**
24
     * @depends testJoinWith
25
     *
26
     * Tests the alias syntax for joinWith: 'alias' => 'relation'.
27
     *
28
     * @dataProvider aliasMethodProvider
29
     *
30
     * @param string $aliasMethod whether alias is specified explicitly or using the query syntax {{@tablename}}
31
     *
32
     * @throws Exception|InvalidConfigException|Throwable
33
     */
34
    public function testJoinWithAlias(string $aliasMethod): void
35
    {
36
        $orders = [];
37
        $this->checkFixture($this->db(), 'order', true);
38
39
        /** left join and eager loading */
40
        $orderQuery = new ActiveQuery(Order::class);
41
        $query = $orderQuery->joinWith(['customer c']);
42
43
        if ($aliasMethod === 'explicit') {
44
            $orders = $query->orderBy('c.id DESC, order.id')->all();
45
        } elseif ($aliasMethod === 'querysyntax') {
46
            $orders = $query->orderBy('{{@customer}}.id DESC, {{@order}}.id')->all();
47
        } elseif ($aliasMethod === 'applyAlias') {
48
            $orders = $query->orderBy(
49
                $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

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

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

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