ProxyQueryTest   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 237
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 11
dl 0
loc 237
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A testSetHint() 0 24 1
A testSortOrderValidatesItsInput() 0 9 1
A validSortOrders() 0 11 1
A testItAllowsSortOrdersWithStrangeCase() 0 6 1
A setUpBeforeClass() 0 6 2
A setUp() 0 19 3
A tearDown() 0 4 1
A dataGetFixedQueryBuilder() 0 9 1
B testGetFixedQueryBuilder() 0 87 1
A testExecuteWithOrderBy() 0 39 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\DoctrineORMAdminBundle\Tests\Datagrid;
15
16
use Doctrine\DBAL\Connection;
17
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
18
use Doctrine\DBAL\Types\Type;
19
use Doctrine\ORM\AbstractQuery;
20
use Doctrine\ORM\EntityManager;
21
use Doctrine\ORM\Mapping\ClassMetadata;
22
use Doctrine\ORM\Mapping\ClassMetadataFactory;
23
use Doctrine\ORM\Query;
24
use Doctrine\ORM\Query\Expr\From;
25
use Doctrine\ORM\Query\Expr\OrderBy;
26
use Doctrine\ORM\QueryBuilder;
27
use Doctrine\ORM\Tools\SchemaTool;
28
use PHPUnit\Framework\TestCase;
29
use Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery;
30
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\UuidType;
31
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\DoubleNameEntity;
32
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Query\FooWalker;
33
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Util\NonIntegerIdentifierTestClass;
34
use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper;
35
36
class ProxyQueryTest extends TestCase
37
{
38
    /**
39
     * @var EntityManager
40
     */
41
    private $em;
42
43
    public static function setUpBeforeClass(): void
44
    {
45
        if (!Type::hasType('uuid')) {
46
            Type::addType('uuid', UuidType::class);
47
        }
48
    }
49
50
    protected function setUp(): void
51
    {
52
        $this->em = DoctrineTestHelper::createTestEntityManager();
53
54
        $schemaTool = new SchemaTool($this->em);
55
        $classes = [
56
            $this->em->getClassMetadata(DoubleNameEntity::class),
57
        ];
58
59
        try {
60
            $schemaTool->dropSchema($classes);
61
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
62
        }
63
64
        try {
65
            $schemaTool->createSchema($classes);
66
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
67
        }
68
    }
69
70
    protected function tearDown(): void
71
    {
72
        $this->em = null;
73
    }
74
75
    public function dataGetFixedQueryBuilder()
76
    {
77
        return [
78
            ['aaa', 'bbb', 'id', 'id_idx', 33, Type::INTEGER, true],
0 ignored issues
show
Deprecated Code introduced by
The constant Doctrine\DBAL\Types\Type::INTEGER has been deprecated with message: Use {@see Types::INTEGER} instead.

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
79
            ['aaa', 'bbb', 'associatedId', 'associatedId_idx', 33, null, true],
80
            ['aaa', 'bbb', 'id.value', 'id_value_idx', 33, Type::INTEGER, false],
0 ignored issues
show
Deprecated Code introduced by
The constant Doctrine\DBAL\Types\Type::INTEGER has been deprecated with message: Use {@see Types::INTEGER} instead.

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
81
            ['aaa', 'bbb', 'id.uuid', 'id_uuid_idx', new NonIntegerIdentifierTestClass('80fb6f91-bba1-4d35-b3d4-e06b24494e85'), UuidType::NAME, false],
82
        ];
83
    }
84
85
    /**
86
     * @dataProvider dataGetFixedQueryBuilder
87
     */
88
    public function testGetFixedQueryBuilder($class, $alias, $id, $expectedId, $value, $identifierType, $distinct): void
89
    {
90
        $meta = $this->createMock(ClassMetadata::class);
91
        $meta->expects($this->any())
92
            ->method('getIdentifierFieldNames')
93
            ->willReturn([$id]);
94
        $meta->expects($this->any())
95
            ->method('getTypeOfField')
96
            ->willReturn($identifierType);
97
98
        $mf = $this->createMock(ClassMetadataFactory::class);
99
        $mf->expects($this->any())
100
            ->method('getMetadataFor')
101
            ->with($this->equalTo($class))
102
            ->willReturn($meta);
103
104
        $platform = $this->createMock(PostgreSqlPlatform::class);
105
106
        $conn = $this->createMock(Connection::class);
107
        $conn->expects($this->any())
108
            ->method('getDatabasePlatform')
109
            ->willReturn($platform);
110
111
        $em = $this->createMock(EntityManager::class);
112
        $em->expects($this->any())
113
            ->method('getMetadataFactory')
114
            ->willReturn($mf);
115
        $em->expects($this->any())
116
            ->method('getConnection')
117
            ->willReturn($conn);
118
119
        $q = $this->getMockBuilder(AbstractQuery::class)
120
            ->disableOriginalConstructor()
121
            ->setMethods(['setHint', 'execute'])
122
            ->getMockForAbstractClass();
123
        $q->expects($this->once())
124
           ->method('setHint')
125
           ->willReturn($q);
126
        $q->expects($this->any())
127
            ->method('execute')
128
            ->willReturn([[$id => $value]]);
129
130
        $qb = $this->getMockBuilder(QueryBuilder::class)
131
            ->setConstructorArgs([$em])
132
            ->getMock();
133
        $qb->expects($this->once())
134
            ->method('distinct')
135
            ->with($this->equalTo($distinct));
136
        $qb->expects($this->any())
137
            ->method('getEntityManager')
138
            ->willReturn($em);
139
        $qb->expects($this->any())
140
            ->method('getQuery')
141
            ->willReturn($q);
142
        $qb->expects($this->once())
143
            ->method('setParameter')
144
            ->with($this->equalTo($expectedId), $this->equalTo([$value]));
145
        $qb->expects($this->any())
146
            ->method('getDQLPart')
147
            ->willReturnCallback(static function ($part) use ($class, $alias) {
148
                $parts = [
149
                    'from' => [new From($class, $alias)],
150
                    'orderBy' => [new OrderBy('whatever', 'DESC')],
151
                ];
152
153
                return $parts[$part];
154
            });
155
        $qb->expects($this->once())
156
            ->method('addOrderBy')
157
            ->with("$alias.$id", null);
158
        $qb->expects($this->once())
159
            ->method('getRootEntities')
160
            ->willReturn([$class]);
161
        $qb->expects($this->exactly(2))
162
            ->method('getRootAliases')
163
            ->willReturn([$alias]);
164
165
        $pq = $this->getMockBuilder(ProxyQuery::class)
166
            ->setConstructorArgs([$qb])
167
            ->setMethods(['a'])
168
            ->getMock();
169
170
        $pq->setDistinct($distinct);
171
172
        /* Work */
173
        $pq->execute();
174
    }
175
176
    public function testSetHint(): void
177
    {
178
        $entity1 = new DoubleNameEntity(1, 'Foo', null);
179
        $entity2 = new DoubleNameEntity(2, 'Bar', null);
180
181
        $this->em->persist($entity1);
182
        $this->em->persist($entity2);
183
        $this->em->flush();
184
185
        $qb = $this->em->createQueryBuilder()
186
            ->select('o.id')
187
            ->from(DoubleNameEntity::class, 'o');
188
189
        $pq = new ProxyQuery($qb);
190
        $pq->setHint(
191
            Query::HINT_CUSTOM_OUTPUT_WALKER,
192
            FooWalker::class
193
        );
194
        $pq->setHint('hint', 'value');
195
196
        $result = $pq->execute();
197
198
        $this->assertSame(2, $result[0]['id']);
199
    }
200
201
    public function testSortOrderValidatesItsInput(): void
202
    {
203
        $query = new ProxyQuery($this->em->createQueryBuilder());
204
        $this->expectException(\InvalidArgumentException::class);
205
        $this->expectExceptionMessage(
206
            '"ASC,injection" is not a valid sort order, valid values are "ASC, DESC"'
207
        );
208
        $query->setSortOrder('ASC,injection');
209
    }
210
211
    public function validSortOrders()
212
    {
213
        return [
214
            ['ASC'],
215
            ['DESC'],
216
            ['asc'],
217
            ['desc'],
218
            ['AsC'],
219
            ['deSc'],
220
        ];
221
    }
222
223
    /**
224
     * @dataProvider validSortOrders
225
     */
226
    public function testItAllowsSortOrdersWithStrangeCase($validValue): void
227
    {
228
        $query = new ProxyQuery($this->em->createQueryBuilder());
229
        $query->setSortOrder($validValue);
230
        $this->assertSame($validValue, $query->getSortOrder());
231
    }
232
233
    public function testExecuteWithOrderBy(): void
234
    {
235
        $entity1 = new DoubleNameEntity(1, 'Foo', 'Bar');
236
        $entity2 = new DoubleNameEntity(2, 'Bar', 'Bar');
237
        $entity3 = new DoubleNameEntity(3, 'Bar', 'Foo');
238
239
        $this->em->persist($entity1);
240
        $this->em->persist($entity2);
241
        $this->em->persist($entity3);
242
        $this->em->flush();
243
244
        $query = new ProxyQuery(
245
            $this->em->createQueryBuilder()->select('o.id')->from(DoubleNameEntity::class, 'o')
246
        );
247
        $query->setSortBy([], ['fieldName' => 'name2'])->setSortOrder('ASC');
248
249
        $this->assertSame(
250
            [
251
                ['id' => 1],
252
                ['id' => 2],
253
                ['id' => 3],
254
            ],
255
            $query->execute()
256
        );
257
258
        $query2 = new ProxyQuery(
259
            $this->em->createQueryBuilder()->select('o.id')->from(DoubleNameEntity::class, 'o')->addOrderBy('o.name')
260
        );
261
        $query2->setSortBy([], ['fieldName' => 'name2'])->setSortOrder('ASC');
262
263
        $this->assertSame(
264
            [
265
                ['id' => 2],
266
                ['id' => 1],
267
                ['id' => 3],
268
            ],
269
            $query2->execute()
270
        );
271
    }
272
}
273