3
3
namespace Test \Pager \Subscriber \Paginate \Doctrine ;
4
4
5
5
use Doctrine \DBAL \Query \QueryBuilder ;
6
+ use Doctrine \ORM \EntityManager ;
7
+ use Knp \Component \Pager \ArgumentAccess \ArgumentAccessInterface ;
8
+ use Knp \Component \Pager \Event \ItemsEvent ;
9
+ use Knp \Component \Pager \Event \Subscriber \Paginate \Doctrine \DBALQueryBuilderSubscriber ;
6
10
use PHPUnit \Framework \Attributes \Test ;
7
11
use Test \Fixture \Entity \Article ;
12
+ use Test \Fixture \Entity \Shop \Product ;
13
+ use Test \Fixture \Entity \Shop \Tag ;
8
14
use Test \Tool \BaseTestCaseORM ;
9
15
10
16
final class DBALQueryBuilderTest extends BaseTestCaseORM
@@ -31,9 +37,61 @@ public function shouldPaginateSimpleDoctrineQuery(): void
31
37
$ this ->assertEquals ('winter ' , $ items [1 ]['title ' ]);
32
38
}
33
39
40
+ #[Test]
41
+ public function shouldStripOrderByForCount (): void
42
+ {
43
+ $ this ->populate ();
44
+ $ qb = new QueryBuilder ($ this ->em ->getConnection ());
45
+ $ qb
46
+ ->select ('* ' )
47
+ ->from ('Article ' , 'a ' )
48
+ ->orderBy ('a.title ' );
49
+
50
+ $ event = new ItemsEvent (0 , 2 , $ this ->mockArgumentAccess ());
51
+ $ event ->target = $ qb ;
52
+
53
+ $ this ->queryAnalyzer ->enable ();
54
+ $ service = new DBALQueryBuilderSubscriber ($ this ->em ->getConnection ());
55
+ $ service ->items ($ event );
56
+ $ this ->queryAnalyzer ->disable ();
57
+ $ countQuery = null ;
58
+ foreach ($ this ->queryAnalyzer ->getExecutedQueries () as $ query ) {
59
+ $ query = strtolower ($ query );
60
+ if (str_contains ($ query , 'count(*) ' )) {
61
+ $ countQuery = $ query ;
62
+ break ;
63
+ }
64
+ }
65
+
66
+ $ this ->assertNotNull ($ countQuery );
67
+ $ this ->assertFalse (str_contains ($ countQuery , 'order by ' ));
68
+ //Ensure original query builder is not affected by the order by removal.
69
+ $ this ->assertTrue (str_contains (strtolower ($ qb ->getSQL ()), 'order by ' ));
70
+ }
71
+
72
+ #[Test]
73
+ public function shouldWorkWithGroupBy (): void
74
+ {
75
+ $ this ->populateProducts ();
76
+ $ qb = new QueryBuilder ($ this ->em ->getConnection ());
77
+ $ qb
78
+ ->select ('p.title, count(pt.tag_id) as totalTags ' )
79
+ ->from ('Product ' , 'p ' )
80
+ ->join ('p ' , 'product_tag ' , 'pt ' , 'pt.product_id = p.id ' )
81
+ ->groupBy ('p.id ' );
82
+
83
+ $ event = new ItemsEvent (0 , 2 , $ this ->mockArgumentAccess ());
84
+ $ event ->target = $ qb ;
85
+
86
+ $ service = new DBALQueryBuilderSubscriber ($ this ->em ->getConnection ());
87
+ $ service ->items ($ event );
88
+ $ this ->assertCount (2 , $ event ->items );
89
+ $ this ->assertEquals (4 , $ event ->count );
90
+ }
91
+
34
92
protected function getUsedEntityFixtures (): array
35
93
{
36
- return [Article::class];
94
+ return [Article::class, Product::class, Tag::class ];
37
95
}
38
96
39
97
private function populate (): void
@@ -57,4 +115,61 @@ private function populate(): void
57
115
$ em ->persist ($ spring );
58
116
$ em ->flush ();
59
117
}
118
+
119
+ private function populateProducts (): void
120
+ {
121
+ $ em = $ this ->getMockSqliteEntityManager ();
122
+ $ product = new Product ();
123
+ $ product ->setTitle ('Item 1 ' );
124
+ $ product ->addTag ($ this ->createTag ($ em , 'A ' ));
125
+ $ product ->addTag ($ this ->createTag ($ em , 'B ' ));
126
+ $ product ->addTag ($ this ->createTag ($ em , 'C ' ));
127
+ $ em ->persist ($ product );
128
+
129
+ $ product = new Product ();
130
+ $ product ->setTitle ('Item 2 ' );
131
+ $ product ->addTag ($ this ->createTag ($ em , 'A ' ));
132
+ $ em ->persist ($ product );
133
+
134
+ $ product = new Product ();
135
+ $ product ->setTitle ('Item 3 ' );
136
+ $ product ->addTag ($ this ->createTag ($ em , 'A ' ));
137
+ $ product ->addTag ($ this ->createTag ($ em , 'B ' ));
138
+ $ em ->persist ($ product );
139
+
140
+ $ product = new Product ();
141
+ $ product ->setTitle ('Item 4 ' );
142
+ $ product ->addTag ($ this ->createTag ($ em , 'A ' ));
143
+ $ product ->addTag ($ this ->createTag ($ em , 'B ' ));
144
+ $ product ->addTag ($ this ->createTag ($ em , 'C ' ));
145
+ $ em ->persist ($ product );
146
+ $ em ->flush ();
147
+ $ this ->queryAnalyzer ->disable ();
148
+ }
149
+
150
+ private function createTag (EntityManager $ em , string $ name ): Tag
151
+ {
152
+ $ tag = new Tag ();
153
+ $ tag ->setName ($ name );
154
+ $ em ->persist ($ tag );
155
+
156
+ return $ tag ;
157
+ }
158
+
159
+ private function mockArgumentAccess (): ArgumentAccessInterface
160
+ {
161
+ return new class implements ArgumentAccessInterface {
162
+ public function has (string $ name ): bool
163
+ {
164
+ return false ;
165
+ }
166
+
167
+ public function get (string $ name ): string |int |float |bool |null
168
+ {
169
+ return null ;
170
+ }
171
+
172
+ public function set (string $ name , float |bool |int |string |null $ value ): void {}
173
+ };
174
+ }
60
175
}
0 commit comments