Completed
Pull Request — master (#1045)
by Mathieu
05:49 queued 04:39
created

eprecatedRegistryInterface()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
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\DBAL\Connection;
18
use Doctrine\DBAL\DBALException;
19
use Doctrine\DBAL\Platforms\MySqlPlatform;
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\Mapping\ClassMetadataInfo;
27
use Doctrine\ORM\OptimisticLockException;
28
use Doctrine\ORM\Query;
29
use Doctrine\ORM\QueryBuilder;
30
use Doctrine\Persistence\ManagerRegistry;
31
use Doctrine\Persistence\ObjectManager;
32
use PHPUnit\Framework\MockObject\MockObject;
33
use PHPUnit\Framework\TestCase;
34
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
35
use Sonata\AdminBundle\Datagrid\Datagrid;
36
use Sonata\AdminBundle\Datagrid\DatagridInterface;
37
use Sonata\AdminBundle\Exception\LockException;
38
use Sonata\AdminBundle\Exception\ModelManagerException;
39
use Sonata\DoctrineORMAdminBundle\Admin\FieldDescription;
40
use Sonata\DoctrineORMAdminBundle\Datagrid\OrderByToSelectWalker;
41
use Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery;
42
use Sonata\DoctrineORMAdminBundle\Model\ModelManager;
43
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\ProductIdType;
44
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\UuidBinaryType;
45
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\UuidType;
46
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\ValueObjectWithMagicToStringImpl;
47
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\ValueObjectWithToStringImpl;
48
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\AbstractEntity;
49
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\AssociatedEntity;
50
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\ContainerEntity;
51
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\Embeddable\EmbeddedEntity;
52
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\Embeddable\SubEmbeddedEntity;
53
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\Product;
54
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\ProductId;
55
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\ProtectedEntity;
56
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\SimpleEntity;
57
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\UuidBinaryEntity;
58
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\UuidEntity;
59
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\VersionedEntity;
60
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Util\NonIntegerIdentifierTestClass;
61
62
class ModelManagerTest extends TestCase
63
{
64
    public static function setUpBeforeClass(): void
65
    {
66
        if (!Type::hasType(UuidType::NAME)) {
67
            Type::addType(UuidType::NAME, UuidType::class);
68
        }
69
        if (!Type::hasType(UuidBinaryType::NAME)) {
70
            Type::addType(UuidBinaryType::NAME, UuidBinaryType::class);
71
        }
72
        if (!Type::hasType(ProductIdType::NAME)) {
73
            Type::addType(ProductIdType::NAME, ProductIdType::class);
74
        }
75
    }
76
77
    public function valueObjectDataProvider(): array
78
    {
79
        return [
80
            'value object with toString implementation' => [ValueObjectWithToStringImpl::class],
81
            'value object with magic toString implementation' => [ValueObjectWithMagicToStringImpl::class],
82
        ];
83
    }
84
85
    /**
86
     * @dataProvider valueObjectDataProvider
87
     */
88
    public function testGetIdentifierValuesWhenIdentifierIsValueObjectWithToStringMethod(string $vbClassName): void
89
    {
90
        $entity = new UuidBinaryEntity(new $vbClassName('a7ef873a-e7b5-11e9-81b4-2a2ae2dbcce4'));
91
92
        $platform = $this->createMock(MySqlPlatform::class);
93
94
        $connection = $this->createMock(Connection::class);
95
        $connection->method('getDatabasePlatform')->willReturn($platform);
96
97
        $classMetadata = $this->createMock(ClassMetadataInfo::class);
98
        $classMetadata->method('getIdentifierValues')->willReturn([$entity->getId()]);
99
        $classMetadata->method('getTypeOfField')->willReturn(UuidBinaryType::NAME);
100
101
        $classMetadataFactory = $this->createMock(ClassMetadataFactory::class);
102
        $classMetadataFactory->method('getMetadataFor')->willReturn($classMetadata);
103
104
        $entityManager = $this->createMock(EntityManager::class);
105
        $entityManager->method('getMetadataFactory')->willReturn($classMetadataFactory);
106
        $entityManager->method('getConnection')->willReturn($connection);
107
108
        $registry = $this->createMock(ManagerRegistry::class);
109
        $registry->method('getManagerForClass')->willReturn($entityManager);
110
111
        $manager = new ModelManager($registry);
112
113
        $this->assertSame(
114
            ['a7ef873a-e7b5-11e9-81b4-2a2ae2dbcce4'],
115
            $manager->getIdentifierValues($entity)
116
        );
117
    }
118
119
    public function testSortParameters(): void
120
    {
121
        $registry = $this->createMock(ManagerRegistry::class);
122
123
        $manager = new ModelManager($registry);
124
125
        $datagrid1 = $this->createMock(Datagrid::class);
126
        $datagrid2 = $this->createMock(Datagrid::class);
127
128
        $field1 = new FieldDescription();
129
        $field1->setName('field1');
130
131
        $field2 = new FieldDescription();
132
        $field2->setName('field2');
133
134
        $field3 = new FieldDescription();
135
        $field3->setName('field3');
136
        $field3->setOption('sortable', 'field3sortBy');
137
138
        $datagrid1
139
            ->expects($this->any())
140
            ->method('getValues')
141
            ->willReturn([
142
                '_sort_by' => $field1,
143
                '_sort_order' => 'ASC',
144
            ]);
145
146
        $datagrid2
147
            ->expects($this->any())
148
            ->method('getValues')
149
            ->willReturn([
150
                '_sort_by' => $field3,
151
                '_sort_order' => 'ASC',
152
            ]);
153
154
        $parameters = $manager->getSortParameters($field1, $datagrid1);
155
156
        $this->assertSame('DESC', $parameters['filter']['_sort_order']);
157
        $this->assertSame('field1', $parameters['filter']['_sort_by']);
158
159
        $parameters = $manager->getSortParameters($field2, $datagrid1);
160
161
        $this->assertSame('ASC', $parameters['filter']['_sort_order']);
162
        $this->assertSame('field2', $parameters['filter']['_sort_by']);
163
164
        $parameters = $manager->getSortParameters($field3, $datagrid1);
165
166
        $this->assertSame('ASC', $parameters['filter']['_sort_order']);
167
        $this->assertSame('field3sortBy', $parameters['filter']['_sort_by']);
168
169
        $parameters = $manager->getSortParameters($field3, $datagrid2);
170
171
        $this->assertSame('DESC', $parameters['filter']['_sort_order']);
172
        $this->assertSame('field3sortBy', $parameters['filter']['_sort_by']);
173
    }
174
175
    public function getVersionDataProvider(): array
176
    {
177
        return [
178
            [true],
179
            [false],
180
        ];
181
    }
182
183
    /**
184
     * @dataProvider getVersionDataProvider
185
     */
186
    public function testGetVersion($isVersioned): void
187
    {
188
        $object = new VersionedEntity();
189
190
        $modelManager = $this->getMockBuilder(ModelManager::class)
191
            ->disableOriginalConstructor()
192
            ->setMethods(['getMetadata'])
193
            ->getMock();
194
195
        $metadata = $this->getMetadata(\get_class($object), $isVersioned);
196
197
        $modelManager->expects($this->any())
198
            ->method('getMetadata')
199
            ->willReturn($metadata);
200
201
        if ($isVersioned) {
202
            $object->version = 123;
203
204
            $this->assertNotNull($modelManager->getLockVersion($object));
205
        } else {
206
            $this->assertNull($modelManager->getLockVersion($object));
207
        }
208
    }
209
210
    public function lockDataProvider(): array
211
    {
212
        return [
213
            [true,  false],
214
            [true,  true],
215
            [false, false],
216
        ];
217
    }
218
219
    /**
220
     * @dataProvider lockDataProvider
221
     */
222
    public function testLock($isVersioned, $expectsException): void
223
    {
224
        $object = new VersionedEntity();
225
226
        $em = $this->getMockBuilder(EntityManager::class)
227
            ->disableOriginalConstructor()
228
            ->setMethods(['lock'])
229
            ->getMock();
230
231
        $modelManager = $this->getMockBuilder(ModelManager::class)
232
            ->disableOriginalConstructor()
233
            ->setMethods(['getMetadata', 'getEntityManager'])
234
            ->getMock();
235
236
        $modelManager->expects($this->any())
237
            ->method('getEntityManager')
238
            ->willReturn($em);
239
240
        $metadata = $this->getMetadata(\get_class($object), $isVersioned);
241
242
        $modelManager->expects($this->any())
243
            ->method('getMetadata')
244
            ->willReturn($metadata);
245
246
        $em->expects($isVersioned ? $this->once() : $this->never())
247
            ->method('lock');
248
249
        if ($expectsException) {
250
            $em->expects($this->once())
251
                ->method('lock')
252
                ->will($this->throwException(OptimisticLockException::lockFailed($object)));
253
254
            $this->expectException(LockException::class);
255
        }
256
257
        $modelManager->lock($object, 123);
258
    }
259
260
    public function testGetParentMetadataForProperty(): void
261
    {
262
        $containerEntityClass = ContainerEntity::class;
263
        $associatedEntityClass = AssociatedEntity::class;
264
        $embeddedEntityClass = EmbeddedEntity::class;
265
        $modelManagerClass = ModelManager::class;
266
267
        $em = $this->createMock(EntityManager::class);
268
269
        /** @var MockObject|ModelManager $modelManager */
270
        $modelManager = $this->getMockBuilder($modelManagerClass)
271
            ->disableOriginalConstructor()
272
            ->setMethods(['getMetadata', 'getEntityManager'])
273
            ->getMock();
274
275
        $modelManager->expects($this->any())
276
            ->method('getEntityManager')
277
            ->willReturn($em);
278
279
        $containerEntityMetadata = $this->getMetadataForContainerEntity();
280
        $associatedEntityMetadata = $this->getMetadataForAssociatedEntity();
281
        $embeddedEntityMetadata = $this->getMetadataForEmbeddedEntity();
282
283
        $modelManager->expects($this->any())->method('getMetadata')
284
            ->willReturnMap(
285
                [
286
                        [$containerEntityClass, $containerEntityMetadata],
287
                        [$embeddedEntityClass, $embeddedEntityMetadata],
288
                        [$associatedEntityClass, $associatedEntityMetadata],
289
                    ]
290
            );
291
292
        /** @var ClassMetadata $metadata */
293
        list($metadata, $lastPropertyName) = $modelManager
294
            ->getParentMetadataForProperty($containerEntityClass, 'plainField');
295
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'integer');
296
297
        list($metadata, $lastPropertyName) = $modelManager
298
            ->getParentMetadataForProperty($containerEntityClass, 'associatedEntity.plainField');
299
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'string');
300
301
        list($metadata, $lastPropertyName) = $modelManager
302
            ->getParentMetadataForProperty($containerEntityClass, 'embeddedEntity.plainField');
303
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
304
305
        list($metadata, $lastPropertyName) = $modelManager
306
            ->getParentMetadataForProperty($containerEntityClass, 'associatedEntity.embeddedEntity.plainField');
307
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
308
309
        list($metadata, $lastPropertyName) = $modelManager
310
            ->getParentMetadataForProperty(
311
                $containerEntityClass,
312
                'associatedEntity.embeddedEntity.subEmbeddedEntity.plainField'
313
            );
314
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
315
    }
316
317
    public function getMetadataForEmbeddedEntity()
318
    {
319
        $metadata = new ClassMetadata(EmbeddedEntity::class);
320
321
        $metadata->fieldMappings = [
322
            'plainField' => [
323
                'fieldName' => 'plainField',
324
                'columnName' => 'plainField',
325
                'type' => 'boolean',
326
            ],
327
        ];
328
329
        return $metadata;
330
    }
331
332
    public function getMetadataForSubEmbeddedEntity()
333
    {
334
        $metadata = new ClassMetadata(SubEmbeddedEntity::class);
335
336
        $metadata->fieldMappings = [
337
            'plainField' => [
338
                'fieldName' => 'plainField',
339
                'columnName' => 'plainField',
340
                'type' => 'boolean',
341
            ],
342
        ];
343
344
        return $metadata;
345
    }
346
347
    public function getMetadataForAssociatedEntity()
348
    {
349
        $embeddedEntityClass = EmbeddedEntity::class;
350
        $subEmbeddedEntityClass = SubEmbeddedEntity::class;
351
352
        $metadata = new ClassMetadata(AssociatedEntity::class);
353
354
        $metadata->fieldMappings = [
355
            'plainField' => [
356
                'fieldName' => 'plainField',
357
                'columnName' => 'plainField',
358
                'type' => 'string',
359
            ],
360
        ];
361
362
        $metadata->embeddedClasses['embeddedEntity'] = [
363
            'class' => $embeddedEntityClass,
364
            'columnPrefix' => 'embedded_entity_',
365
        ];
366
        $metadata->embeddedClasses['embeddedEntity.subEmbeddedEntity'] = [
367
            'class' => $subEmbeddedEntityClass,
368
            'columnPrefix' => 'embedded_entity_sub_embedded_entity_',
369
            'declaredField' => 'embeddedEntity',
370
            'originalField' => 'subEmbeddedEntity',
371
        ];
372
373
        $metadata->inlineEmbeddable('embeddedEntity', $this->getMetadataForEmbeddedEntity());
374
        $metadata->inlineEmbeddable('embeddedEntity.subEmbeddedEntity', $this->getMetadataForSubEmbeddedEntity());
375
376
        return $metadata;
377
    }
378
379
    public function getMetadataForContainerEntity()
380
    {
381
        $containerEntityClass = ContainerEntity::class;
382
        $associatedEntityClass = AssociatedEntity::class;
383
        $embeddedEntityClass = EmbeddedEntity::class;
384
        $subEmbeddedEntityClass = SubEmbeddedEntity::class;
385
386
        $metadata = new ClassMetadata($containerEntityClass);
387
388
        $metadata->fieldMappings = [
389
            'plainField' => [
390
                'fieldName' => 'plainField',
391
                'columnName' => 'plainField',
392
                'type' => 'integer',
393
            ],
394
        ];
395
396
        $metadata->associationMappings['associatedEntity'] = [
397
            'fieldName' => 'associatedEntity',
398
            'targetEntity' => $associatedEntityClass,
399
            'sourceEntity' => $containerEntityClass,
400
        ];
401
402
        $metadata->embeddedClasses['embeddedEntity'] = [
403
            'class' => $embeddedEntityClass,
404
            'columnPrefix' => 'embeddedEntity',
405
        ];
406
        $metadata->embeddedClasses['embeddedEntity.subEmbeddedEntity'] = [
407
            'class' => $subEmbeddedEntityClass,
408
            'columnPrefix' => 'embedded_entity_sub_embedded_entity_',
409
            'declaredField' => 'embeddedEntity',
410
            'originalField' => 'subEmbeddedEntity',
411
        ];
412
413
        $metadata->inlineEmbeddable('embeddedEntity', $this->getMetadataForEmbeddedEntity());
414
        $metadata->inlineEmbeddable('embeddedEntity.subEmbeddedEntity', $this->getMetadataForSubEmbeddedEntity());
415
416
        return $metadata;
417
    }
418
419
    public function testNonIntegerIdentifierType(): void
420
    {
421
        $uuid = new NonIntegerIdentifierTestClass('efbcfc4b-8c43-4d42-aa4c-d707e55151ac');
422
        $entity = new UuidEntity($uuid);
423
424
        $meta = $this->createMock(ClassMetadata::class);
425
        $meta->expects($this->any())
426
            ->method('getIdentifierValues')
427
            ->willReturn([$entity->getId()]);
428
        $meta->expects($this->any())
429
            ->method('getTypeOfField')
430
            ->willReturn(UuidType::NAME);
431
432
        $mf = $this->createMock(ClassMetadataFactory::class);
433
        $mf->expects($this->any())
434
            ->method('getMetadataFor')
435
            ->willReturn($meta);
436
437
        $platform = $this->createMock(PostgreSqlPlatform::class);
438
        $platform->expects($this->any())
439
            ->method('hasDoctrineTypeMappingFor')
440
            ->with(UuidType::NAME)
441
            ->willReturn(false);
442
        $platform->expects($this->never())
443
            ->method('getDoctrineTypeMapping');
444
445
        $conn = $this->createMock(Connection::class);
446
        $conn->expects($this->any())
447
            ->method('getDatabasePlatform')
448
            ->willReturn($platform);
449
450
        $em = $this->createMock(EntityManager::class);
451
        $em->expects($this->any())
452
            ->method('getMetadataFactory')
453
            ->willReturn($mf);
454
        $em->expects($this->any())
455
            ->method('getConnection')
456
            ->willReturn($conn);
457
458
        $registry = $this->createMock(ManagerRegistry::class);
459
        $registry->expects($this->any())
460
            ->method('getManagerForClass')
461
            ->willReturn($em);
462
463
        $manager = new ModelManager($registry);
464
        $result = $manager->getIdentifierValues($entity);
465
466
        $this->assertSame($entity->getId()->toString(), $result[0]);
467
    }
468
469
    public function testIntegerIdentifierType(): void
470
    {
471
        $id = new ProductId(12345);
472
        $entity = new Product($id, 'Some product');
473
474
        $meta = $this->createMock(ClassMetadata::class);
475
        $meta->expects($this->any())
476
            ->method('getIdentifierValues')
477
            ->willReturn([$entity->getId()]);
478
        $meta->expects($this->any())
479
            ->method('getTypeOfField')
480
            ->willReturn(ProductIdType::NAME);
481
482
        $mf = $this->createMock(ClassMetadataFactory::class);
483
        $mf->expects($this->any())
484
            ->method('getMetadataFor')
485
            ->willReturn($meta);
486
487
        $platform = $this->createMock(PostgreSqlPlatform::class);
488
        $platform->expects($this->any())
489
            ->method('hasDoctrineTypeMappingFor')
490
            ->with(ProductIdType::NAME)
491
            ->willReturn(false);
492
        $platform->expects($this->never())
493
            ->method('getDoctrineTypeMapping');
494
495
        $conn = $this->createMock(Connection::class);
496
        $conn->expects($this->any())
497
            ->method('getDatabasePlatform')
498
            ->willReturn($platform);
499
500
        $em = $this->createMock(EntityManager::class);
501
        $em->expects($this->any())
502
            ->method('getMetadataFactory')
503
            ->willReturn($mf);
504
        $em->expects($this->any())
505
            ->method('getConnection')
506
            ->willReturn($conn);
507
508
        $registry = $this->createMock(ManagerRegistry::class);
509
        $registry->expects($this->any())
510
            ->method('getManagerForClass')
511
            ->willReturn($em);
512
513
        $manager = new ModelManager($registry);
514
        $result = $manager->getIdentifierValues($entity);
515
516
        $this->assertSame((string) $entity->getId()->getId(), $result[0]);
517
    }
518
519
    public function testAssociationIdentifierType(): void
520
    {
521
        $entity = new ContainerEntity(new AssociatedEntity(42, new EmbeddedEntity()), new EmbeddedEntity());
522
523
        $meta = $this->createMock(ClassMetadata::class);
524
        $meta->expects($this->any())
525
            ->method('getIdentifierValues')
526
            ->willReturn([$entity->getAssociatedEntity()->getPlainField()]);
527
        $meta->expects($this->any())
528
            ->method('getTypeOfField')
529
            ->willReturn(null);
530
531
        $mf = $this->createMock(ClassMetadataFactory::class);
532
        $mf->expects($this->any())
533
            ->method('getMetadataFor')
534
            ->willReturn($meta);
535
536
        $platform = $this->createMock(PostgreSqlPlatform::class);
537
        $platform->expects($this->never())
538
            ->method('hasDoctrineTypeMappingFor');
539
540
        $conn = $this->createMock(Connection::class);
541
        $conn->expects($this->any())
542
            ->method('getDatabasePlatform')
543
            ->willReturn($platform);
544
545
        $em = $this->createMock(EntityManager::class);
546
        $em->expects($this->any())
547
            ->method('getMetadataFactory')
548
            ->willReturn($mf);
549
        $em->expects($this->any())
550
            ->method('getConnection')
551
            ->willReturn($conn);
552
553
        $registry = $this->createMock(ManagerRegistry::class);
554
        $registry->expects($this->any())
555
            ->method('getManagerForClass')
556
            ->willReturn($em);
557
558
        $manager = new ModelManager($registry);
559
        $result = $manager->getIdentifierValues($entity);
560
561
        $this->assertSame(42, $result[0]);
562
    }
563
564
    /**
565
     * [sortBy, sortOrder, isAddOrderBy].
566
     */
567
    public function getSortableInDataSourceIteratorDataProvider(): array
568
    {
569
        return [
570
            [null, null, false],
571
            ['', 'ASC', false],
572
            ['field', 'ASC', true],
573
            ['field', null, true],
574
        ];
575
    }
576
577
    /**
578
     * @dataProvider getSortableInDataSourceIteratorDataProvider
579
     *
580
     * @param string|null $sortBy
581
     * @param string|null $sortOrder
582
     * @param bool        $isAddOrderBy
583
     */
584
    public function testSortableInDataSourceIterator($sortBy, $sortOrder, $isAddOrderBy): void
585
    {
586
        $datagrid = $this->getMockForAbstractClass(DatagridInterface::class);
587
        $configuration = $this->getMockBuilder(Configuration::class)->getMock();
588
        $configuration->expects($this->any())
589
            ->method('getDefaultQueryHints')
590
            ->willReturn([]);
591
592
        $em = $this->getMockBuilder(EntityManager::class)
593
            ->disableOriginalConstructor()
594
            ->getMock();
595
596
        $em->expects($this->any())
597
            ->method('getConfiguration')
598
            ->willReturn($configuration);
599
600
        $queryBuilder = $this->getMockBuilder(QueryBuilder::class)
601
            ->setConstructorArgs([$em])
602
            ->getMock();
603
        $query = new Query($em);
604
605
        $proxyQuery = $this->getMockBuilder(ProxyQuery::class)
606
            ->setConstructorArgs([$queryBuilder])
607
            ->setMethods(['getSortBy', 'getSortOrder', 'getRootAliases'])
608
            ->getMock();
609
610
        $proxyQuery->expects($this->any())
611
            ->method('getSortOrder')
612
            ->willReturn($sortOrder);
613
614
        $proxyQuery->expects($this->any())
615
            ->method('getSortBy')
616
            ->willReturn($sortBy);
617
618
        $queryBuilder->expects($isAddOrderBy ? $this->atLeastOnce() : $this->never())
619
            ->method('addOrderBy');
620
621
        $proxyQuery->expects($this->any())
622
            ->method('getRootAliases')
623
            ->willReturn(['a']);
624
625
        $queryBuilder->expects($this->any())
626
            ->method('getQuery')
627
            ->willReturn($query);
628
629
        $datagrid->expects($this->any())
630
            ->method('getQuery')
631
            ->willReturn($proxyQuery);
632
633
        $registry = $this->getMockBuilder(ManagerRegistry::class)->getMock();
634
        $manager = new ModelManager($registry);
635
        $manager->getDataSourceIterator($datagrid, []);
636
637
        if ($isAddOrderBy) {
638
            $this->assertArrayHasKey($key = 'doctrine.customTreeWalkers', $hints = $query->getHints());
639
            $this->assertContains(OrderByToSelectWalker::class, $hints[$key]);
640
        }
641
    }
642
643
    public function testModelReverseTransform(): void
644
    {
645
        $class = SimpleEntity::class;
646
647
        $metadataFactory = $this->createMock(ClassMetadataFactory::class);
648
        $modelManager = $this->createMock(ObjectManager::class);
649
        $registry = $this->createMock(ManagerRegistry::class);
650
651
        $classMetadata = new ClassMetadata($class);
652
        $classMetadata->reflClass = new \ReflectionClass($class);
653
654
        $modelManager->expects($this->once())
655
            ->method('getMetadataFactory')
656
            ->willReturn($metadataFactory);
657
        $metadataFactory->expects($this->once())
658
            ->method('getMetadataFor')
659
            ->with($class)
660
            ->willReturn($classMetadata);
661
        $registry->expects($this->once())
662
            ->method('getManagerForClass')
663
            ->with($class)
664
            ->willReturn($modelManager);
665
666
        $manager = new ModelManager($registry);
667
        $this->assertInstanceOf($class, $object = $manager->modelReverseTransform(
668
            $class,
669
            [
670
                'schmeckles' => 42,
671
                'multi_word_property' => 'hello',
672
            ]
673
        ));
674
        $this->assertSame(42, $object->getSchmeckles());
675
        $this->assertSame('hello', $object->getMultiWordProperty());
676
    }
677
678
    public function testCollections(): void
679
    {
680
        $registry = $this->createMock(ManagerRegistry::class);
681
        $model = new ModelManager($registry);
682
683
        $collection = $model->getModelCollectionInstance('whyDoWeEvenHaveThisParameter');
684
        $this->assertInstanceOf(ArrayCollection::class, $collection);
685
686
        $item1 = 'item1';
687
        $item2 = 'item2';
688
        $model->collectionAddElement($collection, $item1);
689
        $model->collectionAddElement($collection, $item2);
690
691
        $this->assertTrue($model->collectionHasElement($collection, $item1));
692
693
        $model->collectionRemoveElement($collection, $item1);
694
695
        $this->assertFalse($model->collectionHasElement($collection, $item1));
696
697
        $model->collectionClear($collection);
698
699
        $this->assertTrue($collection->isEmpty());
700
    }
701
702
    public function testModelTransform(): void
703
    {
704
        $registry = $this->createMock(ManagerRegistry::class);
705
        $model = new ModelManager($registry);
706
707
        $result = $model->modelTransform('thisIsNotUsed', 'doWeNeedThisMethod');
708
709
        $this->assertSame('doWeNeedThisMethod', $result);
710
    }
711
712
    public function testGetPaginationParameters(): void
713
    {
714
        $datagrid = $this->createMock(DatagridInterface::class);
715
        $field = $this->createMock(FieldDescriptionInterface::class);
716
        $registry = $this->createMock(ManagerRegistry::class);
717
718
        $datagrid->expects($this->once())
719
            ->method('getValues')
720
            ->willReturn(['_sort_by' => $field]);
721
722
        $field->expects($this->once())
723
            ->method('getName')
724
            ->willReturn($name = 'test');
725
726
        $model = new ModelManager($registry);
727
728
        $result = $model->getPaginationParameters($datagrid, $page = 5);
729
730
        $this->assertSame($page, $result['filter']['_page']);
731
        $this->assertSame($name, $result['filter']['_sort_by']);
732
    }
733
734
    public function testGetModelInstanceException(): void
735
    {
736
        $registry = $this->createMock(ManagerRegistry::class);
737
738
        $model = new ModelManager($registry);
739
740
        $this->expectException(\RuntimeException::class);
741
742
        $model->getModelInstance(AbstractEntity::class);
743
    }
744
745
    public function testGetModelInstanceForProtectedEntity(): void
746
    {
747
        $registry = $this->createMock(ManagerRegistry::class);
748
749
        $model = new ModelManager($registry);
750
751
        $this->assertInstanceOf(ProtectedEntity::class, $model->getModelInstance(ProtectedEntity::class));
752
    }
753
754
    public function testGetEntityManagerException(): void
755
    {
756
        $registry = $this->createMock(ManagerRegistry::class);
757
758
        $model = new ModelManager($registry);
759
760
        $this->expectException(\RuntimeException::class);
761
762
        $model->getEntityManager(VersionedEntity::class);
763
    }
764
765
    public function testGetNewFieldDescriptionInstanceException(): void
766
    {
767
        $registry = $this->createMock(ManagerRegistry::class);
768
769
        $model = new ModelManager($registry);
770
771
        $this->expectException(\RuntimeException::class);
772
773
        $model->getNewFieldDescriptionInstance(VersionedEntity::class, [], []);
774
    }
775
776
    /**
777
     * @dataProvider createUpdateRemoveData
778
     */
779
    public function testCreate($exception): void
780
    {
781
        $registry = $this->createMock(ManagerRegistry::class);
782
783
        $entityManger = $this->createMock(EntityManager::class);
784
785
        $registry->expects($this->once())
786
            ->method('getManagerForClass')
787
            ->willReturn($entityManger);
788
789
        $entityManger->expects($this->once())
790
            ->method('persist');
791
792
        $entityManger->expects($this->once())
793
            ->method('flush')
794
            ->willThrowException($exception);
795
796
        $model = new ModelManager($registry);
797
798
        $this->expectException(ModelManagerException::class);
799
800
        $model->create(new VersionedEntity());
801
    }
802
803
    public function createUpdateRemoveData(): array
804
    {
805
        return [
806
            'PDOException' => [
807
                new \PDOException(),
808
            ],
809
            'DBALException' => [
810
                new DBALException(),
811
            ],
812
        ];
813
    }
814
815
    /**
816
     * @dataProvider createUpdateRemoveData
817
     */
818
    public function testUpdate($exception): void
819
    {
820
        $registry = $this->createMock(ManagerRegistry::class);
821
822
        $entityManger = $this->createMock(EntityManager::class);
823
824
        $registry->expects($this->once())
825
            ->method('getManagerForClass')
826
            ->willReturn($entityManger);
827
828
        $entityManger->expects($this->once())
829
            ->method('persist');
830
831
        $entityManger->expects($this->once())
832
            ->method('flush')
833
            ->willThrowException($exception);
834
835
        $model = new ModelManager($registry);
836
837
        $this->expectException(ModelManagerException::class);
838
839
        $model->update(new VersionedEntity());
840
    }
841
842
    /**
843
     * @dataProvider createUpdateRemoveData
844
     */
845
    public function testRemove($exception): void
846
    {
847
        $registry = $this->createMock(ManagerRegistry::class);
848
849
        $entityManger = $this->createMock(EntityManager::class);
850
851
        $registry->expects($this->once())
852
            ->method('getManagerForClass')
853
            ->willReturn($entityManger);
854
855
        $entityManger->expects($this->once())
856
            ->method('remove');
857
858
        $entityManger->expects($this->once())
859
            ->method('flush')
860
            ->willThrowException($exception);
861
862
        $model = new ModelManager($registry);
863
864
        $this->expectException(ModelManagerException::class);
865
866
        $model->delete(new VersionedEntity());
867
    }
868
869
    public function testFindBadId(): void
870
    {
871
        $registry = $this->createMock(ManagerRegistry::class);
872
873
        $model = new ModelManager($registry);
874
875
        $this->assertNull($model->find('notImportant', null));
876
    }
877
878
    /**
879
     * @dataProvider getWrongEntities
880
     *
881
     * @param mixed $entity
882
     */
883
    public function testNormalizedIdentifierException($entity): void
884
    {
885
        $registry = $this->createMock(ManagerRegistry::class);
886
887
        $model = new ModelManager($registry);
888
889
        $this->expectException(\RuntimeException::class);
890
891
        $model->getNormalizedIdentifier($entity);
892
    }
893
894
    public function getWrongEntities(): iterable
895
    {
896
        yield [0];
897
        yield [1];
898
        yield [false];
899
        yield [true];
900
        yield [[]];
901
        yield [''];
902
        yield ['sonata-project'];
903
    }
904
905
    public function testGetUrlsafeIdentifierNull(): void
906
    {
907
        $registry = $this->createMock(ManagerRegistry::class);
908
909
        $model = new ModelManager($registry);
910
911
        $this->assertNull($model->getNormalizedIdentifier(null));
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