Completed
Pull Request — master (#957)
by Grégoire
10:39
created

ModelManagerTest::getMetadata()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 2
nc 2
nop 2
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\ManagerRegistry;
18
use Doctrine\Common\Persistence\ObjectManager;
19
use Doctrine\DBAL\Connection;
20
use Doctrine\DBAL\DBALException;
21
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
22
use Doctrine\DBAL\Types\Type;
23
use Doctrine\ORM\Configuration;
24
use Doctrine\ORM\EntityManager;
25
use Doctrine\ORM\EntityManagerInterface;
26
use Doctrine\ORM\Mapping\ClassMetadata;
27
use Doctrine\ORM\Mapping\ClassMetadataFactory;
28
use Doctrine\ORM\OptimisticLockException;
29
use Doctrine\ORM\Query;
30
use Doctrine\ORM\QueryBuilder;
31
use Doctrine\ORM\Version;
32
use PHPUnit\Framework\TestCase;
33
use Sonata\AdminBundle\Datagrid\Datagrid;
34
use Sonata\AdminBundle\Datagrid\DatagridInterface;
35
use Sonata\AdminBundle\Exception\LockException;
36
use Sonata\AdminBundle\Exception\ModelManagerException;
37
use Sonata\AdminBundle\Filter\FilterInterface;
38
use Sonata\DoctrineORMAdminBundle\Admin\FieldDescription;
39
use Sonata\DoctrineORMAdminBundle\Datagrid\OrderByToSelectWalker;
40
use Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery;
41
use Sonata\DoctrineORMAdminBundle\Model\ModelManager;
42
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\ProductIdType;
43
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\UuidBinaryType;
44
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\DoctrineType\UuidType;
45
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\AbstractEntity;
46
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\AssociatedEntity;
47
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\ContainerEntity;
48
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\Embeddable\EmbeddedEntity;
49
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\Embeddable\SubEmbeddedEntity;
50
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\Product;
51
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\ProductId;
52
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\ProtectedEntity;
53
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\SimpleEntity;
54
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\UuidEntity;
55
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Entity\VersionedEntity;
56
use Sonata\DoctrineORMAdminBundle\Tests\Fixtures\Util\NonIntegerIdentifierTestClass;
57
use Symfony\Bridge\Doctrine\RegistryInterface;
58
59
class ModelManagerTest extends TestCase
60
{
61
    public static function setUpBeforeClass(): void
62
    {
63
        if (!Type::hasType(UuidType::NAME)) {
64
            Type::addType(UuidType::NAME, UuidType::class);
65
        }
66
        if (!Type::hasType(UuidBinaryType::NAME)) {
67
            Type::addType(UuidBinaryType::NAME, UuidBinaryType::class);
68
        }
69
        if (!Type::hasType(ProductIdType::NAME)) {
70
            Type::addType(ProductIdType::NAME, ProductIdType::class);
71
        }
72
    }
73
74
    public function testInstantiateWithDeprecatedRegistryInterface(): void
75
    {
76
        $registry = $this->createMock(RegistryInterface::class);
77
        $manager = new ModelManager($registry);
78
        $em = $this->createMock(EntityManagerInterface::class);
79
80
        $registry->expects($this->once())
81
            ->method('getManagerForClass')
82
            ->with('x')
83
            ->willReturn($em)
84
        ;
85
        $this->assertSame($em, $manager->getEntityManager('x'));
86
    }
87
88
    public function testSortParameters(): void
89
    {
90
        $registry = $this->createMock(ManagerRegistry::class);
91
92
        $manager = new ModelManager($registry);
93
94
        $datagrid1 = $this->createMock(Datagrid::class);
95
        $datagrid2 = $this->createMock(Datagrid::class);
96
97
        $field1 = new FieldDescription();
98
        $field1->setName('field1');
99
100
        $field2 = new FieldDescription();
101
        $field2->setName('field2');
102
103
        $field3 = new FieldDescription();
104
        $field3->setName('field3');
105
        $field3->setOption('sortable', 'field3sortBy');
106
107
        $datagrid1
108
            ->expects($this->any())
109
            ->method('getValues')
110
            ->willReturn([
111
                '_sort_by' => $field1,
112
                '_sort_order' => 'ASC',
113
            ]);
114
115
        $datagrid2
116
            ->expects($this->any())
117
            ->method('getValues')
118
            ->willReturn([
119
                '_sort_by' => $field3,
120
                '_sort_order' => 'ASC',
121
            ]);
122
123
        $parameters = $manager->getSortParameters($field1, $datagrid1);
124
125
        $this->assertSame('DESC', $parameters['filter']['_sort_order']);
126
        $this->assertSame('field1', $parameters['filter']['_sort_by']);
127
128
        $parameters = $manager->getSortParameters($field2, $datagrid1);
129
130
        $this->assertSame('ASC', $parameters['filter']['_sort_order']);
131
        $this->assertSame('field2', $parameters['filter']['_sort_by']);
132
133
        $parameters = $manager->getSortParameters($field3, $datagrid1);
134
135
        $this->assertSame('ASC', $parameters['filter']['_sort_order']);
136
        $this->assertSame('field3sortBy', $parameters['filter']['_sort_by']);
137
138
        $parameters = $manager->getSortParameters($field3, $datagrid2);
139
140
        $this->assertSame('DESC', $parameters['filter']['_sort_order']);
141
        $this->assertSame('field3sortBy', $parameters['filter']['_sort_by']);
142
    }
143
144
    public function getVersionDataProvider(): array
145
    {
146
        return [
147
            [true],
148
            [false],
149
        ];
150
    }
151
152
    /**
153
     * @dataProvider getVersionDataProvider
154
     */
155
    public function testGetVersion($isVersioned): void
156
    {
157
        $object = new VersionedEntity();
158
159
        $modelManager = $this->getMockBuilder(ModelManager::class)
160
            ->disableOriginalConstructor()
161
            ->setMethods(['getMetadata'])
162
            ->getMock();
163
164
        $metadata = $this->getMetadata(\get_class($object), $isVersioned);
165
166
        $modelManager->expects($this->any())
167
            ->method('getMetadata')
168
            ->willReturn($metadata);
169
170
        if ($isVersioned) {
171
            $object->version = 123;
172
173
            $this->assertNotNull($modelManager->getLockVersion($object));
174
        } else {
175
            $this->assertNull($modelManager->getLockVersion($object));
176
        }
177
    }
178
179
    public function lockDataProvider(): array
180
    {
181
        return [
182
            [true,  false],
183
            [true,  true],
184
            [false, false],
185
        ];
186
    }
187
188
    /**
189
     * @dataProvider lockDataProvider
190
     */
191
    public function testLock($isVersioned, $expectsException): void
192
    {
193
        $object = new VersionedEntity();
194
195
        $em = $this->getMockBuilder(EntityManager::class)
196
            ->disableOriginalConstructor()
197
            ->setMethods(['lock'])
198
            ->getMock();
199
200
        $modelManager = $this->getMockBuilder(ModelManager::class)
201
            ->disableOriginalConstructor()
202
            ->setMethods(['getMetadata', 'getEntityManager'])
203
            ->getMock();
204
205
        $modelManager->expects($this->any())
206
            ->method('getEntityManager')
207
            ->willReturn($em);
208
209
        $metadata = $this->getMetadata(\get_class($object), $isVersioned);
210
211
        $modelManager->expects($this->any())
212
            ->method('getMetadata')
213
            ->willReturn($metadata);
214
215
        $em->expects($isVersioned ? $this->once() : $this->never())
216
            ->method('lock');
217
218
        if ($expectsException) {
219
            $em->expects($this->once())
220
                ->method('lock')
221
                ->will($this->throwException(OptimisticLockException::lockFailed($object)));
222
223
            $this->expectException(LockException::class);
224
        }
225
226
        $modelManager->lock($object, 123);
227
    }
228
229
    public function testGetParentMetadataForProperty(): void
230
    {
231
        if (version_compare(Version::VERSION, '2.5') < 0) {
232
            $this->markTestSkipped('Test for embeddables needs to run on Doctrine >= 2.5');
233
234
            return;
235
        }
236
237
        $containerEntityClass = ContainerEntity::class;
238
        $associatedEntityClass = AssociatedEntity::class;
239
        $embeddedEntityClass = EmbeddedEntity::class;
240
        $modelManagerClass = ModelManager::class;
241
242
        $em = $this->createMock(EntityManager::class);
243
244
        /** @var \PHPUnit_Framework_MockObject_MockObject|ModelManager $modelManager */
245
        $modelManager = $this->getMockBuilder($modelManagerClass)
246
            ->disableOriginalConstructor()
247
            ->setMethods(['getMetadata', 'getEntityManager'])
248
            ->getMock();
249
250
        $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...
251
            ->method('getEntityManager')
252
            ->willReturn($em);
253
254
        $containerEntityMetadata = $this->getMetadataForContainerEntity();
255
        $associatedEntityMetadata = $this->getMetadataForAssociatedEntity();
256
        $embeddedEntityMetadata = $this->getMetadataForEmbeddedEntity();
257
258
        $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...
259
            ->willReturnMap(
260
261
                    [
262
                        [$containerEntityClass, $containerEntityMetadata],
263
                        [$embeddedEntityClass, $embeddedEntityMetadata],
264
                        [$associatedEntityClass, $associatedEntityMetadata],
265
                    ]
266
267
            );
268
269
        /** @var ClassMetadata $metadata */
270
        list($metadata, $lastPropertyName) = $modelManager
271
            ->getParentMetadataForProperty($containerEntityClass, 'plainField');
272
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'integer');
273
274
        list($metadata, $lastPropertyName) = $modelManager
275
            ->getParentMetadataForProperty($containerEntityClass, 'associatedEntity.plainField');
276
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'string');
277
278
        list($metadata, $lastPropertyName) = $modelManager
279
            ->getParentMetadataForProperty($containerEntityClass, 'embeddedEntity.plainField');
280
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
281
282
        list($metadata, $lastPropertyName) = $modelManager
283
            ->getParentMetadataForProperty($containerEntityClass, 'associatedEntity.embeddedEntity.plainField');
284
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
285
286
        list($metadata, $lastPropertyName) = $modelManager
287
            ->getParentMetadataForProperty(
288
                $containerEntityClass,
289
                'associatedEntity.embeddedEntity.subEmbeddedEntity.plainField'
290
            );
291
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
292
    }
293
294
    public function getMetadataForEmbeddedEntity()
295
    {
296
        $metadata = new ClassMetadata(EmbeddedEntity::class);
297
298
        $metadata->fieldMappings = [
299
            'plainField' => [
300
                'fieldName' => 'plainField',
301
                'columnName' => 'plainField',
302
                'type' => 'boolean',
303
            ],
304
        ];
305
306
        return $metadata;
307
    }
308
309
    public function getMetadataForSubEmbeddedEntity()
310
    {
311
        $metadata = new ClassMetadata(SubEmbeddedEntity::class);
312
313
        $metadata->fieldMappings = [
314
            'plainField' => [
315
                'fieldName' => 'plainField',
316
                'columnName' => 'plainField',
317
                'type' => 'boolean',
318
            ],
319
        ];
320
321
        return $metadata;
322
    }
323
324
    public function getMetadataForAssociatedEntity()
325
    {
326
        $embeddedEntityClass = EmbeddedEntity::class;
327
        $subEmbeddedEntityClass = SubEmbeddedEntity::class;
328
329
        $metadata = new ClassMetadata(AssociatedEntity::class);
330
331
        $metadata->fieldMappings = [
332
            'plainField' => [
333
                'fieldName' => 'plainField',
334
                'columnName' => 'plainField',
335
                'type' => 'string',
336
            ],
337
        ];
338
339
        $metadata->embeddedClasses['embeddedEntity'] = [
340
            'class' => $embeddedEntityClass,
341
            'columnPrefix' => 'embedded_entity_',
342
        ];
343
        $metadata->embeddedClasses['embeddedEntity.subEmbeddedEntity'] = [
344
            'class' => $subEmbeddedEntityClass,
345
            'columnPrefix' => 'embedded_entity_sub_embedded_entity_',
346
            'declaredField' => 'embeddedEntity',
347
            'originalField' => 'subEmbeddedEntity',
348
        ];
349
350
        $metadata->inlineEmbeddable('embeddedEntity', $this->getMetadataForEmbeddedEntity());
351
        $metadata->inlineEmbeddable('embeddedEntity.subEmbeddedEntity', $this->getMetadataForSubEmbeddedEntity());
352
353
        return $metadata;
354
    }
355
356
    public function getMetadataForContainerEntity()
357
    {
358
        $containerEntityClass = ContainerEntity::class;
359
        $associatedEntityClass = AssociatedEntity::class;
360
        $embeddedEntityClass = EmbeddedEntity::class;
361
        $subEmbeddedEntityClass = SubEmbeddedEntity::class;
362
363
        $metadata = new ClassMetadata($containerEntityClass);
364
365
        $metadata->fieldMappings = [
366
            'plainField' => [
367
                'fieldName' => 'plainField',
368
                'columnName' => 'plainField',
369
                'type' => 'integer',
370
            ],
371
        ];
372
373
        $metadata->associationMappings['associatedEntity'] = [
374
            'fieldName' => 'associatedEntity',
375
            'targetEntity' => $associatedEntityClass,
376
            'sourceEntity' => $containerEntityClass,
377
        ];
378
379
        $metadata->embeddedClasses['embeddedEntity'] = [
380
            'class' => $embeddedEntityClass,
381
            'columnPrefix' => 'embeddedEntity',
382
        ];
383
        $metadata->embeddedClasses['embeddedEntity.subEmbeddedEntity'] = [
384
            'class' => $subEmbeddedEntityClass,
385
            'columnPrefix' => 'embedded_entity_sub_embedded_entity_',
386
            'declaredField' => 'embeddedEntity',
387
            'originalField' => 'subEmbeddedEntity',
388
        ];
389
390
        $metadata->inlineEmbeddable('embeddedEntity', $this->getMetadataForEmbeddedEntity());
391
        $metadata->inlineEmbeddable('embeddedEntity.subEmbeddedEntity', $this->getMetadataForSubEmbeddedEntity());
392
393
        return $metadata;
394
    }
395
396
    public function testNonIntegerIdentifierType(): void
397
    {
398
        $uuid = new NonIntegerIdentifierTestClass('efbcfc4b-8c43-4d42-aa4c-d707e55151ac');
399
        $entity = new UuidEntity($uuid);
400
401
        $meta = $this->createMock(ClassMetadata::class);
402
        $meta->expects($this->any())
403
            ->method('getIdentifierValues')
404
            ->willReturn([$entity->getId()]);
405
        $meta->expects($this->any())
406
            ->method('getTypeOfField')
407
            ->willReturn(UuidType::NAME);
408
409
        $mf = $this->createMock(ClassMetadataFactory::class);
410
        $mf->expects($this->any())
411
            ->method('getMetadataFor')
412
            ->willReturn($meta);
413
414
        $platform = $this->createMock(PostgreSqlPlatform::class);
415
        $platform->expects($this->any())
416
            ->method('hasDoctrineTypeMappingFor')
417
            ->with(UuidType::NAME)
418
            ->willReturn(false);
419
        $platform->expects($this->never())
420
            ->method('getDoctrineTypeMapping');
421
422
        $conn = $this->createMock(Connection::class);
423
        $conn->expects($this->any())
424
            ->method('getDatabasePlatform')
425
            ->willReturn($platform);
426
427
        $em = $this->createMock(EntityManager::class);
428
        $em->expects($this->any())
429
            ->method('getMetadataFactory')
430
            ->willReturn($mf);
431
        $em->expects($this->any())
432
            ->method('getConnection')
433
            ->willReturn($conn);
434
435
        $registry = $this->createMock(ManagerRegistry::class);
436
        $registry->expects($this->any())
437
            ->method('getManagerForClass')
438
            ->willReturn($em);
439
440
        $manager = new ModelManager($registry);
441
        $result = $manager->getIdentifierValues($entity);
442
443
        $this->assertSame($entity->getId()->toString(), $result[0]);
444
    }
445
446
    public function testIntegerIdentifierType(): void
447
    {
448
        $id = new ProductId(12345);
449
        $entity = new Product($id, 'Some product');
450
451
        $meta = $this->createMock(ClassMetadata::class);
452
        $meta->expects($this->any())
453
            ->method('getIdentifierValues')
454
            ->willReturn([$entity->getId()]);
455
        $meta->expects($this->any())
456
            ->method('getTypeOfField')
457
            ->willReturn(ProductIdType::NAME);
458
459
        $mf = $this->createMock(ClassMetadataFactory::class);
460
        $mf->expects($this->any())
461
            ->method('getMetadataFor')
462
            ->willReturn($meta);
463
464
        $platform = $this->createMock(PostgreSqlPlatform::class);
465
        $platform->expects($this->any())
466
            ->method('hasDoctrineTypeMappingFor')
467
            ->with(ProductIdType::NAME)
468
            ->willReturn(false);
469
        $platform->expects($this->never())
470
            ->method('getDoctrineTypeMapping');
471
472
        $conn = $this->createMock(Connection::class);
473
        $conn->expects($this->any())
474
            ->method('getDatabasePlatform')
475
            ->willReturn($platform);
476
477
        $em = $this->createMock(EntityManager::class);
478
        $em->expects($this->any())
479
            ->method('getMetadataFactory')
480
            ->willReturn($mf);
481
        $em->expects($this->any())
482
            ->method('getConnection')
483
            ->willReturn($conn);
484
485
        $registry = $this->createMock(ManagerRegistry::class);
486
        $registry->expects($this->any())
487
            ->method('getManagerForClass')
488
            ->willReturn($em);
489
490
        $manager = new ModelManager($registry);
491
        $result = $manager->getIdentifierValues($entity);
492
493
        $this->assertSame((string) $entity->getId()->getId(), $result[0]);
494
    }
495
496
    public function testAssociationIdentifierType(): void
497
    {
498
        $entity = new ContainerEntity(new AssociatedEntity(42, new EmbeddedEntity()), new EmbeddedEntity());
499
500
        $meta = $this->createMock(ClassMetadata::class);
501
        $meta->expects($this->any())
502
            ->method('getIdentifierValues')
503
            ->willReturn([$entity->getAssociatedEntity()->getPlainField()]);
504
        $meta->expects($this->any())
505
            ->method('getTypeOfField')
506
            ->willReturn(null);
507
508
        $mf = $this->createMock(ClassMetadataFactory::class);
509
        $mf->expects($this->any())
510
            ->method('getMetadataFor')
511
            ->willReturn($meta);
512
513
        $platform = $this->createMock(PostgreSqlPlatform::class);
514
        $platform->expects($this->never())
515
            ->method('hasDoctrineTypeMappingFor');
516
517
        $conn = $this->createMock(Connection::class);
518
        $conn->expects($this->any())
519
            ->method('getDatabasePlatform')
520
            ->willReturn($platform);
521
522
        $em = $this->createMock(EntityManager::class);
523
        $em->expects($this->any())
524
            ->method('getMetadataFactory')
525
            ->willReturn($mf);
526
        $em->expects($this->any())
527
            ->method('getConnection')
528
            ->willReturn($conn);
529
530
        $registry = $this->createMock(ManagerRegistry::class);
531
        $registry->expects($this->any())
532
            ->method('getManagerForClass')
533
            ->willReturn($em);
534
535
        $manager = new ModelManager($registry);
536
        $result = $manager->getIdentifierValues($entity);
537
538
        $this->assertSame(42, $result[0]);
539
    }
540
541
    /**
542
     * [sortBy, sortOrder, isAddOrderBy].
543
     */
544
    public function getSortableInDataSourceIteratorDataProvider(): array
545
    {
546
        return [
547
            [null, null, false],
548
            ['', 'ASC', false],
549
            ['field', 'ASC', true],
550
            ['field', null, true],
551
        ];
552
    }
553
554
    /**
555
     * @dataProvider getSortableInDataSourceIteratorDataProvider
556
     *
557
     * @param string|null $sortBy
558
     * @param string|null $sortOrder
559
     * @param bool        $isAddOrderBy
560
     */
561
    public function testSortableInDataSourceIterator($sortBy, $sortOrder, $isAddOrderBy): void
562
    {
563
        $datagrid = $this->getMockForAbstractClass(DatagridInterface::class);
564
        $configuration = $this->getMockBuilder(Configuration::class)->getMock();
565
        $configuration->expects($this->any())
566
            ->method('getDefaultQueryHints')
567
            ->willReturn([]);
568
569
        $em = $this->getMockBuilder(EntityManager::class)
570
            ->disableOriginalConstructor()
571
            ->getMock();
572
573
        $em->expects($this->any())
574
            ->method('getConfiguration')
575
            ->willReturn($configuration);
576
577
        $queryBuilder = $this->getMockBuilder(QueryBuilder::class)
578
            ->setConstructorArgs([$em])
579
            ->getMock();
580
        $query = new Query($em);
581
582
        $proxyQuery = $this->getMockBuilder(ProxyQuery::class)
583
            ->setConstructorArgs([$queryBuilder])
584
            ->setMethods(['getSortBy', 'getSortOrder', 'getRootAliases'])
585
            ->getMock();
586
587
        $proxyQuery->expects($this->any())
588
            ->method('getSortOrder')
589
            ->willReturn($sortOrder);
590
591
        $proxyQuery->expects($this->any())
592
            ->method('getSortBy')
593
            ->willReturn($sortBy);
594
595
        $queryBuilder->expects($isAddOrderBy ? $this->atLeastOnce() : $this->never())
596
            ->method('addOrderBy');
597
598
        $proxyQuery->expects($this->any())
599
            ->method('getRootAliases')
600
            ->willReturn(['a']);
601
602
        $queryBuilder->expects($this->any())
603
            ->method('getQuery')
604
            ->willReturn($query);
605
606
        $datagrid->expects($this->any())
607
            ->method('getQuery')
608
            ->willReturn($proxyQuery);
609
610
        $registry = $this->getMockBuilder(RegistryInterface::class)->getMock();
611
        $manager = new ModelManager($registry);
612
        $manager->getDataSourceIterator($datagrid, []);
613
614
        if ($isAddOrderBy) {
615
            $this->assertArrayHasKey($key = 'doctrine.customTreeWalkers', $hints = $query->getHints());
616
            $this->assertContains(OrderByToSelectWalker::class, $hints[$key]);
617
        }
618
    }
619
620
    public function testModelReverseTransform(): void
621
    {
622
        $class = SimpleEntity::class;
623
624
        $metadataFactory = $this->createMock(ClassMetadataFactory::class);
625
        $modelManager = $this->createMock(ObjectManager::class);
626
        $registry = $this->createMock(ManagerRegistry::class);
627
628
        $classMetadata = new ClassMetadata($class);
629
        $classMetadata->reflClass = new \ReflectionClass($class);
630
631
        $modelManager->expects($this->once())
632
            ->method('getMetadataFactory')
633
            ->willReturn($metadataFactory);
634
        $metadataFactory->expects($this->once())
635
            ->method('getMetadataFor')
636
            ->with($class)
637
            ->willReturn($classMetadata);
638
        $registry->expects($this->once())
639
            ->method('getManagerForClass')
640
            ->with($class)
641
            ->willReturn($modelManager);
642
643
        $manager = new ModelManager($registry);
644
        $this->assertInstanceOf($class, $object = $manager->modelReverseTransform(
645
            $class,
646
            [
647
                'schmeckles' => 42,
648
                'multi_word_property' => 'hello',
649
            ]
650
        ));
651
        $this->assertSame(42, $object->getSchmeckles());
652
        $this->assertSame('hello', $object->getMultiWordProperty());
653
    }
654
655
    public function testCollections(): void
656
    {
657
        $registry = $this->createMock(ManagerRegistry::class);
658
        $model = new ModelManager($registry);
659
660
        $collection = $model->getModelCollectionInstance('whyDoWeEvenHaveThisParameter');
661
        $this->assertInstanceOf(ArrayCollection::class, $collection);
662
663
        $item1 = 'item1';
664
        $item2 = 'item2';
665
        $model->collectionAddElement($collection, $item1);
0 ignored issues
show
Bug introduced by
It seems like $collection defined by $model->getModelCollecti...EvenHaveThisParameter') on line 660 can also be of type object<ArrayAccess>; however, Sonata\DoctrineORMAdminB...:collectionAddElement() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Documentation introduced by
$item1 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...
666
        $model->collectionAddElement($collection, $item2);
0 ignored issues
show
Documentation introduced by
$item2 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...
667
668
        $this->assertTrue($model->collectionHasElement($collection, $item1));
669
670
        $model->collectionRemoveElement($collection, $item1);
671
672
        $this->assertFalse($model->collectionHasElement($collection, $item1));
673
674
        $model->collectionClear($collection);
675
676
        $this->assertTrue($collection->isEmpty());
0 ignored issues
show
Bug introduced by
The method isEmpty cannot be called on $collection (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
677
    }
678
679
    public function testModelTransform(): void
680
    {
681
        $registry = $this->createMock(ManagerRegistry::class);
682
        $model = new ModelManager($registry);
683
684
        $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...
685
686
        $this->assertSame('doWeNeedThisMethod', $result);
687
    }
688
689
    public function testGetPaginationParameters(): void
690
    {
691
        $datagrid = $this->createMock(DatagridInterface::class);
692
        $filter = $this->createMock(FilterInterface::class);
693
        $registry = $this->createMock(ManagerRegistry::class);
694
695
        $datagrid->expects($this->once())
696
            ->method('getValues')
697
            ->willReturn(['_sort_by' => $filter]);
698
699
        $filter->expects($this->once())
700
            ->method('getName')
701
            ->willReturn($name = 'test');
702
703
        $model = new ModelManager($registry);
704
705
        $result = $model->getPaginationParameters($datagrid, $page = 5);
706
707
        $this->assertSame($page, $result['filter']['_page']);
708
        $this->assertSame($name, $result['filter']['_sort_by']);
709
    }
710
711
    public function testGetModelInstanceException(): void
712
    {
713
        $registry = $this->createMock(ManagerRegistry::class);
714
715
        $model = new ModelManager($registry);
716
717
        $this->expectException(\RuntimeException::class);
718
719
        $model->getModelInstance(AbstractEntity::class);
720
    }
721
722
    public function testGetModelInstanceForProtectedEntity(): void
723
    {
724
        $registry = $this->createMock(ManagerRegistry::class);
725
726
        $model = new ModelManager($registry);
727
728
        $this->assertInstanceOf(ProtectedEntity::class, $model->getModelInstance(ProtectedEntity::class));
729
    }
730
731
    public function testGetEntityManagerException(): void
732
    {
733
        $registry = $this->createMock(ManagerRegistry::class);
734
735
        $model = new ModelManager($registry);
736
737
        $this->expectException(\RuntimeException::class);
738
739
        $model->getEntityManager(VersionedEntity::class);
740
    }
741
742
    public function testGetNewFieldDescriptionInstanceException(): void
743
    {
744
        $registry = $this->createMock(ManagerRegistry::class);
745
746
        $model = new ModelManager($registry);
747
748
        $this->expectException(\RuntimeException::class);
749
750
        $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...
751
    }
752
753
    /**
754
     * @dataProvider createUpdateRemoveData
755
     */
756
    public function testCreate($exception): void
757
    {
758
        $registry = $this->createMock(ManagerRegistry::class);
759
760
        $entityManger = $this->createMock(EntityManager::class);
761
762
        $registry->expects($this->once())
763
            ->method('getManagerForClass')
764
            ->willReturn($entityManger);
765
766
        $entityManger->expects($this->once())
767
            ->method('persist');
768
769
        $entityManger->expects($this->once())
770
            ->method('flush')
771
            ->willThrowException($exception);
772
773
        $model = new ModelManager($registry);
774
775
        $this->expectException(ModelManagerException::class);
776
777
        $model->create(new VersionedEntity());
778
    }
779
780
    public function createUpdateRemoveData(): array
781
    {
782
        return [
783
            'PDOException' => [
784
                new \PDOException(),
785
            ],
786
            'DBALException' => [
787
                new DBALException(),
788
            ],
789
        ];
790
    }
791
792
    /**
793
     * @dataProvider createUpdateRemoveData
794
     */
795
    public function testUpdate($exception): void
796
    {
797
        $registry = $this->createMock(ManagerRegistry::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->update(new VersionedEntity());
817
    }
818
819
    /**
820
     * @dataProvider createUpdateRemoveData
821
     */
822
    public function testRemove($exception): void
823
    {
824
        $registry = $this->createMock(ManagerRegistry::class);
825
826
        $entityManger = $this->createMock(EntityManager::class);
827
828
        $registry->expects($this->once())
829
            ->method('getManagerForClass')
830
            ->willReturn($entityManger);
831
832
        $entityManger->expects($this->once())
833
            ->method('remove');
834
835
        $entityManger->expects($this->once())
836
            ->method('flush')
837
            ->willThrowException($exception);
838
839
        $model = new ModelManager($registry);
840
841
        $this->expectException(ModelManagerException::class);
842
843
        $model->delete(new VersionedEntity());
844
    }
845
846
    public function testFindBadId(): void
847
    {
848
        $registry = $this->createMock(ManagerRegistry::class);
849
850
        $model = new ModelManager($registry);
851
852
        $this->assertNull($model->find('notImportant', null));
853
    }
854
855
    public function testGetUrlsafeIdentifierException(): void
856
    {
857
        $registry = $this->createMock(ManagerRegistry::class);
858
859
        $model = new ModelManager($registry);
860
861
        $this->expectException(\RuntimeException::class);
862
863
        $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...
864
    }
865
866
    public function testGetUrlsafeIdentifierNull(): void
867
    {
868
        $registry = $this->createMock(ManagerRegistry::class);
869
870
        $model = new ModelManager($registry);
871
872
        $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...
873
    }
874
875
    private function getMetadata($class, $isVersioned)
876
    {
877
        $metadata = new ClassMetadata($class);
878
879
        $metadata->isVersioned = $isVersioned;
880
881
        if ($isVersioned) {
882
            $versionField = 'version';
883
            $metadata->versionField = $versionField;
884
            $metadata->reflFields[$versionField] = new \ReflectionProperty($class, $versionField);
885
        }
886
887
        return $metadata;
888
    }
889
}
890