Failed Conditions
Push — master ( 2ade86...13f838 )
by Jonathan
18s
created

Tools/Pagination/LimitSubqueryOutputWalkerTest.php (7 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Doctrine\Tests\ORM\Tools\Pagination;
4
5
use Doctrine\DBAL\Platforms\MySqlPlatform;
6
use Doctrine\DBAL\Platforms\OraclePlatform;
7
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
8
use Doctrine\ORM\Query;
9
use Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker;
10
11
final class LimitSubqueryOutputWalkerTest extends PaginationTestCase
12
{
13
    public function testLimitSubquery() : void
14
    {
15
        $query = $this->entityManager->createQuery(
16
            'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a');
17
        $query->expireQueryCache(true);
18
        $limitQuery = clone $query;
19
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
20
21
        self::assertSame(
22
            "SELECT DISTINCT id_0 FROM (SELECT m0_.id AS id_0, m0_.title AS title_1, c1_.id AS id_2, a2_.id AS id_3, a2_.name AS name_4, m0_.author_id AS author_id_5, m0_.category_id AS category_id_6 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result", $limitQuery->getSQL()
23
        );
24
    }
25
26 View Code Duplication
    public function testLimitSubqueryWithSortPg() : void
27
    {
28
        $odp = $this->entityManager->getConnection()->getDatabasePlatform();
29
        $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
30
31
        $query = $this->entityManager->createQuery(
32
            'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title');
33
        $limitQuery = clone $query;
34
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
35
36
        self::assertSame(
37
            "SELECT DISTINCT id_0, MIN(sclr_5) AS dctrn_minrownum FROM (SELECT m0_.id AS id_0, m0_.title AS title_1, c1_.id AS id_2, a2_.id AS id_3, a2_.name AS name_4, ROW_NUMBER() OVER(ORDER BY m0_.title ASC) AS sclr_5, m0_.author_id AS author_id_6, m0_.category_id AS category_id_7 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC", $limitQuery->getSQL()
38
        );
39
40
        $this->entityManager->getConnection()->setDatabasePlatform($odp);
41
    }
42
43 View Code Duplication
    public function testLimitSubqueryWithScalarSortPg() : void
44
    {
45
        $odp = $this->entityManager->getConnection()->getDatabasePlatform();
46
        $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
47
48
        $query = $this->entityManager->createQuery(
49
            'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity'
50
        );
51
        $limitQuery = clone $query;
52
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
53
54
        self::assertSame(
55
            "SELECT DISTINCT id_1, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS sclr_0, u1_.id AS id_1, g0_.id AS id_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC) AS sclr_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY id_1 ORDER BY dctrn_minrownum ASC",
56
            $limitQuery->getSQL()
57
        );
58
59
        $this->entityManager->getConnection()->setDatabasePlatform($odp);
60
    }
61
62 View Code Duplication
    public function testLimitSubqueryWithMixedSortPg() : void
63
    {
64
        $odp = $this->entityManager->getConnection()->getDatabasePlatform();
65
        $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
66
67
        $query = $this->entityManager->createQuery(
68
            'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC'
69
        );
70
        $limitQuery = clone $query;
71
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
72
73
        self::assertSame(
74
            "SELECT DISTINCT id_1, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS sclr_0, u1_.id AS id_1, g0_.id AS id_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC, u1_.id DESC) AS sclr_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY id_1 ORDER BY dctrn_minrownum ASC",
75
            $limitQuery->getSQL()
76
        );
77
78
        $this->entityManager->getConnection()->setDatabasePlatform($odp);
79
    }
80
81 View Code Duplication
    public function testLimitSubqueryWithHiddenScalarSortPg() : void
82
    {
83
        $odp = $this->entityManager->getConnection()->getDatabasePlatform();
84
        $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
85
86
        $query = $this->entityManager->createQuery(
87
           'SELECT u, g, COUNT(g.id) AS hidden g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC'
88
        );
89
        $limitQuery = clone $query;
90
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
91
92
        self::assertSame(
93
            "SELECT DISTINCT id_1, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS sclr_0, u1_.id AS id_1, g0_.id AS id_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC, u1_.id DESC) AS sclr_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY id_1 ORDER BY dctrn_minrownum ASC",
94
            $limitQuery->getSQL()
95
        );
96
97
        $this->entityManager->getConnection()->setDatabasePlatform($odp);
98
    }
99
100
    public function testLimitSubqueryPg() : void
101
    {
102
        $odp = $this->entityManager->getConnection()->getDatabasePlatform();
103
        $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
104
105
        $this->testLimitSubquery();
106
107
        $this->entityManager->getConnection()->setDatabasePlatform($odp);
108
    }
109
110 View Code Duplication
    public function testLimitSubqueryWithSortOracle() : void
111
    {
112
        $odp = $this->entityManager->getConnection()->getDatabasePlatform();
113
        $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform);
114
115
        $query = $this->entityManager->createQuery(
116
            'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title');
117
        $query->expireQueryCache(true);
118
        $limitQuery = clone $query;
119
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
120
121
        self::assertSame(
122
            "SELECT DISTINCT ID_0, MIN(SCLR_5) AS dctrn_minrownum FROM (SELECT m0_.id AS ID_0, m0_.title AS TITLE_1, c1_.id AS ID_2, a2_.id AS ID_3, a2_.name AS NAME_4, ROW_NUMBER() OVER(ORDER BY m0_.title ASC) AS SCLR_5, m0_.author_id AS AUTHOR_ID_6, m0_.category_id AS CATEGORY_ID_7 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC", $limitQuery->getSQL()
123
        );
124
125
        $this->entityManager->getConnection()->setDatabasePlatform($odp);
126
    }
127
128 View Code Duplication
    public function testLimitSubqueryWithScalarSortOracle() : void
129
    {
130
        $odp = $this->entityManager->getConnection()->getDatabasePlatform();
131
        $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform);
132
133
        $query = $this->entityManager->createQuery(
134
            'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity'
135
        );
136
        $query->expireQueryCache(true);
137
        $limitQuery = clone $query;
138
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
139
140
        self::assertSame(
141
            "SELECT DISTINCT ID_1, MIN(SCLR_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS SCLR_0, u1_.id AS ID_1, g0_.id AS ID_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC) AS SCLR_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY ID_1 ORDER BY dctrn_minrownum ASC",
142
            $limitQuery->getSQL()
143
        );
144
145
        $this->entityManager->getConnection()->setDatabasePlatform($odp);
146
    }
147
148 View Code Duplication
    public function testLimitSubqueryWithMixedSortOracle() : void
149
    {
150
        $odp = $this->entityManager->getConnection()->getDatabasePlatform();
151
        $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform);
152
153
        $query = $this->entityManager->createQuery(
154
            'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC'
155
        );
156
        $query->expireQueryCache(true);
157
        $limitQuery = clone $query;
158
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
159
160
        self::assertSame(
161
            "SELECT DISTINCT ID_1, MIN(SCLR_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS SCLR_0, u1_.id AS ID_1, g0_.id AS ID_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC, u1_.id DESC) AS SCLR_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY ID_1 ORDER BY dctrn_minrownum ASC",
162
            $limitQuery->getSQL()
163
        );
164
165
        $this->entityManager->getConnection()->setDatabasePlatform($odp);
166
    }
167
168 View Code Duplication
    public function testLimitSubqueryOracle() : void
169
    {
170
        $odp = $this->entityManager->getConnection()->getDatabasePlatform();
171
        $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform);
172
173
        $query = $this->entityManager->createQuery(
174
            'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a');
175
        $query->expireQueryCache(true);
176
        $limitQuery = clone $query;
177
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
178
179
        self::assertSame(
180
            "SELECT DISTINCT ID_0 FROM (SELECT m0_.id AS ID_0, m0_.title AS TITLE_1, c1_.id AS ID_2, a2_.id AS ID_3, a2_.name AS NAME_4, m0_.author_id AS AUTHOR_ID_5, m0_.category_id AS CATEGORY_ID_6 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result", $limitQuery->getSQL()
181
        );
182
183
        $this->entityManager->getConnection()->setDatabasePlatform($odp);
184
    }
185
186 View Code Duplication
    public function testCountQueryMixedResultsWithName() : void
187
    {
188
        $query = $this->entityManager->createQuery(
189
            'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a');
190
        $limitQuery = clone $query;
191
        $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
192
193
        self::assertSame(
194
            "SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, sum(a0_.name) AS sclr_2 FROM Author a0_) dctrn_result", $limitQuery->getSQL()
195
        );
196
    }
197
198
    /**
199
     * @group DDC-3336
200
     */
201 View Code Duplication
    public function testCountQueryWithArithmeticOrderByCondition() : void
202
    {
203
        $query = $this->entityManager->createQuery(
204
            'SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY (1 - 1000) * 1 DESC'
205
        );
206
        $this->entityManager->getConnection()->setDatabasePlatform(new MySqlPlatform());
207
208
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
209
210
        $this->assertSame(
211
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, (1 - 1000) * 1 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1 FROM Author a0_) dctrn_result_inner ORDER BY (1 - 1000) * 1 DESC) dctrn_result',
212
            $query->getSQL()
213
        );
214
    }
215
216 View Code Duplication
    public function testCountQueryWithComplexScalarOrderByItem() : void
217
    {
218
        $query = $this->entityManager->createQuery(
219
            'SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Avatar a ORDER BY a.image_height * a.image_width DESC'
220
        );
221
        $this->entityManager->getConnection()->setDatabasePlatform(new MySqlPlatform());
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Doctrine\DBAL\Connection as the method setDatabasePlatform() does only exist in the following sub-classes of Doctrine\DBAL\Connection: Doctrine\Tests\Mocks\ConnectionMock. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
222
223
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
224
225
        $this->assertSame(
226
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, image_height_2 * image_width_3 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.image_height AS image_height_2, a0_.image_width AS image_width_3, a0_.image_alt_desc AS image_alt_desc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result_inner ORDER BY image_height_2 * image_width_3 DESC) dctrn_result',
227
            $query->getSQL()
228
        );
229
    }
230
231 View Code Duplication
    public function testCountQueryWithComplexScalarOrderByItemJoined() : void
232
    {
233
        $query = $this->entityManager->createQuery(
234
            'SELECT u FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.avatar a ORDER BY a.image_height * a.image_width DESC'
235
        );
236
        $this->entityManager->getConnection()->setDatabasePlatform(new MySqlPlatform());
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Doctrine\DBAL\Connection as the method setDatabasePlatform() does only exist in the following sub-classes of Doctrine\DBAL\Connection: Doctrine\Tests\Mocks\ConnectionMock. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
237
238
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
239
240
        $this->assertSame(
241
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, image_height_1 * image_width_2 FROM (SELECT u0_.id AS id_0, a1_.image_height AS image_height_1, a1_.image_width AS image_width_2, a1_.user_id AS user_id_3 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result_inner ORDER BY image_height_1 * image_width_2 DESC) dctrn_result',
242
            $query->getSQL()
243
        );
244
    }
245
246 View Code Duplication
    public function testCountQueryWithComplexScalarOrderByItemJoinedWithPartial() : void
247
    {
248
        $query = $this->entityManager->createQuery(
249
            'SELECT u, partial a.{id, image_alt_desc} FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.avatar a ORDER BY a.image_height * a.image_width DESC'
250
        );
251
        $this->entityManager->getConnection()->setDatabasePlatform(new MySqlPlatform());
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Doctrine\DBAL\Connection as the method setDatabasePlatform() does only exist in the following sub-classes of Doctrine\DBAL\Connection: Doctrine\Tests\Mocks\ConnectionMock. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
252
253
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
254
255
        $this->assertSame(
256
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, image_height_3 * image_width_4 FROM (SELECT u0_.id AS id_0, a1_.id AS id_1, a1_.image_alt_desc AS image_alt_desc_2, a1_.image_height AS image_height_3, a1_.image_width AS image_width_4, a1_.user_id AS user_id_5 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result_inner ORDER BY image_height_3 * image_width_4 DESC) dctrn_result',
257
            $query->getSQL()
258
        );
259
    }
260
261 View Code Duplication
    public function testCountQueryWithComplexScalarOrderByItemOracle() : void
262
    {
263
        $query = $this->entityManager->createQuery(
264
            'SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Avatar a ORDER BY a.image_height * a.image_width DESC'
265
        );
266
        $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform());
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Doctrine\DBAL\Connection as the method setDatabasePlatform() does only exist in the following sub-classes of Doctrine\DBAL\Connection: Doctrine\Tests\Mocks\ConnectionMock. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
267
268
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
269
270
        $this->assertSame(
271
            'SELECT DISTINCT ID_0, MIN(SCLR_5) AS dctrn_minrownum FROM (SELECT a0_.id AS ID_0, a0_.image AS IMAGE_1, a0_.image_height AS IMAGE_HEIGHT_2, a0_.image_width AS IMAGE_WIDTH_3, a0_.image_alt_desc AS IMAGE_ALT_DESC_4, ROW_NUMBER() OVER(ORDER BY a0_.image_height * a0_.image_width DESC) AS SCLR_5, a0_.user_id AS USER_ID_6 FROM Avatar a0_) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC',
272
            $query->getSQL()
273
        );
274
    }
275
276
    /**
277
     * @group DDC-3434
278
     */
279 View Code Duplication
    public function testLimitSubqueryWithHiddenSelectionInOrderBy() : void
280
    {
281
        $query = $this->entityManager->createQuery(
282
            'SELECT a, a.name AS HIDDEN ord FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY ord DESC'
283
        );
284
285
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
286
287
        self::assertSame(
288
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, name_2 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, a0_.name AS name_2 FROM Author a0_) dctrn_result_inner ORDER BY name_2 DESC) dctrn_result',
289
            $query->getSQL()
290
        );
291
    }
292
293 View Code Duplication
    public function testLimitSubqueryWithColumnWithSortDirectionInName() : void
294
    {
295
        $query = $this->entityManager->createQuery(
296
            'SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Avatar a ORDER BY a.image_alt_desc DESC'
297
        );
298
        $this->entityManager->getConnection()->setDatabasePlatform(new MySqlPlatform());
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Doctrine\DBAL\Connection as the method setDatabasePlatform() does only exist in the following sub-classes of Doctrine\DBAL\Connection: Doctrine\Tests\Mocks\ConnectionMock. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
299
300
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
301
302
        $this->assertSame(
303
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, image_alt_desc_4 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.image_height AS image_height_2, a0_.image_width AS image_width_3, a0_.image_alt_desc AS image_alt_desc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result_inner ORDER BY image_alt_desc_4 DESC) dctrn_result',
304
            $query->getSQL()
305
        );
306
    }
307
308 View Code Duplication
    public function testLimitSubqueryWithOrderByInnerJoined() : void
309
    {
310
        $query = $this->entityManager->createQuery(
311
            'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost b JOIN b.author a ORDER BY a.name ASC'
312
        );
313
314
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
315
316
        self::assertSame(
317
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, name_1 FROM (SELECT b0_.id AS id_0, a1_.name AS name_1, b0_.author_id AS author_id_2, b0_.category_id AS category_id_3 FROM BlogPost b0_ INNER JOIN Author a1_ ON b0_.author_id = a1_.id) dctrn_result_inner ORDER BY name_1 ASC) dctrn_result',
318
            $query->getSQL()
319
        );
320
    }
321
322 View Code Duplication
    public function testLimitSubqueryWithOrderByAndSubSelectInWhereClauseMySql() : void
323
    {
324
        $this->entityManager->getConnection()->setDatabasePlatform(new MySqlPlatform());
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Doctrine\DBAL\Connection as the method setDatabasePlatform() does only exist in the following sub-classes of Doctrine\DBAL\Connection: Doctrine\Tests\Mocks\ConnectionMock. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
325
        $query = $this->entityManager->createQuery(
326
            'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost b
327
WHERE  ((SELECT COUNT(simple.id) FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost simple) = 1)
328
ORDER BY b.id DESC'
329
        );
330
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
331
332
        self::assertSame(
333
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.author_id AS author_id_1, b0_.category_id AS category_id_2 FROM BlogPost b0_ WHERE ((SELECT COUNT(b1_.id) AS sclr_3 FROM BlogPost b1_) = 1)) dctrn_result_inner ORDER BY id_0 DESC) dctrn_result',
334
            $query->getSQL()
335
        );
336
    }
337
338 View Code Duplication
    public function testLimitSubqueryWithOrderByAndSubSelectInWhereClausePgSql() : void
339
    {
340
        $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform());
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Doctrine\DBAL\Connection as the method setDatabasePlatform() does only exist in the following sub-classes of Doctrine\DBAL\Connection: Doctrine\Tests\Mocks\ConnectionMock. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
341
        $query = $this->entityManager->createQuery(
342
            'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost b
343
WHERE  ((SELECT COUNT(simple.id) FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost simple) = 1)
344
ORDER BY b.id DESC'
345
        );
346
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
347
348
        self::assertSame(
349
            'SELECT DISTINCT id_0, MIN(sclr_1) AS dctrn_minrownum FROM (SELECT b0_.id AS id_0, ROW_NUMBER() OVER(ORDER BY b0_.id DESC) AS sclr_1, b0_.author_id AS author_id_2, b0_.category_id AS category_id_3 FROM BlogPost b0_ WHERE ((SELECT COUNT(b1_.id) AS sclr_4 FROM BlogPost b1_) = 1)) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC',
350
            $query->getSQL()
351
        );
352
    }
353
354
    /**
355
     * This tests ordering by property that has the 'declared' field.
356
     */
357 View Code Duplication
    public function testLimitSubqueryOrderByFieldFromMappedSuperclass() : void
358
    {
359
        $this->entityManager->getConnection()->setDatabasePlatform(new MySqlPlatform());
360
361
        // now use the third one in query
362
        $query = $this->entityManager->createQuery(
363
            'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\Banner b ORDER BY b.id DESC'
364
        );
365
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
366
367
        self::assertSame(
368
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.name AS name_1 FROM Banner b0_) dctrn_result_inner ORDER BY id_0 DESC) dctrn_result',
369
            $query->getSQL()
370
        );
371
    }
372
373
    /**
374
     * Tests order by on a subselect expression (mysql).
375
     */
376 View Code Duplication
    public function testLimitSubqueryOrderBySubSelectOrderByExpression() : void
377
    {
378
        $this->entityManager->getConnection()->setDatabasePlatform(new MySqlPlatform());
379
380
        $query = $this->entityManager->createQuery(
381
            'SELECT a,
382
                (
383
                    SELECT MIN(bp.title)
384
                    FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost bp
385
                    WHERE bp.author = a
386
                ) AS HIDDEN first_blog_post
387
            FROM Doctrine\Tests\ORM\Tools\Pagination\Author a
388
            ORDER BY first_blog_post DESC'
389
        );
390
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
391
392
        self::assertSame(
393
            'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, sclr_2 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS sclr_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2 FROM Author a0_) dctrn_result_inner ORDER BY sclr_2 DESC) dctrn_result',
394
            $query->getSQL()
395
        );
396
    }
397
398
    /**
399
     * Tests order by on a subselect expression invoking RowNumberOverFunction (postgres).
400
     */
401 View Code Duplication
    public function testLimitSubqueryOrderBySubSelectOrderByExpressionPg() : void
402
    {
403
        $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform());
404
405
        $query = $this->entityManager->createQuery(
406
            'SELECT a,
407
                (
408
                    SELECT MIN(bp.title)
409
                    FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost bp
410
                    WHERE bp.author = a
411
                ) AS HIDDEN first_blog_post
412
            FROM Doctrine\Tests\ORM\Tools\Pagination\Author a
413
            ORDER BY first_blog_post DESC'
414
        );
415
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
416
417
        self::assertSame(
418
            'SELECT DISTINCT id_0, MIN(sclr_4) AS dctrn_minrownum FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS sclr_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS sclr_5 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS sclr_4 FROM Author a0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC',
419
            $query->getSQL()
420
        );
421
    }
422
423
    /**
424
     * Tests order by on a subselect expression invoking RowNumberOverFunction (oracle).
425
     */
426 View Code Duplication
    public function testLimitSubqueryOrderBySubSelectOrderByExpressionOracle() : void
427
    {
428
        $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform());
429
430
        $query = $this->entityManager->createQuery(
431
            'SELECT a,
432
                (
433
                    SELECT MIN(bp.title)
434
                    FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost bp
435
                    WHERE bp.author = a
436
                ) AS HIDDEN first_blog_post
437
            FROM Doctrine\Tests\ORM\Tools\Pagination\Author a
438
            ORDER BY first_blog_post DESC'
439
        );
440
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
441
442
        self::assertSame(
443
            'SELECT DISTINCT ID_0, MIN(SCLR_4) AS dctrn_minrownum FROM (SELECT a0_.id AS ID_0, a0_.name AS NAME_1, (SELECT MIN(m1_.title) AS SCLR_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS SCLR_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS SCLR_5 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS SCLR_4 FROM Author a0_) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC',
444
            $query->getSQL()
445
        );
446
    }
447
}
448
449