testFilterWillApplyExpectedJoinWithoutConditions()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 19
rs 9.8666
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\DoctrineQueryFilter\Filter;
6
7
use Arp\DoctrineQueryFilter\Enum\JoinConditionType;
8
use Arp\DoctrineQueryFilter\Filter\AbstractJoin;
9
use Arp\DoctrineQueryFilter\Filter\AndX;
10
use Arp\DoctrineQueryFilter\Filter\Exception\FilterException;
11
use Arp\DoctrineQueryFilter\Filter\Exception\InvalidArgumentException;
12
use Arp\DoctrineQueryFilter\Filter\FilterInterface;
13
use Arp\DoctrineQueryFilter\QueryBuilderInterface;
14
use Doctrine\ORM\Query\Expr;
15
use Doctrine\ORM\Query\Expr\Andx as DoctrineAndX;
16
use Doctrine\ORM\Query\Expr\Base;
17
use Doctrine\ORM\Query\Expr\Composite;
18
use PHPUnit\Framework\MockObject\MockObject;
19
20
abstract class AbstractJoinTest extends AbstractFilterTest
21
{
22
    protected AbstractJoin $filter;
23
24
    protected string $filterClassName;
25
26
    public function setUp(): void
27
    {
28
        parent::setUp();
29
30
        /** @var AbstractJoin $filter */
31
        $filter = new $this->filterClassName($this->queryFilterManager, $this->typecaster, $this->paramNameGenerator);
32
        $this->filter = $filter;
33
    }
34
35
    public function testInstanceOfFilterInterface(): void
36
    {
37
        $this->assertInstanceOf(FilterInterface::class, $this->filter);
38
    }
39
40
    public function testInstanceOfAbstractJoin(): void
41
    {
42
        $this->assertInstanceOf(AbstractJoin::class, $this->filter);
43
    }
44
45
    /**
46
     * @throws FilterException
47
     */
48
    public function testFilterWillThrowInvalidArgumentExceptionIfTheRequiredFieldCriteriaIsNotProvided(): void
49
    {
50
        $this->expectException(InvalidArgumentException::class);
51
        $this->expectExceptionMessage(
52
            sprintf(
53
                'The required \'field\' criteria value is missing for filter \'%s\'',
54
                $this->filterClassName
55
            )
56
        );
57
58
        $this->filter->filter($this->queryBuilder, $this->metadata, []);
59
    }
60
61
    /**
62
     * @throws FilterException
63
     */
64
    public function testFilterWillThrowInvalidArgumentExceptionIfTheRequiredJoinAliasIsNotProvided(): void
65
    {
66
        $this->expectException(InvalidArgumentException::class);
67
        $this->expectExceptionMessage(
68
            sprintf(
69
                'The required \'alias\' criteria value is missing for filter \'%s\'',
70
                $this->filterClassName
71
            )
72
        );
73
74
        $fieldName = 'foo';
75
        $this->metadata->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Arp\DoctrineQueryFilter\Metadata\MetadataInterface. ( Ignorable by Annotation )

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

75
        $this->metadata->/** @scrutinizer ignore-call */ 
76
                         expects($this->once())

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...
76
            ->method('hasField')
77
            ->with($fieldName)
78
            ->willReturn(true);
79
80
        $criteria = [
81
            'field' => 'x.' . $fieldName,
82
        ];
83
84
        $this->filter->filter($this->queryBuilder, $this->metadata, $criteria);
85
    }
86
87
88
    /**
89
     * @throws FilterException
90
     */
91
    public function testFilterWillThrowInvalidArgumentExceptionIfProvidedAnInvalidFieldName(): void
92
    {
93
        $entityName = 'Test';
94
        $fieldName = 'foo';
95
        $criteria = [
96
            'field' => $fieldName,
97
        ];
98
99
        $this->metadata->expects($this->once())
100
            ->method('getName')
101
            ->willReturn($entityName);
102
103
        $this->metadata->expects($this->once())
104
            ->method('hasField')
105
            ->with($fieldName)
106
            ->willReturn(false);
107
108
        $this->metadata->expects($this->once())
109
            ->method('hasAssociation')
110
            ->with($fieldName)
111
            ->willReturn(false);
112
113
        $this->expectException(InvalidArgumentException::class);
114
        $this->expectExceptionMessage(
115
            sprintf(
116
                'Unable to apply query filter \'%s\': '
117
                . 'The entity class \'%s\' has no field or association named \'%s\'',
118
                $this->filterClassName,
119
                $entityName,
120
                $fieldName
121
            )
122
        );
123
124
        $this->filter->filter($this->queryBuilder, $this->metadata, $criteria);
125
    }
126
127
    /**
128
     * @param QueryBuilderInterface&MockObject $queryBuilder
129
     * @param string $fieldName
130
     * @param string $alias
131
     * @param null|string|Composite|Base $joinCondition
132
     * @param JoinConditionType|null $joinConditionType
133
     * @param string|null $indexBy
134
     */
135
    abstract protected function assertFilterJoin(
136
        QueryBuilderInterface $queryBuilder,
137
        string $fieldName,
138
        string $alias,
139
        null|string|Composite|Base $joinCondition = null,
140
        ?JoinConditionType $joinConditionType = null,
141
        ?string $indexBy = null
142
    ): void;
143
144
    /**
145
     * @throws InvalidArgumentException
146
     * @throws FilterException
147
     */
148
    public function testFilterWillApplyExpectedJoinWithoutConditions(): void
149
    {
150
        $fieldName = 'foo';
151
        $fieldAlias = 't';
152
153
        $joinAlias = 'a';
154
        $criteria = [
155
            'field' => $fieldAlias . '.' . $fieldName,
156
            'alias' => $joinAlias,
157
        ];
158
159
        $this->metadata->expects($this->once())
160
            ->method('hasField')
161
            ->with($fieldName)
162
            ->willReturn(true);
163
164
        $this->assertFilterJoin($this->queryBuilder, $fieldAlias . '.' . $fieldName, $joinAlias);
165
166
        $this->filter->filter($this->queryBuilder, $this->metadata, $criteria);
167
    }
168
169
    /**
170
     * @throws InvalidArgumentException
171
     * @throws FilterException
172
     */
173
    public function testFilterWillApplyExpectedJoinWithConditions(): void
174
    {
175
        $fieldName = 'foo';
176
        $fieldAlias = 't';
177
        $joinAlias = 'a';
178
179
        $conditions = [
180
            [
181
                'name' => 'eq',
182
                'field' => 'id',
183
                'alias' => $fieldAlias,
184
                'value' => $joinAlias . '.id',
185
            ]
186
        ];
187
188
        $criteria = [
189
            'field' => $fieldAlias . '.' . $fieldName,
190
            'alias' => $joinAlias,
191
            'condition_type' => JoinConditionType::WITH->value,
192
            'conditions' => $conditions,
193
        ];
194
195
        $associationMapping = [
196
            'targetEntity' => 'Bar',
197
        ];
198
199
        $this->metadata->expects($this->once())
200
            ->method('getAssociationMapping')
201
            ->with($fieldName)
202
            ->willReturn($associationMapping);
203
204
        $this->metadata->expects($this->once())
205
            ->method('hasField')
206
            ->with($fieldName)
207
            ->willReturn(true);
208
209
        /** @var QueryBuilderInterface&MockObject $conditionsQueryBuilder */
210
        $conditionsQueryBuilder = $this->createMock(QueryBuilderInterface::class);
211
        $this->queryBuilder->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Arp\DoctrineQueryFilter\QueryBuilderInterface. ( Ignorable by Annotation )

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

211
        $this->queryBuilder->/** @scrutinizer ignore-call */ 
212
                             expects($this->once())

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...
212
            ->method('createQueryBuilder')
213
            ->willReturn($conditionsQueryBuilder);
214
215
        $this->queryFilterManager->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Arp\DoctrineQueryFilter\...yFilterManagerInterface. ( Ignorable by Annotation )

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

215
        $this->queryFilterManager->/** @scrutinizer ignore-call */ 
216
                                   expects($this->once())

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...
216
            ->method('filter')
217
            ->with(
218
                $conditionsQueryBuilder,
219
                $associationMapping['targetEntity'],
220
                [
221
                    'filters' => [
222
                        [
223
                            'name' => AndX::class,
224
                            'conditions' => $conditions,
225
                            'where' => null,
226
                        ]
227
                    ]
228
                ]
229
            );
230
231
        /** @var DoctrineAndX&MockObject $andX */
232
        $andX = $this->createMock(DoctrineAndX::class);
233
        $queryParts = [
234
            'where' => $andX,
235
        ];
236
        $andXParts = [
237
            $fieldAlias . '.id = ' . $joinAlias . '.id',
238
        ];
239
240
        $conditionsQueryBuilder->expects($this->once())
241
            ->method('getQueryParts')
242
            ->willReturn($queryParts);
243
244
        /** @var Expr&MockObject $expr */
245
        $expr = $this->createMock(Expr::class);
246
        $this->queryBuilder->expects($this->once())
247
            ->method('expr')
248
            ->willReturn($expr);
249
250
        /** @var DoctrineAndX&MockObject $conditionAndX */
251
        $conditionAndX = $this->createMock(DoctrineAndX::class);
252
        $expr->expects($this->once())
253
            ->method('andX')
254
            ->willReturn($conditionAndX);
255
256
        $conditionAndX->expects($this->once())
257
            ->method('addMultiple')
258
            ->willReturn($andXParts);
259
260
        $this->queryBuilder->expects($this->once())
261
            ->method('mergeParameters')
262
            ->with($conditionsQueryBuilder);
263
264
        $this->assertFilterJoin(
265
            $this->queryBuilder,
266
            $fieldAlias . '.' . $fieldName,
267
            $joinAlias,
268
            $conditionAndX,
269
            JoinConditionType::WITH
270
        );
271
272
        $this->filter->filter($this->queryBuilder, $this->metadata, $criteria);
273
    }
274
}
275