Completed
Pull Request — 3.x (#935)
by Peter
02:00 queued 11s
created

ModelManagerTest::testFindBadId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 1
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\Model;
15
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Common\Persistence\ObjectManager;
18
use Doctrine\DBAL\Connection;
19
use Doctrine\DBAL\DBALException;
20
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
21
use Doctrine\DBAL\Types\Type;
22
use Doctrine\ORM\Configuration;
23
use Doctrine\ORM\EntityManager;
24
use Doctrine\ORM\Mapping\ClassMetadata;
25
use Doctrine\ORM\Mapping\ClassMetadataFactory;
26
use Doctrine\ORM\OptimisticLockException;
27
use Doctrine\ORM\Query;
28
use Doctrine\ORM\QueryBuilder;
29
use Doctrine\ORM\Version;
30
use PHPUnit\Framework\TestCase;
31
use Sonata\AdminBundle\Datagrid\Datagrid;
32
use Sonata\AdminBundle\Datagrid\DatagridInterface;
33
use Sonata\AdminBundle\Exception\LockException;
34
use Sonata\AdminBundle\Exception\ModelManagerException;
35
use Sonata\AdminBundle\Filter\FilterInterface;
36
use Sonata\DoctrineORMAdminBundle\Admin\FieldDescription;
37
use Sonata\DoctrineORMAdminBundle\Datagrid\OrderByToSelectWalker;
38
use Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery;
39
use Sonata\DoctrineORMAdminBundle\Model\ModelManager;
40
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\ProductIdType;
41
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\UuidBinaryType;
42
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\UuidType;
43
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\AbstractEntity;
44
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\AssociatedEntity;
45
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\ContainerEntity;
46
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\Embeddable\EmbeddedEntity;
47
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\Embeddable\SubEmbeddedEntity;
48
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\Product;
49
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\ProductId;
50
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\ProtectedEntity;
51
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\SimpleEntity;
52
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\UuidEntity;
53
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\VersionedEntity;
54
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Util\NonIntegerIdentifierTestClass;
55
use Symfony\Bridge\Doctrine\RegistryInterface;
56
57
class ModelManagerTest extends TestCase
58
{
59
    public static function setUpBeforeClass(): void
60
    {
61
        if (!Type::hasType(UuidType::NAME)) {
62
            Type::addType(UuidType::NAME, UuidType::class);
63
        }
64
        if (!Type::hasType(UuidBinaryType::NAME)) {
65
            Type::addType(UuidBinaryType::NAME, UuidBinaryType::class);
66
        }
67
        if (!Type::hasType(ProductIdType::NAME)) {
68
            Type::addType(ProductIdType::NAME, ProductIdType::class);
69
        }
70
    }
71
72
    public function testSortParameters(): void
73
    {
74
        $registry = $this->createMock(RegistryInterface::class);
75
76
        $manager = new ModelManager($registry);
77
78
        $datagrid1 = $this->createMock(Datagrid::class);
79
        $datagrid2 = $this->createMock(Datagrid::class);
80
81
        $field1 = new FieldDescription();
82
        $field1->setName('field1');
83
84
        $field2 = new FieldDescription();
85
        $field2->setName('field2');
86
87
        $field3 = new FieldDescription();
88
        $field3->setName('field3');
89
        $field3->setOption('sortable', 'field3sortBy');
90
91
        $datagrid1
92
            ->expects($this->any())
93
            ->method('getValues')
94
            ->willReturn([
95
                '_sort_by' => $field1,
96
                '_sort_order' => 'ASC',
97
            ]);
98
99
        $datagrid2
100
            ->expects($this->any())
101
            ->method('getValues')
102
            ->willReturn([
103
                '_sort_by' => $field3,
104
                '_sort_order' => 'ASC',
105
            ]);
106
107
        $parameters = $manager->getSortParameters($field1, $datagrid1);
108
109
        $this->assertSame('DESC', $parameters['filter']['_sort_order']);
110
        $this->assertSame('field1', $parameters['filter']['_sort_by']);
111
112
        $parameters = $manager->getSortParameters($field2, $datagrid1);
113
114
        $this->assertSame('ASC', $parameters['filter']['_sort_order']);
115
        $this->assertSame('field2', $parameters['filter']['_sort_by']);
116
117
        $parameters = $manager->getSortParameters($field3, $datagrid1);
118
119
        $this->assertSame('ASC', $parameters['filter']['_sort_order']);
120
        $this->assertSame('field3sortBy', $parameters['filter']['_sort_by']);
121
122
        $parameters = $manager->getSortParameters($field3, $datagrid2);
123
124
        $this->assertSame('DESC', $parameters['filter']['_sort_order']);
125
        $this->assertSame('field3sortBy', $parameters['filter']['_sort_by']);
126
    }
127
128
    public function getVersionDataProvider()
129
    {
130
        return [
131
            [true],
132
            [false],
133
        ];
134
    }
135
136
    /**
137
     * @dataProvider getVersionDataProvider
138
     */
139
    public function testGetVersion($isVersioned): void
140
    {
141
        $object = new VersionedEntity();
142
143
        $modelManager = $this->getMockBuilder(ModelManager::class)
144
            ->disableOriginalConstructor()
145
            ->setMethods(['getMetadata'])
146
            ->getMock();
147
148
        $metadata = $this->getMetadata(\get_class($object), $isVersioned);
149
150
        $modelManager->expects($this->any())
151
            ->method('getMetadata')
152
            ->willReturn($metadata);
153
154
        if ($isVersioned) {
155
            $object->version = 123;
156
157
            $this->assertNotNull($modelManager->getLockVersion($object));
158
        } else {
159
            $this->assertNull($modelManager->getLockVersion($object));
160
        }
161
    }
162
163
    public function lockDataProvider()
164
    {
165
        return [
166
            [true,  false],
167
            [true,  true],
168
            [false, false],
169
        ];
170
    }
171
172
    /**
173
     * @dataProvider lockDataProvider
174
     */
175
    public function testLock($isVersioned, $expectsException): void
176
    {
177
        $object = new VersionedEntity();
178
179
        $em = $this->getMockBuilder(EntityManager::class)
180
            ->disableOriginalConstructor()
181
            ->setMethods(['lock'])
182
            ->getMock();
183
184
        $modelManager = $this->getMockBuilder(ModelManager::class)
185
            ->disableOriginalConstructor()
186
            ->setMethods(['getMetadata', 'getEntityManager'])
187
            ->getMock();
188
189
        $modelManager->expects($this->any())
190
            ->method('getEntityManager')
191
            ->willReturn($em);
192
193
        $metadata = $this->getMetadata(\get_class($object), $isVersioned);
194
195
        $modelManager->expects($this->any())
196
            ->method('getMetadata')
197
            ->willReturn($metadata);
198
199
        $em->expects($isVersioned ? $this->once() : $this->never())
200
            ->method('lock');
201
202
        if ($expectsException) {
203
            $em->expects($this->once())
204
                ->method('lock')
205
                ->will($this->throwException(OptimisticLockException::lockFailed($object)));
206
207
            $this->expectException(LockException::class);
208
        }
209
210
        $modelManager->lock($object, 123);
211
    }
212
213
    public function testGetParentMetadataForProperty(): void
214
    {
215
        if (version_compare(Version::VERSION, '2.5') < 0) {
216
            $this->markTestSkipped('Test for embeddables needs to run on Doctrine >= 2.5');
217
218
            return;
219
        }
220
221
        $containerEntityClass = ContainerEntity::class;
222
        $associatedEntityClass = AssociatedEntity::class;
223
        $embeddedEntityClass = EmbeddedEntity::class;
224
        $modelManagerClass = ModelManager::class;
225
226
        $em = $this->createMock(EntityManager::class);
227
228
        /** @var \PHPUnit_Framework_MockObject_MockObject|ModelManager $modelManager */
229
        $modelManager = $this->getMockBuilder($modelManagerClass)
230
            ->disableOriginalConstructor()
231
            ->setMethods(['getMetadata', 'getEntityManager'])
232
            ->getMock();
233
234
        $modelManager->expects($this->any())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\DoctrineOR...dle\Model\ModelManager>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
235
            ->method('getEntityManager')
236
            ->willReturn($em);
237
238
        $containerEntityMetadata = $this->getMetadataForContainerEntity();
239
        $associatedEntityMetadata = $this->getMetadataForAssociatedEntity();
240
        $embeddedEntityMetadata = $this->getMetadataForEmbeddedEntity();
241
242
        $modelManager->expects($this->any())->method('getMetadata')
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\DoctrineOR...dle\Model\ModelManager>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
243
            ->willReturnMap(
244
245
                    [
246
                        [$containerEntityClass, $containerEntityMetadata],
247
                        [$embeddedEntityClass, $embeddedEntityMetadata],
248
                        [$associatedEntityClass, $associatedEntityMetadata],
249
                    ]
250
251
            );
252
253
        /** @var ClassMetadata $metadata */
254
        list($metadata, $lastPropertyName) = $modelManager
255
            ->getParentMetadataForProperty($containerEntityClass, 'plainField');
256
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'integer');
257
258
        list($metadata, $lastPropertyName) = $modelManager
259
            ->getParentMetadataForProperty($containerEntityClass, 'associatedEntity.plainField');
260
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'string');
261
262
        list($metadata, $lastPropertyName) = $modelManager
263
            ->getParentMetadataForProperty($containerEntityClass, 'embeddedEntity.plainField');
264
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
265
266
        list($metadata, $lastPropertyName) = $modelManager
267
            ->getParentMetadataForProperty($containerEntityClass, 'associatedEntity.embeddedEntity.plainField');
268
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
269
270
        list($metadata, $lastPropertyName) = $modelManager
271
            ->getParentMetadataForProperty(
272
                $containerEntityClass,
273
                'associatedEntity.embeddedEntity.subEmbeddedEntity.plainField'
274
            );
275
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
276
    }
277
278
    public function getMetadataForEmbeddedEntity()
279
    {
280
        $metadata = new ClassMetadata(EmbeddedEntity::class);
281
282
        $metadata->fieldMappings = [
283
            'plainField' => [
284
                'fieldName' => 'plainField',
285
                'columnName' => 'plainField',
286
                'type' => 'boolean',
287
            ],
288
        ];
289
290
        return $metadata;
291
    }
292
293
    public function getMetadataForSubEmbeddedEntity()
294
    {
295
        $metadata = new ClassMetadata(SubEmbeddedEntity::class);
296
297
        $metadata->fieldMappings = [
298
            'plainField' => [
299
                'fieldName' => 'plainField',
300
                'columnName' => 'plainField',
301
                'type' => 'boolean',
302
            ],
303
        ];
304
305
        return $metadata;
306
    }
307
308
    public function getMetadataForAssociatedEntity()
309
    {
310
        $embeddedEntityClass = EmbeddedEntity::class;
311
        $subEmbeddedEntityClass = SubEmbeddedEntity::class;
312
313
        $metadata = new ClassMetadata(AssociatedEntity::class);
314
315
        $metadata->fieldMappings = [
316
            'plainField' => [
317
                'fieldName' => 'plainField',
318
                'columnName' => 'plainField',
319
                'type' => 'string',
320
            ],
321
        ];
322
323
        $metadata->embeddedClasses['embeddedEntity'] = [
324
            'class' => $embeddedEntityClass,
325
            'columnPrefix' => 'embedded_entity_',
326
        ];
327
        $metadata->embeddedClasses['embeddedEntity.subEmbeddedEntity'] = [
328
            'class' => $subEmbeddedEntityClass,
329
            'columnPrefix' => 'embedded_entity_sub_embedded_entity_',
330
            'declaredField' => 'embeddedEntity',
331
            'originalField' => 'subEmbeddedEntity',
332
        ];
333
334
        $metadata->inlineEmbeddable('embeddedEntity', $this->getMetadataForEmbeddedEntity());
335
        $metadata->inlineEmbeddable('embeddedEntity.subEmbeddedEntity', $this->getMetadataForSubEmbeddedEntity());
336
337
        return $metadata;
338
    }
339
340
    public function getMetadataForContainerEntity()
341
    {
342
        $containerEntityClass = ContainerEntity::class;
343
        $associatedEntityClass = AssociatedEntity::class;
344
        $embeddedEntityClass = EmbeddedEntity::class;
345
        $subEmbeddedEntityClass = SubEmbeddedEntity::class;
346
347
        $metadata = new ClassMetadata($containerEntityClass);
348
349
        $metadata->fieldMappings = [
350
            'plainField' => [
351
                'fieldName' => 'plainField',
352
                'columnName' => 'plainField',
353
                'type' => 'integer',
354
            ],
355
        ];
356
357
        $metadata->associationMappings['associatedEntity'] = [
358
            'fieldName' => 'associatedEntity',
359
            'targetEntity' => $associatedEntityClass,
360
            'sourceEntity' => $containerEntityClass,
361
        ];
362
363
        $metadata->embeddedClasses['embeddedEntity'] = [
364
            'class' => $embeddedEntityClass,
365
            'columnPrefix' => 'embeddedEntity',
366
        ];
367
        $metadata->embeddedClasses['embeddedEntity.subEmbeddedEntity'] = [
368
            'class' => $subEmbeddedEntityClass,
369
            'columnPrefix' => 'embedded_entity_sub_embedded_entity_',
370
            'declaredField' => 'embeddedEntity',
371
            'originalField' => 'subEmbeddedEntity',
372
        ];
373
374
        $metadata->inlineEmbeddable('embeddedEntity', $this->getMetadataForEmbeddedEntity());
375
        $metadata->inlineEmbeddable('embeddedEntity.subEmbeddedEntity', $this->getMetadataForSubEmbeddedEntity());
376
377
        return $metadata;
378
    }
379
380
    public function testGetIdentifierValuesForIdInObjectTypeBinaryToStringSupport(): void
381
    {
382
        $uuid = new NonIntegerIdentifierTestClass('efbcfc4b-8c43-4d42-aa4c-d707e55151ac');
383
384
        $entity = new UuidEntity($uuid);
385
386
        $meta = $this->createMock(ClassMetadata::class);
387
        $meta->expects($this->any())
388
            ->method('getIdentifierValues')
389
            ->willReturn([$entity->getId()]);
390
        $meta->expects($this->any())
391
            ->method('getTypeOfField')
392
            ->willReturn(UuidBinaryType::NAME); //'uuid_binary'
393
394
        $mf = $this->createMock(ClassMetadataFactory::class);
395
        $mf->expects($this->any())
396
            ->method('getMetadataFor')
397
            ->willReturn($meta);
398
399
        $platform = $this->createMock(PostgreSqlPlatform::class);
400
        $platform->expects($this->any())
401
            ->method('hasDoctrineTypeMappingFor')
402
            ->with(UuidBinaryType::NAME)
403
            ->willReturn(true);
404
        $platform->expects($this->any())
405
            ->method('getDoctrineTypeMapping')
406
            ->with(UuidBinaryType::NAME)
407
            ->willReturn('binary');
408
409
        $conn = $this->createMock(Connection::class);
410
        $conn->expects($this->any())
411
            ->method('getDatabasePlatform')
412
            ->willReturn($platform);
413
414
        $em = $this->createMock(EntityManager::class);
415
        $em->expects($this->any())
416
            ->method('getMetadataFactory')
417
            ->willReturn($mf);
418
        $em->expects($this->any())
419
            ->method('getConnection')
420
            ->willReturn($conn);
421
422
        $registry = $this->createMock(RegistryInterface::class);
423
        $registry->expects($this->any())
424
            ->method('getManagerForClass')
425
            ->willReturn($em);
426
427
        $manager = new ModelManager($registry);
428
        $result = $manager->getIdentifierValues($entity);
429
430
        $this->assertSame($entity->getId()->toString(), $result[0]);
431
    }
432
433
    public function testNonIntegerIdentifierType(): void
434
    {
435
        $uuid = new NonIntegerIdentifierTestClass('efbcfc4b-8c43-4d42-aa4c-d707e55151ac');
436
        $entity = new UuidEntity($uuid);
437
438
        $meta = $this->createMock(ClassMetadata::class);
439
        $meta->expects($this->any())
440
            ->method('getIdentifierValues')
441
            ->willReturn([$entity->getId()]);
442
        $meta->expects($this->any())
443
            ->method('getTypeOfField')
444
            ->willReturn(UuidType::NAME);
445
446
        $mf = $this->createMock(ClassMetadataFactory::class);
447
        $mf->expects($this->any())
448
            ->method('getMetadataFor')
449
            ->willReturn($meta);
450
451
        $platform = $this->createMock(PostgreSqlPlatform::class);
452
        $platform->expects($this->any())
453
            ->method('hasDoctrineTypeMappingFor')
454
            ->with(UuidType::NAME)
455
            ->willReturn(false);
456
        $platform->expects($this->never())
457
            ->method('getDoctrineTypeMapping');
458
459
        $conn = $this->createMock(Connection::class);
460
        $conn->expects($this->any())
461
            ->method('getDatabasePlatform')
462
            ->willReturn($platform);
463
464
        $em = $this->createMock(EntityManager::class);
465
        $em->expects($this->any())
466
            ->method('getMetadataFactory')
467
            ->willReturn($mf);
468
        $em->expects($this->any())
469
            ->method('getConnection')
470
            ->willReturn($conn);
471
472
        $registry = $this->createMock(RegistryInterface::class);
473
        $registry->expects($this->any())
474
            ->method('getManagerForClass')
475
            ->willReturn($em);
476
477
        $manager = new ModelManager($registry);
478
        $result = $manager->getIdentifierValues($entity);
479
480
        $this->assertSame($entity->getId()->toString(), $result[0]);
481
    }
482
483
    public function testIntegerIdentifierType(): void
484
    {
485
        $id = new ProductId(12345);
486
        $entity = new Product($id, 'Some product');
487
488
        $meta = $this->createMock(ClassMetadata::class);
489
        $meta->expects($this->any())
490
            ->method('getIdentifierValues')
491
            ->willReturn([$entity->getId()]);
492
        $meta->expects($this->any())
493
            ->method('getTypeOfField')
494
            ->willReturn(ProductIdType::NAME);
495
496
        $mf = $this->createMock(ClassMetadataFactory::class);
497
        $mf->expects($this->any())
498
            ->method('getMetadataFor')
499
            ->willReturn($meta);
500
501
        $platform = $this->createMock(PostgreSqlPlatform::class);
502
        $platform->expects($this->any())
503
            ->method('hasDoctrineTypeMappingFor')
504
            ->with(ProductIdType::NAME)
505
            ->willReturn(false);
506
        $platform->expects($this->never())
507
            ->method('getDoctrineTypeMapping');
508
509
        $conn = $this->createMock(Connection::class);
510
        $conn->expects($this->any())
511
            ->method('getDatabasePlatform')
512
            ->willReturn($platform);
513
514
        $em = $this->createMock(EntityManager::class);
515
        $em->expects($this->any())
516
            ->method('getMetadataFactory')
517
            ->willReturn($mf);
518
        $em->expects($this->any())
519
            ->method('getConnection')
520
            ->willReturn($conn);
521
522
        $registry = $this->createMock(RegistryInterface::class);
523
        $registry->expects($this->any())
524
            ->method('getManagerForClass')
525
            ->willReturn($em);
526
527
        $manager = new ModelManager($registry);
528
        $result = $manager->getIdentifierValues($entity);
529
530
        $this->assertSame((string) $entity->getId()->getId(), $result[0]);
531
    }
532
533
    public function testAssociationIdentifierType(): void
534
    {
535
        $entity = new ContainerEntity(new AssociatedEntity(42, new EmbeddedEntity()), new EmbeddedEntity());
536
537
        $meta = $this->createMock(ClassMetadata::class);
538
        $meta->expects($this->any())
539
            ->method('getIdentifierValues')
540
            ->willReturn([$entity->getAssociatedEntity()->getPlainField()]);
541
        $meta->expects($this->any())
542
            ->method('getTypeOfField')
543
            ->willReturn(null);
544
545
        $mf = $this->createMock(ClassMetadataFactory::class);
546
        $mf->expects($this->any())
547
            ->method('getMetadataFor')
548
            ->willReturn($meta);
549
550
        $platform = $this->createMock(PostgreSqlPlatform::class);
551
        $platform->expects($this->never())
552
            ->method('hasDoctrineTypeMappingFor');
553
554
        $conn = $this->createMock(Connection::class);
555
        $conn->expects($this->any())
556
            ->method('getDatabasePlatform')
557
            ->willReturn($platform);
558
559
        $em = $this->createMock(EntityManager::class);
560
        $em->expects($this->any())
561
            ->method('getMetadataFactory')
562
            ->willReturn($mf);
563
        $em->expects($this->any())
564
            ->method('getConnection')
565
            ->willReturn($conn);
566
567
        $registry = $this->createMock(RegistryInterface::class);
568
        $registry->expects($this->any())
569
            ->method('getManagerForClass')
570
            ->willReturn($em);
571
572
        $manager = new ModelManager($registry);
573
        $result = $manager->getIdentifierValues($entity);
574
575
        $this->assertSame(42, $result[0]);
576
    }
577
578
    /**
579
     * [sortBy, sortOrder, isAddOrderBy].
580
     *
581
     * @return array
582
     */
583
    public function getSortableInDataSourceIteratorDataProvider()
584
    {
585
        return [
586
            [null, null, false],
587
            ['', 'ASC', false],
588
            ['field', 'ASC', true],
589
            ['field', null, true],
590
        ];
591
    }
592
593
    /**
594
     * @dataProvider getSortableInDataSourceIteratorDataProvider
595
     *
596
     * @param string|null $sortBy
597
     * @param string|null $sortOrder
598
     * @param bool        $isAddOrderBy
599
     */
600
    public function testSortableInDataSourceIterator($sortBy, $sortOrder, $isAddOrderBy): void
601
    {
602
        $datagrid = $this->getMockForAbstractClass(DatagridInterface::class);
603
        $configuration = $this->getMockBuilder(Configuration::class)->getMock();
604
        $configuration->expects($this->any())
605
            ->method('getDefaultQueryHints')
606
            ->willReturn([]);
607
608
        $em = $this->getMockBuilder(EntityManager::class)
609
            ->disableOriginalConstructor()
610
            ->getMock();
611
612
        $em->expects($this->any())
613
            ->method('getConfiguration')
614
            ->willReturn($configuration);
615
616
        $queryBuilder = $this->getMockBuilder(QueryBuilder::class)
617
            ->setConstructorArgs([$em])
618
            ->getMock();
619
        $query = new Query($em);
620
621
        $proxyQuery = $this->getMockBuilder(ProxyQuery::class)
622
            ->setConstructorArgs([$queryBuilder])
623
            ->setMethods(['getSortBy', 'getSortOrder', 'getRootAliases'])
624
            ->getMock();
625
626
        $proxyQuery->expects($this->any())
627
            ->method('getSortOrder')
628
            ->willReturn($sortOrder);
629
630
        $proxyQuery->expects($this->any())
631
            ->method('getSortBy')
632
            ->willReturn($sortBy);
633
634
        $queryBuilder->expects($isAddOrderBy ? $this->atLeastOnce() : $this->never())
635
            ->method('addOrderBy');
636
637
        $proxyQuery->expects($this->any())
638
            ->method('getRootAliases')
639
            ->willReturn(['a']);
640
641
        $queryBuilder->expects($this->any())
642
            ->method('getQuery')
643
            ->willReturn($query);
644
645
        $datagrid->expects($this->any())
646
            ->method('getQuery')
647
            ->willReturn($proxyQuery);
648
649
        $registry = $this->getMockBuilder(RegistryInterface::class)->getMock();
650
        $manager = new ModelManager($registry);
651
        $manager->getDataSourceIterator($datagrid, []);
652
653
        if ($isAddOrderBy) {
654
            $this->assertArrayHasKey($key = 'doctrine.customTreeWalkers', $hints = $query->getHints());
655
            $this->assertContains(OrderByToSelectWalker::class, $hints[$key]);
656
        }
657
    }
658
659
    public function testModelReverseTransform(): void
660
    {
661
        $class = SimpleEntity::class;
662
663
        $metadataFactory = $this->createMock(ClassMetadataFactory::class);
664
        $modelManager = $this->createMock(ObjectManager::class);
665
        $registry = $this->createMock(RegistryInterface::class);
666
667
        $classMetadata = new ClassMetadata($class);
668
        $classMetadata->reflClass = new \ReflectionClass($class);
669
670
        $modelManager->expects($this->once())
671
            ->method('getMetadataFactory')
672
            ->willReturn($metadataFactory);
673
        $metadataFactory->expects($this->once())
674
            ->method('getMetadataFor')
675
            ->with($class)
676
            ->willReturn($classMetadata);
677
        $registry->expects($this->once())
678
            ->method('getManagerForClass')
679
            ->with($class)
680
            ->willReturn($modelManager);
681
682
        $manager = new ModelManager($registry);
683
        $this->assertInstanceOf($class, $object = $manager->modelReverseTransform(
684
            $class,
685
            [
686
                'schmeckles' => 42,
687
                'multi_word_property' => 'hello',
688
            ]
689
        ));
690
        $this->assertSame(42, $object->getSchmeckles());
691
        $this->assertSame('hello', $object->getMultiWordProperty());
692
    }
693
694
    public function testCollections(): void
695
    {
696
        $registry = $this->createMock(RegistryInterface::class);
697
        $model = new ModelManager($registry);
698
699
        $collection = $model->getModelCollectionInstance('whyDoWeEvenHaveThisParameter');
700
        $this->assertInstanceOf(ArrayCollection::class, $collection);
701
702
        $item1 = 'item1';
703
        $item2 = 'item2';
704
        $model->collectionAddElement($collection, $item1);
705
        $model->collectionAddElement($collection, $item2);
706
707
        $this->assertTrue($model->collectionHasElement($collection, $item1));
708
709
        $model->collectionRemoveElement($collection, $item1);
710
711
        $this->assertFalse($model->collectionHasElement($collection, $item1));
712
713
        $model->collectionClear($collection);
714
715
        $this->assertTrue($collection->isEmpty());
716
    }
717
718
    public function testModelTransform(): void
719
    {
720
        $registry = $this->createMock(RegistryInterface::class);
721
        $model = new ModelManager($registry);
722
723
        $result = $model->modelTransform('thisIsNotUsed', 'doWeNeedThisMethod');
0 ignored issues
show
Documentation introduced by
'doWeNeedThisMethod' is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
724
725
        $this->assertSame('doWeNeedThisMethod', $result);
726
    }
727
728
    public function testGetPaginationParameters(): void
729
    {
730
        $datagrid = $this->createMock(DatagridInterface::class);
731
        $filter = $this->createMock(FilterInterface::class);
732
        $registry = $this->createMock(RegistryInterface::class);
733
734
        $datagrid->expects($this->once())
735
            ->method('getValues')
736
            ->willReturn(['_sort_by' => $filter]);
737
738
        $filter->expects($this->once())
739
            ->method('getName')
740
            ->willReturn($name = 'test');
741
742
        $model = new ModelManager($registry);
743
744
        $result = $model->getPaginationParameters($datagrid, $page = 5);
745
746
        $this->assertSame($page, $result['filter']['_page']);
747
        $this->assertSame($name, $result['filter']['_sort_by']);
748
    }
749
750
    public function testGetModelInstanceException(): void
751
    {
752
        $registry = $this->createMock(RegistryInterface::class);
753
754
        $model = new ModelManager($registry);
755
756
        $this->expectException(\RuntimeException::class);
757
758
        $model->getModelInstance(AbstractEntity::class);
759
    }
760
761
    public function testGetModelInstanceForProtectedEntity(): void
762
    {
763
        $registry = $this->createMock(RegistryInterface::class);
764
765
        $model = new ModelManager($registry);
766
767
        $this->assertInstanceOf(ProtectedEntity::class, $model->getModelInstance(ProtectedEntity::class));
768
    }
769
770
    public function testGetEntityManagerException(): void
771
    {
772
        $registry = $this->createMock(RegistryInterface::class);
773
774
        $model = new ModelManager($registry);
775
776
        $this->expectException(\RuntimeException::class);
777
778
        $model->getEntityManager(VersionedEntity::class);
779
    }
780
781
    public function testGetNewFieldDescriptionInstanceException(): void
782
    {
783
        $registry = $this->createMock(RegistryInterface::class);
784
785
        $model = new ModelManager($registry);
786
787
        $this->expectException(\RuntimeException::class);
788
789
        $model->getNewFieldDescriptionInstance(VersionedEntity::class, [], []);
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
790
    }
791
792
    /**
793
     * @dataProvider createUpdateRemoveData
794
     */
795
    public function testCreate($exception): void
796
    {
797
        $registry = $this->createMock(RegistryInterface::class);
798
799
        $entityManger = $this->createMock(EntityManager::class);
800
801
        $registry->expects($this->once())
802
            ->method('getManagerForClass')
803
            ->willReturn($entityManger);
804
805
        $entityManger->expects($this->once())
806
            ->method('persist');
807
808
        $entityManger->expects($this->once())
809
            ->method('flush')
810
            ->willThrowException($exception);
811
812
        $model = new ModelManager($registry);
813
814
        $this->expectException(ModelManagerException::class);
815
816
        $model->create(new VersionedEntity());
817
    }
818
819
    public function createUpdateRemoveData()
820
    {
821
        return [
822
            'PDOException' => [
823
                new \PDOException(),
824
            ],
825
            'DBALException' => [
826
                new DBALException(),
827
            ],
828
        ];
829
    }
830
831
    /**
832
     * @dataProvider createUpdateRemoveData
833
     */
834
    public function testUpdate($exception): void
835
    {
836
        $registry = $this->createMock(RegistryInterface::class);
837
838
        $entityManger = $this->createMock(EntityManager::class);
839
840
        $registry->expects($this->once())
841
            ->method('getManagerForClass')
842
            ->willReturn($entityManger);
843
844
        $entityManger->expects($this->once())
845
            ->method('persist');
846
847
        $entityManger->expects($this->once())
848
            ->method('flush')
849
            ->willThrowException($exception);
850
851
        $model = new ModelManager($registry);
852
853
        $this->expectException(ModelManagerException::class);
854
855
        $model->update(new VersionedEntity());
856
    }
857
858
    /**
859
     * @dataProvider createUpdateRemoveData
860
     */
861
    public function testRemove($exception): void
862
    {
863
        $registry = $this->createMock(RegistryInterface::class);
864
865
        $entityManger = $this->createMock(EntityManager::class);
866
867
        $registry->expects($this->once())
868
            ->method('getManagerForClass')
869
            ->willReturn($entityManger);
870
871
        $entityManger->expects($this->once())
872
            ->method('remove');
873
874
        $entityManger->expects($this->once())
875
            ->method('flush')
876
            ->willThrowException($exception);
877
878
        $model = new ModelManager($registry);
879
880
        $this->expectException(ModelManagerException::class);
881
882
        $model->delete(new VersionedEntity());
883
    }
884
885
    public function testFindBadId(): void
886
    {
887
        $registry = $this->createMock(RegistryInterface::class);
888
889
        $model = new ModelManager($registry);
890
891
        $this->assertNull($model->find('notImportant', null));
892
    }
893
894
    public function testGetUrlsafeIdentifierException(): void
895
    {
896
        $registry = $this->createMock(RegistryInterface::class);
897
898
        $model = new ModelManager($registry);
899
900
        $this->expectException(\RuntimeException::class);
901
902
        $model->getNormalizedIdentifier('test');
0 ignored issues
show
Documentation introduced by
'test' is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
903
    }
904
905
    public function testGetUrlsafeIdentifierNull(): void
906
    {
907
        $registry = $this->createMock(RegistryInterface::class);
908
909
        $model = new ModelManager($registry);
910
911
        $this->assertNull($model->getNormalizedIdentifier(null));
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
912
    }
913
914
    private function getMetadata($class, $isVersioned)
915
    {
916
        $metadata = new ClassMetadata($class);
917
918
        $metadata->isVersioned = $isVersioned;
919
920
        if ($isVersioned) {
921
            $versionField = 'version';
922
            $metadata->versionField = $versionField;
923
            $metadata->reflFields[$versionField] = new \ReflectionProperty($class, $versionField);
924
        }
925
926
        return $metadata;
927
    }
928
}
929