Completed
Push — master ( d83bed...5bb566 )
by
unknown
12:00 queued 11s
created

testGetIdentifierValuesWhenIdentifierIsValueObjectWithToStringMethod()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

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