Completed
Pull Request — master (#781)
by Grégoire
01:46
created

ProxyQueryTest::testAddOrderedColumnsCompositeId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 23
rs 9.0856
cc 1
eloc 17
nc 1
nop 0
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\EntityManager;
20
use Doctrine\ORM\Mapping\ClassMetadataFactory;
21
use Doctrine\ORM\Mapping\ClassMetadataInfo;
22
use Doctrine\ORM\Query;
23
use Doctrine\ORM\Query\Expr\From;
24
use Doctrine\ORM\Query\Expr\OrderBy;
25
use Doctrine\ORM\Query\Expr\Select;
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\Query\FooWalker;
32
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Util\NonIntegerIdentifierTestClass;
33
use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper;
34
use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity;
35
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity;
36
37
class ProxyQueryTest extends TestCase
38
{
39
    public const DOUBLE_NAME_CLASS = DoubleNameEntity::class;
40
41
    /**
42
     * @var EntityManager
43
     */
44
    private $em;
45
46
    public static function setUpBeforeClass(): void
47
    {
48
        if (!Type::hasType('uuid')) {
49
            Type::addType('uuid', UuidType::class);
50
        }
51
    }
52
53
    protected function setUp(): void
54
    {
55
        $this->em = DoctrineTestHelper::createTestEntityManager();
56
57
        $schemaTool = new SchemaTool($this->em);
58
        $classes = [
59
            $this->em->getClassMetadata(self::DOUBLE_NAME_CLASS),
60
        ];
61
62
        try {
63
            $schemaTool->dropSchema($classes);
64
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
65
        }
66
67
        try {
68
            $schemaTool->createSchema($classes);
69
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
70
        }
71
    }
72
73
    protected function tearDown(): void
74
    {
75
        $this->em = null;
76
    }
77
78
    public function dataGetFixedQueryBuilder()
79
    {
80
        return [
81
            ['aaa', 'bbb', 'id', 'id_idx', 33, Type::INTEGER],
82
            ['aaa', 'bbb', 'associatedId', 'associatedId_idx', 33, null],
83
            ['aaa', 'bbb', 'id.value', 'id_value_idx', 33, Type::INTEGER],
84
            ['aaa', 'bbb', 'id.uuid', 'id_uuid_idx', new NonIntegerIdentifierTestClass('80fb6f91-bba1-4d35-b3d4-e06b24494e85'), UuidType::NAME],
85
        ];
86
    }
87
88
    /**
89
     * @dataProvider dataGetFixedQueryBuilder
90
     *
91
     * @param $class
92
     * @param $alias
93
     * @param $id
94
     */
95
    public function testGetFixedQueryBuilder($class, $alias, $id, $expectedId, $value, $identifierType): void
96
    {
97
        $meta = $this->createMock(ClassMetadataInfo::class);
98
        $meta->expects($this->any())
99
            ->method('getIdentifierFieldNames')
100
            ->willReturn([$id]);
101
        $meta->expects($this->any())
102
            ->method('getTypeOfField')
103
            ->willReturn($identifierType);
104
105
        $mf = $this->createMock(ClassMetadataFactory::class);
106
        $mf->expects($this->any())
107
            ->method('getMetadataFor')
108
            ->with($this->equalTo($class))
109
            ->willReturn($meta);
110
111
        $platform = $this->createMock(PostgreSqlPlatform::class);
112
113
        $conn = $this->createMock(Connection::class);
114
        $conn->expects($this->any())
115
            ->method('getDatabasePlatform')
116
            ->willReturn($platform);
117
118
        $em = $this->createMock(EntityManager::class);
119
        $em->expects($this->any())
120
            ->method('getMetadataFactory')
121
            ->willReturn($mf);
122
        $em->expects($this->any())
123
            ->method('getConnection')
124
            ->willReturn($conn);
125
126
        // NEXT MAJOR: Replace this when dropping PHP < 5.6
127
        // $q = $this->createMock('PDOStatement');
128
        $q = $this->getMockBuilder('stdClass')
129
            ->setMethods(['execute'])
130
            ->getMock();
131
        $q->expects($this->any())
132
            ->method('execute')
133
            ->willReturn([[$id => $value]]);
134
135
        $qb = $this->getMockBuilder(QueryBuilder::class)
136
            ->setConstructorArgs([$em])
137
            ->getMock();
138
        $qb->expects($this->any())
139
            ->method('getEntityManager')
140
            ->willReturn($em);
141
        $qb->expects($this->any())
142
            ->method('getQuery')
143
            ->willReturn($q);
144
        $qb->expects($this->once())
145
            ->method('setParameter')
146
            ->with($this->equalTo($expectedId), $this->equalTo([$value]));
147
        $qb->expects($this->any())
148
            ->method('getDQLPart')
149
            ->will($this->returnCallBack(function ($part) use ($class, $alias) {
150
                $parts = [
151
                    'from' => [new From($class, $alias)],
152
                    'orderBy' => [new OrderBy('whatever', 'DESC')],
153
                ];
154
155
                return $parts[$part];
156
            }));
157
        $qb->expects($this->once())
158
            ->method('addOrderBy')
159
            ->with("$alias.$id", null);
160
        $qb->expects($this->once())
161
            ->method('getRootEntities')
162
            ->willReturn([$class]);
163
        $qb->expects($this->exactly(2))
164
            ->method('getRootAliases')
165
            ->willReturn([$alias]);
166
167
        $pq = $this->getMockBuilder(ProxyQuery::class)
168
            ->setConstructorArgs([$qb])
169
            ->setMethods(['a'])
170
            ->getMock();
171
172
        /* Work */
173
174
        $pq->execute();
175
    }
176
177
    public function testAddOrderedColumns(): void
178
    {
179
        $qb = $this->em->createQueryBuilder()
180
                       ->select('o.id')
181
                       ->distinct()
182
                       ->from(self::DOUBLE_NAME_CLASS, 'o')
183
                       ->orderBy('o.name', 'ASC')
184
                       ->addOrderBy('o.name2', 'DESC');
185
186
        $pq = $this->getMockBuilder(ProxyQuery::class)
187
                   ->disableOriginalConstructor()
188
                   ->getMock();
189
190
        $reflection = new \ReflectionClass(get_class($pq));
191
        $method = $reflection->getMethod('addOrderedColumns');
192
        $method->setAccessible(true);
193
        $method->invoke($pq, $qb, []);
194
195
        $dqlPart = $qb->getDqlPart('select');
196
        $this->assertCount(3, $dqlPart);
197
        $this->assertEquals('o.id', $dqlPart[0]);
198
        $this->assertEquals('o.name', $dqlPart[1]);
199
        $this->assertEquals('o.name2', $dqlPart[2]);
200
    }
201
202
    public function testSetHint(): void
203
    {
204
        $entity1 = new DoubleNameEntity(1, 'Foo', null);
205
        $entity2 = new DoubleNameEntity(2, 'Bar', null);
206
207
        $this->em->persist($entity1);
208
        $this->em->persist($entity2);
209
        $this->em->flush();
210
211
        $qb = $this->em->createQueryBuilder()
212
                       ->select('o.id')
213
                       ->from(self::DOUBLE_NAME_CLASS, 'o');
214
215
        $pq = new ProxyQuery($qb);
216
        $pq->setHint(
217
            Query::HINT_CUSTOM_OUTPUT_WALKER,
218
            FooWalker::class
219
        );
220
        $pq->setHint('hint', 'value');
221
222
        $result = $pq->execute();
223
224
        $this->assertEquals(2, $result[0]['id']);
225
    }
226
227
    public function testAddOrderedColumnsCompositeId(): void
228
    {
229
        $qb = $this->em->createQueryBuilder()
230
            ->select('IDENTITY(o.id1) as id1, IDENTITY(o.id2) as id2')
231
            ->distinct()
232
            ->from(CompositeIntIdEntity::class, 'o')
233
            ->orderBy('o.id1', 'ASC')
234
            ->addOrderBy('o.id2', 'ASC');
235
236
        $pq = $this->createMock(ProxyQuery::class);
237
238
        $reflection = new \ReflectionClass(get_class($pq));
239
        $method = $reflection->getMethod('addOrderedColumns');
240
        $method->setAccessible(true);
241
        $method->invoke($pq, $qb, ['o.id1', 'o.id2']);
242
243
        $dqlPart = $qb->getDqlPart('select');
244
        $this->assertCount(1, $dqlPart);
245
        /** @var Select $select */
246
        $select = $dqlPart[0];
247
        $this->assertInstanceOf(Select::class, $select);
248
        $this->assertEquals('IDENTITY(o.id1) as id1, IDENTITY(o.id2) as id2', $select->getParts()[0]);
249
    }
250
}
251