1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Doctrine\Tests\ORM\Query; |
6
|
|
|
|
7
|
|
|
use DateTime; |
8
|
|
|
use Doctrine\Common\Cache\ArrayCache; |
9
|
|
|
use Doctrine\Common\Collections\ArrayCollection; |
10
|
|
|
use Doctrine\DBAL\ParameterType; |
11
|
|
|
use Doctrine\DBAL\Types\Type; |
12
|
|
|
use Doctrine\ORM\Internal\Hydration\IterableResult; |
13
|
|
|
use Doctrine\ORM\Query\Parameter; |
14
|
|
|
use Doctrine\ORM\Query\QueryException; |
15
|
|
|
use Doctrine\ORM\UnitOfWork; |
16
|
|
|
use Doctrine\Tests\Mocks\DriverConnectionMock; |
17
|
|
|
use Doctrine\Tests\Mocks\EntityManagerMock; |
18
|
|
|
use Doctrine\Tests\Mocks\StatementArrayMock; |
19
|
|
|
use Doctrine\Tests\Models\CMS\CmsAddress; |
20
|
|
|
use Doctrine\Tests\Models\CMS\CmsUser; |
21
|
|
|
use Doctrine\Tests\Models\Generic\DateTimeModel; |
22
|
|
|
use Doctrine\Tests\OrmTestCase; |
23
|
|
|
|
24
|
|
|
class QueryTest extends OrmTestCase |
25
|
|
|
{ |
26
|
|
|
/** @var EntityManagerMock */ |
27
|
|
|
protected $em; |
28
|
|
|
|
29
|
|
|
protected function setUp() : void |
30
|
|
|
{ |
31
|
|
|
$this->em = $this->getTestEntityManager(); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
public function testGetParameters() : void |
35
|
|
|
{ |
36
|
|
|
$query = $this->em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1'); |
37
|
|
|
|
38
|
|
|
$parameters = new ArrayCollection(); |
39
|
|
|
|
40
|
|
|
self::assertEquals($parameters, $query->getParameters()); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
public function testGetParametersHasSomeAlready() : void |
44
|
|
|
{ |
45
|
|
|
$query = $this->em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1'); |
46
|
|
|
$query->setParameter(2, 84); |
47
|
|
|
|
48
|
|
|
$parameters = new ArrayCollection(); |
49
|
|
|
$parameters->add(new Parameter(2, 84)); |
50
|
|
|
|
51
|
|
|
self::assertEquals($parameters, $query->getParameters()); |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
public function testSetParameters() : void |
55
|
|
|
{ |
56
|
|
|
$query = $this->em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1'); |
57
|
|
|
|
58
|
|
|
$parameters = new ArrayCollection(); |
59
|
|
|
$parameters->add(new Parameter(1, 'foo')); |
60
|
|
|
$parameters->add(new Parameter(2, 'bar')); |
61
|
|
|
|
62
|
|
|
$query->setParameters($parameters); |
63
|
|
|
|
64
|
|
|
self::assertEquals($parameters, $query->getParameters()); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
public function testFree() : void |
68
|
|
|
{ |
69
|
|
|
$query = $this->em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1'); |
70
|
|
|
$query->setParameter(2, 84, ParameterType::INTEGER); |
71
|
|
|
|
72
|
|
|
$query->free(); |
73
|
|
|
|
74
|
|
|
self::assertCount(0, $query->getParameters()); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
public function testClone() : void |
78
|
|
|
{ |
79
|
|
|
$dql = 'select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1'; |
80
|
|
|
|
81
|
|
|
$query = $this->em->createQuery($dql); |
82
|
|
|
$query->setParameter(2, 84, ParameterType::INTEGER); |
83
|
|
|
$query->setHint('foo', 'bar'); |
84
|
|
|
|
85
|
|
|
$cloned = clone $query; |
86
|
|
|
|
87
|
|
|
self::assertEquals($dql, $cloned->getDQL()); |
88
|
|
|
self::assertCount(0, $cloned->getParameters()); |
89
|
|
|
self::assertFalse($cloned->getHint('foo')); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
public function testFluentQueryInterface() : void |
93
|
|
|
{ |
94
|
|
|
$q = $this->em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a'); |
95
|
|
|
$q2 = $q->expireQueryCache(true) |
96
|
|
|
->setQueryCacheLifetime(3600) |
97
|
|
|
->setQueryCacheDriver(null) |
98
|
|
|
->expireResultCache(true) |
99
|
|
|
->setHint('foo', 'bar') |
100
|
|
|
->setHint('bar', 'baz') |
101
|
|
|
->setParameter(1, 'bar') |
102
|
|
|
->setParameters(new ArrayCollection([new Parameter(2, 'baz')])) |
103
|
|
|
->setResultCacheDriver(null) |
104
|
|
|
->setResultCacheId('foo') |
105
|
|
|
->setDQL('foo') |
106
|
|
|
->setFirstResult(10) |
107
|
|
|
->setMaxResults(10); |
108
|
|
|
|
109
|
|
|
self::assertSame($q2, $q); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @group DDC-968 |
114
|
|
|
*/ |
115
|
|
|
public function testHints() : void |
116
|
|
|
{ |
117
|
|
|
$q = $this->em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a'); |
118
|
|
|
$q->setHint('foo', 'bar')->setHint('bar', 'baz'); |
119
|
|
|
|
120
|
|
|
self::assertEquals('bar', $q->getHint('foo')); |
121
|
|
|
self::assertEquals('baz', $q->getHint('bar')); |
122
|
|
|
self::assertEquals(['foo' => 'bar', 'bar' => 'baz'], $q->getHints()); |
123
|
|
|
self::assertTrue($q->hasHint('foo')); |
124
|
|
|
self::assertFalse($q->hasHint('barFooBaz')); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @group DDC-1588 |
129
|
|
|
*/ |
130
|
|
|
public function testQueryDefaultResultCache() : void |
131
|
|
|
{ |
132
|
|
|
$this->em->getConfiguration()->setResultCacheImpl(new ArrayCache()); |
133
|
|
|
$q = $this->em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a'); |
134
|
|
|
$q->useResultCache(true); |
135
|
|
|
self::assertSame($this->em->getConfiguration()->getResultCacheImpl(), $q->getQueryCacheProfile()->getResultCacheDriver()); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* @expectedException Doctrine\ORM\Query\QueryException |
140
|
|
|
*/ |
141
|
|
|
public function testIterateWithNoDistinctAndWrongSelectClause() : void |
142
|
|
|
{ |
143
|
|
|
$q = $this->em->createQuery('select u, a from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a'); |
144
|
|
|
$q->iterate(); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* @expectedException Doctrine\ORM\Query\QueryException |
149
|
|
|
*/ |
150
|
|
|
public function testIterateWithNoDistinctAndWithValidSelectClause() : void |
151
|
|
|
{ |
152
|
|
|
$q = $this->em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a'); |
153
|
|
|
$q->iterate(); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
public function testIterateWithDistinct() : void |
157
|
|
|
{ |
158
|
|
|
$q = $this->em->createQuery('SELECT DISTINCT u from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a'); |
159
|
|
|
|
160
|
|
|
self::assertInstanceOf(IterableResult::class, $q->iterate()); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* @group DDC-1697 |
165
|
|
|
*/ |
166
|
|
|
public function testCollectionParameters() : void |
167
|
|
|
{ |
168
|
|
|
$cities = [ |
169
|
|
|
0 => 'Paris', |
170
|
|
|
3 => 'Canne', |
171
|
|
|
9 => 'St Julien', |
172
|
|
|
]; |
173
|
|
|
|
174
|
|
|
$query = $this->em |
175
|
|
|
->createQuery('SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.city IN (:cities)') |
176
|
|
|
->setParameter('cities', $cities); |
177
|
|
|
|
178
|
|
|
$parameters = $query->getParameters(); |
179
|
|
|
$parameter = $parameters->first(); |
180
|
|
|
|
181
|
|
|
self::assertEquals('cities', $parameter->getName()); |
182
|
|
|
self::assertEquals($cities, $parameter->getValue()); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* @group DDC-2224 |
187
|
|
|
*/ |
188
|
|
|
public function testProcessParameterValueClassMetadata() : void |
189
|
|
|
{ |
190
|
|
|
$query = $this->em->createQuery('SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.city IN (:cities)'); |
191
|
|
|
self::assertEquals( |
192
|
|
|
CmsAddress::class, |
193
|
|
|
$query->processParameterValue($this->em->getClassMetadata(CmsAddress::class)) |
194
|
|
|
); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
public function testProcessParameterValueObject() : void |
198
|
|
|
{ |
199
|
|
|
$query = $this->em->createQuery('SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.user = :user'); |
200
|
|
|
$user = new CmsUser(); |
201
|
|
|
$user->id = 12345; |
202
|
|
|
|
203
|
|
|
self::assertSame( |
204
|
|
|
12345, |
205
|
|
|
$query->processParameterValue($user) |
206
|
|
|
); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
public function testProcessParameterValueNull() : void |
210
|
|
|
{ |
211
|
|
|
$query = $this->em->createQuery('SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.user = :user'); |
212
|
|
|
|
213
|
|
|
self::assertNull($query->processParameterValue(null)); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
public function testDefaultQueryHints() : void |
217
|
|
|
{ |
218
|
|
|
$config = $this->em->getConfiguration(); |
219
|
|
|
$defaultHints = [ |
220
|
|
|
'hint_name_1' => 'hint_value_1', |
221
|
|
|
'hint_name_2' => 'hint_value_2', |
222
|
|
|
'hint_name_3' => 'hint_value_3', |
223
|
|
|
]; |
224
|
|
|
|
225
|
|
|
$config->setDefaultQueryHints($defaultHints); |
226
|
|
|
$query = $this->em->createQuery(); |
227
|
|
|
self::assertSame($config->getDefaultQueryHints(), $query->getHints()); |
228
|
|
|
$this->em->getConfiguration()->setDefaultQueryHint('hint_name_1', 'hint_another_value_1'); |
229
|
|
|
self::assertNotSame($config->getDefaultQueryHints(), $query->getHints()); |
230
|
|
|
$q2 = clone $query; |
231
|
|
|
self::assertSame($config->getDefaultQueryHints(), $q2->getHints()); |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* @group DDC-3714 |
236
|
|
|
*/ |
237
|
|
|
public function testResultCacheCaching() : void |
238
|
|
|
{ |
239
|
|
|
$this->em->getConfiguration()->setResultCacheImpl(new ArrayCache()); |
240
|
|
|
$this->em->getConfiguration()->setQueryCacheImpl(new ArrayCache()); |
241
|
|
|
/** @var DriverConnectionMock $driverConnectionMock */ |
242
|
|
|
$driverConnectionMock = $this->em->getConnection()->getWrappedConnection(); |
243
|
|
|
$stmt = new StatementArrayMock([ |
244
|
|
|
['c0' => 1], |
245
|
|
|
]); |
246
|
|
|
$driverConnectionMock->setStatementMock($stmt); |
247
|
|
|
$res = $this->em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u') |
248
|
|
|
->useQueryCache(true) |
249
|
|
|
->useResultCache(true, 60) |
250
|
|
|
//let it cache |
251
|
|
|
->getResult(); |
252
|
|
|
|
253
|
|
|
self::assertCount(1, $res); |
254
|
|
|
|
255
|
|
|
$driverConnectionMock->setStatementMock(null); |
256
|
|
|
|
257
|
|
|
$res = $this->em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u') |
258
|
|
|
->useQueryCache(true) |
259
|
|
|
->useResultCache(false) |
260
|
|
|
->getResult(); |
261
|
|
|
self::assertCount(0, $res); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* @group DDC-3741 |
266
|
|
|
*/ |
267
|
|
|
public function testSetHydrationCacheProfileNull() : void |
268
|
|
|
{ |
269
|
|
|
$query = $this->em->createQuery(); |
270
|
|
|
$query->setHydrationCacheProfile(null); |
271
|
|
|
|
272
|
|
|
self::assertNull($query->getHydrationCacheProfile()); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* @group 2947 |
277
|
|
|
*/ |
278
|
|
|
public function testResultCacheEviction() : void |
279
|
|
|
{ |
280
|
|
|
$this->em->getConfiguration()->setResultCacheImpl(new ArrayCache()); |
281
|
|
|
|
282
|
|
|
$query = $this->em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u') |
283
|
|
|
->useResultCache(true); |
284
|
|
|
|
285
|
|
|
/** @var DriverConnectionMock $driverConnectionMock */ |
286
|
|
|
$driverConnectionMock = $this->em->getConnection() |
287
|
|
|
->getWrappedConnection(); |
288
|
|
|
|
289
|
|
|
// Performs the query and sets up the initial cache |
290
|
|
|
self::assertCount(0, $query->getResult()); |
291
|
|
|
|
292
|
|
|
$driverConnectionMock->setStatementMock(new StatementArrayMock([['c0' => 1]])); |
293
|
|
|
|
294
|
|
|
// Performs the query and sets up the initial cache |
295
|
|
|
self::assertCount(1, $query->expireResultCache(true)->getResult()); |
296
|
|
|
|
297
|
|
|
$driverConnectionMock->setStatementMock(new StatementArrayMock([['c0' => 1], ['c0' => 2]])); |
298
|
|
|
|
299
|
|
|
// Retrieves cached data since expire flag is false and we have a cached result set |
300
|
|
|
self::assertCount(1, $query->expireResultCache(false)->getResult()); |
301
|
|
|
|
302
|
|
|
// Performs the query and caches the result set since expire flag is true |
303
|
|
|
self::assertCount(2, $query->expireResultCache(true)->getResult()); |
304
|
|
|
|
305
|
|
|
$driverConnectionMock->setStatementMock(new StatementArrayMock([['c0' => 1]])); |
306
|
|
|
|
307
|
|
|
// Retrieves cached data since expire flag is false and we have a cached result set |
308
|
|
|
self::assertCount(2, $query->expireResultCache(false)->getResult()); |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* @group #6162 |
313
|
|
|
*/ |
314
|
|
|
public function testSelectJoinSubquery() : void |
315
|
|
|
{ |
316
|
|
|
$query = $this->em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u JOIN (SELECT )'); |
317
|
|
|
|
318
|
|
|
$this->expectException(QueryException::class); |
319
|
|
|
$this->expectExceptionMessage('Subquery'); |
320
|
|
|
$query->getSQL(); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* @group #6162 |
325
|
|
|
*/ |
326
|
|
|
public function testSelectFromSubquery() : void |
327
|
|
|
{ |
328
|
|
|
$query = $this->em->createQuery('select u from (select Doctrine\Tests\Models\CMS\CmsUser c) as u'); |
329
|
|
|
|
330
|
|
|
$this->expectException(QueryException::class); |
331
|
|
|
$this->expectExceptionMessage('Subquery'); |
332
|
|
|
$query->getSQL(); |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* @group 6699 |
337
|
|
|
*/ |
338
|
|
|
public function testGetParameterTypeJuggling() : void |
339
|
|
|
{ |
340
|
|
|
$query = $this->em->createQuery('select u from ' . CmsUser::class . ' u where u.id = ?0'); |
341
|
|
|
|
342
|
|
|
$query->setParameter(0, 0); |
343
|
|
|
|
344
|
|
|
self::assertCount(1, $query->getParameters()); |
345
|
|
|
self::assertSame(0, $query->getParameter(0)->getValue()); |
346
|
|
|
self::assertSame(0, $query->getParameter('0')->getValue()); |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* @group 6699 |
351
|
|
|
*/ |
352
|
|
|
public function testSetParameterWithNameZeroIsNotOverridden() : void |
353
|
|
|
{ |
354
|
|
|
$query = $this->em->createQuery('select u from ' . CmsUser::class . ' u where u.id != ?0 and u.username = :name'); |
355
|
|
|
|
356
|
|
|
$query->setParameter(0, 0); |
357
|
|
|
$query->setParameter('name', 'Doctrine'); |
358
|
|
|
|
359
|
|
|
self::assertCount(2, $query->getParameters()); |
360
|
|
|
self::assertSame(0, $query->getParameter('0')->getValue()); |
361
|
|
|
self::assertSame('Doctrine', $query->getParameter('name')->getValue()); |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
/** |
365
|
|
|
* @group 6699 |
366
|
|
|
*/ |
367
|
|
|
public function testSetParameterWithNameZeroDoesNotOverrideAnotherParameter() : void |
368
|
|
|
{ |
369
|
|
|
$query = $this->em->createQuery('select u from ' . CmsUser::class . ' u where u.id != ?0 and u.username = :name'); |
370
|
|
|
|
371
|
|
|
$query->setParameter('name', 'Doctrine'); |
372
|
|
|
$query->setParameter(0, 0); |
373
|
|
|
|
374
|
|
|
self::assertCount(2, $query->getParameters()); |
375
|
|
|
self::assertSame(0, $query->getParameter(0)->getValue()); |
376
|
|
|
self::assertSame('Doctrine', $query->getParameter('name')->getValue()); |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
/** |
380
|
|
|
* @group 6699 |
381
|
|
|
*/ |
382
|
|
|
public function testSetParameterWithTypeJugglingWorks() : void |
383
|
|
|
{ |
384
|
|
|
$query = $this->em->createQuery('select u from ' . CmsUser::class . ' u where u.id != ?0 and u.username = :name'); |
385
|
|
|
|
386
|
|
|
$query->setParameter('0', 1); |
387
|
|
|
$query->setParameter('name', 'Doctrine'); |
388
|
|
|
$query->setParameter(0, 2); |
389
|
|
|
$query->setParameter('0', 3); |
390
|
|
|
|
391
|
|
|
self::assertCount(2, $query->getParameters()); |
392
|
|
|
self::assertSame(3, $query->getParameter(0)->getValue()); |
393
|
|
|
self::assertSame(3, $query->getParameter('0')->getValue()); |
394
|
|
|
self::assertSame('Doctrine', $query->getParameter('name')->getValue()); |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
/** |
398
|
|
|
* @group 6748 |
399
|
|
|
*/ |
400
|
|
|
public function testResultCacheProfileCanBeRemovedViaSetter() : void |
401
|
|
|
{ |
402
|
|
|
$this->em->getConfiguration()->setResultCacheImpl(new ArrayCache()); |
403
|
|
|
|
404
|
|
|
$query = $this->em->createQuery('SELECT u FROM ' . CmsUser::class . ' u'); |
405
|
|
|
$query->useResultCache(true); |
406
|
|
|
$query->setResultCacheProfile(); |
407
|
|
|
|
408
|
|
|
self::assertAttributeSame(null, 'queryCacheProfile', $query); |
|
|
|
|
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
/** @group 7527 */ |
412
|
|
|
public function testValuesAreNotBeingResolvedForSpecifiedParameterTypes() : void |
413
|
|
|
{ |
414
|
|
|
$unitOfWork = $this->createMock(UnitOfWork::class); |
415
|
|
|
|
416
|
|
|
$this->em->setUnitOfWork($unitOfWork); |
417
|
|
|
|
418
|
|
|
$unitOfWork |
419
|
|
|
->expects(self::never()) |
420
|
|
|
->method('getSingleIdentifierValue'); |
421
|
|
|
|
422
|
|
|
$query = $this->em->createQuery('SELECT d FROM ' . DateTimeModel::class . ' d WHERE d.datetime = :value'); |
423
|
|
|
|
424
|
|
|
$query->setParameter('value', new DateTime(), Type::DATETIME); |
|
|
|
|
425
|
|
|
|
426
|
|
|
self::assertEmpty($query->getResult()); |
427
|
|
|
} |
428
|
|
|
} |
429
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.