Completed
Push — master ( e32eeb...714cda )
by
unknown
89:50 queued 46:29
created

CriteriaTest::testCompleteJoinsForWhere()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 30
rs 8.8571
cc 2
eloc 17
nc 2
nop 0
1
<?php
2
3
namespace Oro\Bundle\ApiBundle\Tests\Unit\Collection;
4
5
use Doctrine\ORM\QueryBuilder;
6
7
use Oro\Bundle\ApiBundle\Collection\Criteria;
8
use Oro\Bundle\ApiBundle\Collection\Join;
9
use Oro\Bundle\ApiBundle\Tests\Unit\OrmRelatedTestCase;
10
use Oro\Bundle\EntityBundle\ORM\EntityClassResolver;
11
12
/**
13
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
14
 */
15
class CriteriaTest extends OrmRelatedTestCase
16
{
17
    const ENTITY_NAMESPACE = 'Oro\Bundle\ApiBundle\Tests\Unit\Fixtures\Entity\\';
18
19
    /** @var Criteria */
20
    protected $criteria;
21
22
    protected function setUp()
23
    {
24
        parent::setUp();
25
26
        $this->criteria = new Criteria(new EntityClassResolver($this->doctrine), 'a%s');
27
    }
28
29
    /**
30
     * @param string $entityShortClass
31
     *
32
     * @return string
33
     */
34
    protected function getEntityClass($entityShortClass)
35
    {
36
        return self::ENTITY_NAMESPACE . $entityShortClass;
37
    }
38
39
    /**
40
     * @param $expectedDql
41
     */
42
    protected function assertQuery($expectedDql)
43
    {
44
        $qb = new QueryBuilder($this->em);
45
        $qb
46
            ->select('e')
47
            ->from($this->getEntityClass('User'), 'e');
48
49
        $this->criteria->completeJoins();
50
        $this->doctrineHelper->applyCriteria($qb, $this->criteria);
51
52
        $this->assertEquals(
53
            $expectedDql,
54
            str_replace(self::ENTITY_NAMESPACE, 'Test:', $qb->getDQL())
55
        );
56
    }
57
58
    public function joinTypeDataProvider()
59
    {
60
        return [
61
            [Join::INNER_JOIN, 'addInnerJoin'],
62
            [Join::LEFT_JOIN, 'addLeftJoin'],
63
        ];
64
    }
65
66
    public function testEmptyJoins()
67
    {
68
        $this->assertCount(0, $this->criteria->getJoins());
69
    }
70
71
    /**
72
     * @dataProvider joinTypeDataProvider
73
     */
74 View Code Duplication
    public function testAddJoin($joinType, $addMethodName)
75
    {
76
        $this->criteria->{$addMethodName}('products', '{root}.products');
77
78
        $expectedJoin = new Join($joinType, '{root}.products');
79
        $this->assertTrue($this->criteria->hasJoin('products'));
80
        $this->assertEquals($expectedJoin, $this->criteria->getJoin('products'));
81
        $this->assertEquals(['products' => $expectedJoin], $this->criteria->getJoins());
82
        $this->assertQuery(
83
            'SELECT e FROM Test:User e ' . $joinType . ' JOIN e.products a1'
84
        );
85
    }
86
87
    /**
88
     * @dataProvider joinTypeDataProvider
89
     */
90 View Code Duplication
    public function testAddJoinWithCondition($joinType, $addMethodName)
91
    {
92
        $this->criteria->{$addMethodName}(
93
            'products',
94
            $this->getEntityClass('Product'),
95
            Join::WITH,
96
            '{entity}.name IS NOT NULL',
97
            'idx_name'
98
        );
99
100
        $expectedJoin = new Join(
101
            $joinType,
102
            $this->getEntityClass('Product'),
103
            Join::WITH,
104
            '{entity}.name IS NOT NULL',
105
            'idx_name'
106
        );
107
        $this->assertTrue($this->criteria->hasJoin('products'));
108
        $this->assertEquals($expectedJoin, $this->criteria->getJoin('products'));
109
        $this->assertEquals(['products' => $expectedJoin], $this->criteria->getJoins());
110
        $this->assertQuery(
111
            'SELECT e FROM Test:User e '
112
            . $joinType . ' JOIN Test:Product a1 INDEX BY idx_name WITH a1.name IS NOT NULL'
113
        );
114
    }
115
116
    /**
117
     * @dataProvider joinTypeDataProvider
118
     */
119 View Code Duplication
    public function testAddJoinWithConditionAndEntityName($joinType, $addMethodName)
120
    {
121
        $this->criteria->{$addMethodName}('products', 'Test:Product', Join::WITH, '{entity}.name IS NOT NULL');
122
123
        $expectedJoin = new Join(
124
            $joinType,
125
            $this->getEntityClass('Product'),
126
            Join::WITH,
127
            '{entity}.name IS NOT NULL'
128
        );
129
        $this->assertTrue($this->criteria->hasJoin('products'));
130
        $this->assertEquals($expectedJoin, $this->criteria->getJoin('products'));
131
        $this->assertEquals(['products' => $expectedJoin], $this->criteria->getJoins());
132
        $this->assertQuery(
133
            'SELECT e FROM Test:User e '
134
            . $joinType . ' JOIN Test:Product a1 WITH a1.name IS NOT NULL'
135
        );
136
    }
137
138
    public function testAddSeveralJoins()
139
    {
140
        $this->criteria->addLeftJoin(
141
            'roles',
142
            'Test:Role',
143
            Join::WITH,
144
            '{root}.id MEMBER OF {entity}.users'
145
        );
146
        $this->criteria->addLeftJoin(
147
            'roles.users',
148
            '{roles}.users'
149
        );
150
        $this->criteria->addLeftJoin(
151
            'products',
152
            'Test:Product',
153
            Join::WITH,
154
            '{entity}.owner = {root}'
155
        );
156
        $this->criteria->addLeftJoin(
157
            'products.owner',
158
            '{products}.owner',
159
            Join::WITH,
160
            '{entity}.id = {roles.users}.id'
161
        );
162
163
        $expectedJoins = [
164
            'roles'          => new Join(
165
                Join::LEFT_JOIN,
166
                $this->getEntityClass('Role'),
167
                Join::WITH,
168
                '{root}.id MEMBER OF {entity}.users'
169
            ),
170
            'roles.users'    => new Join(
171
                Join::LEFT_JOIN,
172
                '{roles}.users'
173
            ),
174
            'products'       => new Join(
175
                Join::LEFT_JOIN,
176
                $this->getEntityClass('Product'),
177
                Join::WITH,
178
                '{entity}.owner = {root}'
179
            ),
180
            'products.owner' => new Join(
181
                Join::LEFT_JOIN,
182
                '{products}.owner',
183
                Join::WITH,
184
                '{entity}.id = {roles.users}.id'
185
            ),
186
        ];
187
        $this->assertEquals($expectedJoins, $this->criteria->getJoins());
188
        $this->assertQuery(
189
            'SELECT e FROM Test:User e'
190
            . ' LEFT JOIN Test:Role a1 WITH e.id MEMBER OF a1.users'
191
            . ' LEFT JOIN a1.users a2'
192
            . ' LEFT JOIN Test:Product a3 WITH a3.owner = e'
193
            . ' LEFT JOIN a3.owner a4 WITH a4.id = a2.id'
194
        );
195
    }
196
197
    /**
198
     * @dataProvider joinTypeDataProvider
199
     * @expectedException \InvalidArgumentException
200
     * @expectedExceptionMessage $propertyPath must be specified.
201
     */
202
    public function testAddJoinWithEmptyPropertyPath($joinType, $addMethodName)
0 ignored issues
show
Unused Code introduced by
The parameter $joinType is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
203
    {
204
        $this->criteria->{$addMethodName}('', 'Test:Product');
205
    }
206
207
    /**
208
     * @dataProvider joinTypeDataProvider
209
     * @expectedException \InvalidArgumentException
210
     * @expectedExceptionMessage $join must be specified. Join path: "products".
211
     */
212
    public function testAddJoinWithEmptyJoinExpr($joinType, $addMethodName)
0 ignored issues
show
Unused Code introduced by
The parameter $joinType is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
213
    {
214
        $this->criteria->{$addMethodName}('products', '');
215
    }
216
217
    /**
218
     * @dataProvider joinTypeDataProvider
219
     * @expectedException \InvalidArgumentException
220
     * @expectedExceptionMessage "Test1:Product" is not valid entity name. Join path: "products".
221
     */
222
    public function testAddJoinWithInvalidEntity($joinType, $addMethodName)
0 ignored issues
show
Unused Code introduced by
The parameter $joinType is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
223
    {
224
        $this->criteria->{$addMethodName}('products', 'Test1:Product');
225
    }
226
227
    /**
228
     * @dataProvider joinTypeDataProvider
229
     * @expectedException \InvalidArgumentException
230
     * @expectedExceptionMessage $conditionType must be specified if $condition exists. Join path: "products".
231
     */
232
    public function testAddJoinWithConditionButWithoutConditionType($joinType, $addMethodName)
0 ignored issues
show
Unused Code introduced by
The parameter $joinType is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
233
    {
234
        $this->criteria->{$addMethodName}('products', 'Test:Product', '', '{entity}.name IS NOT NULL');
235
    }
236
237
    /**
238
     * @dataProvider joinTypeDataProvider
239
     */
240
    public function testAddJoinConflictsWithExistingJoin($joinType, $addMethodName)
241
    {
242
        $this->setExpectedException(
243
            '\LogicException',
244
            'The join definition for "products" conflicts with already added join.'
245
            . ' Existing join: "LEFT JOIN ' . $this->getEntityClass('Product') . '".'
246
            . ' New join: "' . $joinType . ' JOIN ' . $this->getEntityClass('Category') . '".'
247
        );
248
        $this->criteria->addLeftJoin('products', 'Test:Product');
249
        $this->criteria->{$addMethodName}('products', 'Test:Category');
250
    }
251
252
    /**
253
     * @dataProvider joinTypeDataProvider
254
     */
255 View Code Duplication
    public function testAddSameJoinTwice($joinType, $addMethodName)
256
    {
257
        $this->criteria->{$addMethodName}('products', '{root}.products');
258
        $this->criteria->{$addMethodName}('products', '{root}.products');
259
260
        $expectedJoin = new Join($joinType, '{root}.products');
261
        $this->assertTrue($this->criteria->hasJoin('products'));
262
        $this->assertEquals($expectedJoin, $this->criteria->getJoin('products'));
263
        $this->assertEquals(['products' => $expectedJoin], $this->criteria->getJoins());
264
        $this->assertQuery(
265
            'SELECT e FROM Test:User e ' . $joinType . ' JOIN e.products a1'
266
        );
267
    }
268
269 View Code Duplication
    public function testAddInnerJoinAndThenLeftJoinForSameJoinStatement()
270
    {
271
        $this->criteria->addInnerJoin('products', '{root}.products');
272
        $this->criteria->addLeftJoin('products', '{root}.products');
273
274
        $expectedJoin = new Join(Join::INNER_JOIN, '{root}.products');
275
        $this->assertTrue($this->criteria->hasJoin('products'));
276
        $this->assertEquals($expectedJoin, $this->criteria->getJoin('products'));
277
        $this->assertEquals(['products' => $expectedJoin], $this->criteria->getJoins());
278
        $this->assertQuery(
279
            'SELECT e FROM Test:User e INNER JOIN e.products a1'
280
        );
281
    }
282
283 View Code Duplication
    public function testAddLeftJoinAndThenInnerJoinForSameJoinStatement()
284
    {
285
        $this->criteria->addLeftJoin('products', '{root}.products');
286
        $this->criteria->addInnerJoin('products', '{root}.products');
287
288
        $expectedJoin = new Join(Join::INNER_JOIN, '{root}.products');
289
        $this->assertTrue($this->criteria->hasJoin('products'));
290
        $this->assertEquals($expectedJoin, $this->criteria->getJoin('products'));
291
        $this->assertEquals(['products' => $expectedJoin], $this->criteria->getJoins());
292
        $this->assertQuery(
293
            'SELECT e FROM Test:User e INNER JOIN e.products a1'
294
        );
295
    }
296
297
    public function testCompleteJoinsForOrderBy()
298
    {
299
        $this->criteria->orderBy(['id' => Criteria::ASC, 'category.name' => Criteria::ASC]);
300
        $this->assertQuery(
301
            'SELECT e FROM Test:User e'
302
            . ' LEFT JOIN e.category category'
303
            . ' ORDER BY e.id ASC, category.name ASC'
304
        );
305
    }
306
307
    public function testCompleteJoinsForWhere()
308
    {
309
        $this->criteria->andWhere(
310
            $this->criteria->expr()->orX(
311
                $this->criteria->expr()->eq('category.name', 'test_category'),
312
                $this->criteria->expr()->eq('groups.name', 'test_group')
313
            )
314
        );
315
316
        /**
317
         * Changed expected result according to changes
318
         * in user defined sorting algorithm in php7
319
         * https://bugs.php.net/bug.php?id=69158
320
         */
321
        if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
322
            $this->assertQuery(
323
                'SELECT e FROM Test:User e'
324
                . ' LEFT JOIN e.category category'
325
                . ' LEFT JOIN e.groups groups'
326
                . ' WHERE category.name = :category_name OR groups.name = :groups_name'
327
            );
328
        } else {
329
            $this->assertQuery(
330
                'SELECT e FROM Test:User e'
331
                . ' LEFT JOIN e.groups groups'
332
                . ' LEFT JOIN e.category category'
333
                . ' WHERE category.name = :category_name OR groups.name = :groups_name'
334
            );
335
        }
336
    }
337
}
338