Completed
Push — 3.x ( 23a2fd...bf74f2 )
by Oskar
01:27
created

testInstantiateWithDeprecatedRegistryInterface()   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\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()
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()
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 testGetIdentifierValuesForIdInObjectTypeBinaryToStringSupport(): void
397
    {
398
        $uuid = new NonIntegerIdentifierTestClass('efbcfc4b-8c43-4d42-aa4c-d707e55151ac');
399
400
        $entity = new UuidEntity($uuid);
401
402
        $meta = $this->createMock(ClassMetadata::class);
403
        $meta->expects($this->any())
404
            ->method('getIdentifierValues')
405
            ->willReturn([$entity->getId()]);
406
        $meta->expects($this->any())
407
            ->method('getTypeOfField')
408
            ->willReturn(UuidBinaryType::NAME); //'uuid_binary'
409
410
        $mf = $this->createMock(ClassMetadataFactory::class);
411
        $mf->expects($this->any())
412
            ->method('getMetadataFor')
413
            ->willReturn($meta);
414
415
        $platform = $this->createMock(PostgreSqlPlatform::class);
416
        $platform->expects($this->any())
417
            ->method('hasDoctrineTypeMappingFor')
418
            ->with(UuidBinaryType::NAME)
419
            ->willReturn(true);
420
        $platform->expects($this->any())
421
            ->method('getDoctrineTypeMapping')
422
            ->with(UuidBinaryType::NAME)
423
            ->willReturn('binary');
424
425
        $conn = $this->createMock(Connection::class);
426
        $conn->expects($this->any())
427
            ->method('getDatabasePlatform')
428
            ->willReturn($platform);
429
430
        $em = $this->createMock(EntityManager::class);
431
        $em->expects($this->any())
432
            ->method('getMetadataFactory')
433
            ->willReturn($mf);
434
        $em->expects($this->any())
435
            ->method('getConnection')
436
            ->willReturn($conn);
437
438
        $registry = $this->createMock(ManagerRegistry::class);
439
        $registry->expects($this->any())
440
            ->method('getManagerForClass')
441
            ->willReturn($em);
442
443
        $manager = new ModelManager($registry);
444
        $result = $manager->getIdentifierValues($entity);
445
446
        $this->assertSame($entity->getId()->toString(), $result[0]);
447
    }
448
449
    public function testNonIntegerIdentifierType(): void
450
    {
451
        $uuid = new NonIntegerIdentifierTestClass('efbcfc4b-8c43-4d42-aa4c-d707e55151ac');
452
        $entity = new UuidEntity($uuid);
453
454
        $meta = $this->createMock(ClassMetadata::class);
455
        $meta->expects($this->any())
456
            ->method('getIdentifierValues')
457
            ->willReturn([$entity->getId()]);
458
        $meta->expects($this->any())
459
            ->method('getTypeOfField')
460
            ->willReturn(UuidType::NAME);
461
462
        $mf = $this->createMock(ClassMetadataFactory::class);
463
        $mf->expects($this->any())
464
            ->method('getMetadataFor')
465
            ->willReturn($meta);
466
467
        $platform = $this->createMock(PostgreSqlPlatform::class);
468
        $platform->expects($this->any())
469
            ->method('hasDoctrineTypeMappingFor')
470
            ->with(UuidType::NAME)
471
            ->willReturn(false);
472
        $platform->expects($this->never())
473
            ->method('getDoctrineTypeMapping');
474
475
        $conn = $this->createMock(Connection::class);
476
        $conn->expects($this->any())
477
            ->method('getDatabasePlatform')
478
            ->willReturn($platform);
479
480
        $em = $this->createMock(EntityManager::class);
481
        $em->expects($this->any())
482
            ->method('getMetadataFactory')
483
            ->willReturn($mf);
484
        $em->expects($this->any())
485
            ->method('getConnection')
486
            ->willReturn($conn);
487
488
        $registry = $this->createMock(ManagerRegistry::class);
489
        $registry->expects($this->any())
490
            ->method('getManagerForClass')
491
            ->willReturn($em);
492
493
        $manager = new ModelManager($registry);
494
        $result = $manager->getIdentifierValues($entity);
495
496
        $this->assertSame($entity->getId()->toString(), $result[0]);
497
    }
498
499
    public function testIntegerIdentifierType(): void
500
    {
501
        $id = new ProductId(12345);
502
        $entity = new Product($id, 'Some product');
503
504
        $meta = $this->createMock(ClassMetadata::class);
505
        $meta->expects($this->any())
506
            ->method('getIdentifierValues')
507
            ->willReturn([$entity->getId()]);
508
        $meta->expects($this->any())
509
            ->method('getTypeOfField')
510
            ->willReturn(ProductIdType::NAME);
511
512
        $mf = $this->createMock(ClassMetadataFactory::class);
513
        $mf->expects($this->any())
514
            ->method('getMetadataFor')
515
            ->willReturn($meta);
516
517
        $platform = $this->createMock(PostgreSqlPlatform::class);
518
        $platform->expects($this->any())
519
            ->method('hasDoctrineTypeMappingFor')
520
            ->with(ProductIdType::NAME)
521
            ->willReturn(false);
522
        $platform->expects($this->never())
523
            ->method('getDoctrineTypeMapping');
524
525
        $conn = $this->createMock(Connection::class);
526
        $conn->expects($this->any())
527
            ->method('getDatabasePlatform')
528
            ->willReturn($platform);
529
530
        $em = $this->createMock(EntityManager::class);
531
        $em->expects($this->any())
532
            ->method('getMetadataFactory')
533
            ->willReturn($mf);
534
        $em->expects($this->any())
535
            ->method('getConnection')
536
            ->willReturn($conn);
537
538
        $registry = $this->createMock(ManagerRegistry::class);
539
        $registry->expects($this->any())
540
            ->method('getManagerForClass')
541
            ->willReturn($em);
542
543
        $manager = new ModelManager($registry);
544
        $result = $manager->getIdentifierValues($entity);
545
546
        $this->assertSame((string) $entity->getId()->getId(), $result[0]);
547
    }
548
549
    public function testAssociationIdentifierType(): void
550
    {
551
        $entity = new ContainerEntity(new AssociatedEntity(42, new EmbeddedEntity()), new EmbeddedEntity());
552
553
        $meta = $this->createMock(ClassMetadata::class);
554
        $meta->expects($this->any())
555
            ->method('getIdentifierValues')
556
            ->willReturn([$entity->getAssociatedEntity()->getPlainField()]);
557
        $meta->expects($this->any())
558
            ->method('getTypeOfField')
559
            ->willReturn(null);
560
561
        $mf = $this->createMock(ClassMetadataFactory::class);
562
        $mf->expects($this->any())
563
            ->method('getMetadataFor')
564
            ->willReturn($meta);
565
566
        $platform = $this->createMock(PostgreSqlPlatform::class);
567
        $platform->expects($this->never())
568
            ->method('hasDoctrineTypeMappingFor');
569
570
        $conn = $this->createMock(Connection::class);
571
        $conn->expects($this->any())
572
            ->method('getDatabasePlatform')
573
            ->willReturn($platform);
574
575
        $em = $this->createMock(EntityManager::class);
576
        $em->expects($this->any())
577
            ->method('getMetadataFactory')
578
            ->willReturn($mf);
579
        $em->expects($this->any())
580
            ->method('getConnection')
581
            ->willReturn($conn);
582
583
        $registry = $this->createMock(ManagerRegistry::class);
584
        $registry->expects($this->any())
585
            ->method('getManagerForClass')
586
            ->willReturn($em);
587
588
        $manager = new ModelManager($registry);
589
        $result = $manager->getIdentifierValues($entity);
590
591
        $this->assertSame(42, $result[0]);
592
    }
593
594
    /**
595
     * [sortBy, sortOrder, isAddOrderBy].
596
     *
597
     * @return array
598
     */
599
    public function getSortableInDataSourceIteratorDataProvider()
600
    {
601
        return [
602
            [null, null, false],
603
            ['', 'ASC', false],
604
            ['field', 'ASC', true],
605
            ['field', null, true],
606
        ];
607
    }
608
609
    /**
610
     * @dataProvider getSortableInDataSourceIteratorDataProvider
611
     *
612
     * @param string|null $sortBy
613
     * @param string|null $sortOrder
614
     * @param bool        $isAddOrderBy
615
     */
616
    public function testSortableInDataSourceIterator($sortBy, $sortOrder, $isAddOrderBy): void
617
    {
618
        $datagrid = $this->getMockForAbstractClass(DatagridInterface::class);
619
        $configuration = $this->getMockBuilder(Configuration::class)->getMock();
620
        $configuration->expects($this->any())
621
            ->method('getDefaultQueryHints')
622
            ->willReturn([]);
623
624
        $em = $this->getMockBuilder(EntityManager::class)
625
            ->disableOriginalConstructor()
626
            ->getMock();
627
628
        $em->expects($this->any())
629
            ->method('getConfiguration')
630
            ->willReturn($configuration);
631
632
        $queryBuilder = $this->getMockBuilder(QueryBuilder::class)
633
            ->setConstructorArgs([$em])
634
            ->getMock();
635
        $query = new Query($em);
636
637
        $proxyQuery = $this->getMockBuilder(ProxyQuery::class)
638
            ->setConstructorArgs([$queryBuilder])
639
            ->setMethods(['getSortBy', 'getSortOrder', 'getRootAliases'])
640
            ->getMock();
641
642
        $proxyQuery->expects($this->any())
643
            ->method('getSortOrder')
644
            ->willReturn($sortOrder);
645
646
        $proxyQuery->expects($this->any())
647
            ->method('getSortBy')
648
            ->willReturn($sortBy);
649
650
        $queryBuilder->expects($isAddOrderBy ? $this->atLeastOnce() : $this->never())
651
            ->method('addOrderBy');
652
653
        $proxyQuery->expects($this->any())
654
            ->method('getRootAliases')
655
            ->willReturn(['a']);
656
657
        $queryBuilder->expects($this->any())
658
            ->method('getQuery')
659
            ->willReturn($query);
660
661
        $datagrid->expects($this->any())
662
            ->method('getQuery')
663
            ->willReturn($proxyQuery);
664
665
        $registry = $this->getMockBuilder(RegistryInterface::class)->getMock();
666
        $manager = new ModelManager($registry);
667
        $manager->getDataSourceIterator($datagrid, []);
668
669
        if ($isAddOrderBy) {
670
            $this->assertArrayHasKey($key = 'doctrine.customTreeWalkers', $hints = $query->getHints());
671
            $this->assertContains(OrderByToSelectWalker::class, $hints[$key]);
672
        }
673
    }
674
675
    public function testModelReverseTransform(): void
676
    {
677
        $class = SimpleEntity::class;
678
679
        $metadataFactory = $this->createMock(ClassMetadataFactory::class);
680
        $modelManager = $this->createMock(ObjectManager::class);
681
        $registry = $this->createMock(ManagerRegistry::class);
682
683
        $classMetadata = new ClassMetadata($class);
684
        $classMetadata->reflClass = new \ReflectionClass($class);
685
686
        $modelManager->expects($this->once())
687
            ->method('getMetadataFactory')
688
            ->willReturn($metadataFactory);
689
        $metadataFactory->expects($this->once())
690
            ->method('getMetadataFor')
691
            ->with($class)
692
            ->willReturn($classMetadata);
693
        $registry->expects($this->once())
694
            ->method('getManagerForClass')
695
            ->with($class)
696
            ->willReturn($modelManager);
697
698
        $manager = new ModelManager($registry);
699
        $this->assertInstanceOf($class, $object = $manager->modelReverseTransform(
700
            $class,
701
            [
702
                'schmeckles' => 42,
703
                'multi_word_property' => 'hello',
704
            ]
705
        ));
706
        $this->assertSame(42, $object->getSchmeckles());
707
        $this->assertSame('hello', $object->getMultiWordProperty());
708
    }
709
710
    public function testCollections(): void
711
    {
712
        $registry = $this->createMock(ManagerRegistry::class);
713
        $model = new ModelManager($registry);
714
715
        $collection = $model->getModelCollectionInstance('whyDoWeEvenHaveThisParameter');
716
        $this->assertInstanceOf(ArrayCollection::class, $collection);
717
718
        $item1 = 'item1';
719
        $item2 = 'item2';
720
        $model->collectionAddElement($collection, $item1);
0 ignored issues
show
Bug introduced by
It seems like $collection defined by $model->getModelCollecti...EvenHaveThisParameter') on line 715 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...
721
        $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...
722
723
        $this->assertTrue($model->collectionHasElement($collection, $item1));
724
725
        $model->collectionRemoveElement($collection, $item1);
726
727
        $this->assertFalse($model->collectionHasElement($collection, $item1));
728
729
        $model->collectionClear($collection);
730
731
        $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...
732
    }
733
734
    public function testModelTransform(): void
735
    {
736
        $registry = $this->createMock(ManagerRegistry::class);
737
        $model = new ModelManager($registry);
738
739
        $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...
740
741
        $this->assertSame('doWeNeedThisMethod', $result);
742
    }
743
744
    public function testGetPaginationParameters(): void
745
    {
746
        $datagrid = $this->createMock(DatagridInterface::class);
747
        $filter = $this->createMock(FilterInterface::class);
748
        $registry = $this->createMock(ManagerRegistry::class);
749
750
        $datagrid->expects($this->once())
751
            ->method('getValues')
752
            ->willReturn(['_sort_by' => $filter]);
753
754
        $filter->expects($this->once())
755
            ->method('getName')
756
            ->willReturn($name = 'test');
757
758
        $model = new ModelManager($registry);
759
760
        $result = $model->getPaginationParameters($datagrid, $page = 5);
761
762
        $this->assertSame($page, $result['filter']['_page']);
763
        $this->assertSame($name, $result['filter']['_sort_by']);
764
    }
765
766
    public function testGetModelInstanceException(): void
767
    {
768
        $registry = $this->createMock(ManagerRegistry::class);
769
770
        $model = new ModelManager($registry);
771
772
        $this->expectException(\RuntimeException::class);
773
774
        $model->getModelInstance(AbstractEntity::class);
775
    }
776
777
    public function testGetModelInstanceForProtectedEntity(): void
778
    {
779
        $registry = $this->createMock(ManagerRegistry::class);
780
781
        $model = new ModelManager($registry);
782
783
        $this->assertInstanceOf(ProtectedEntity::class, $model->getModelInstance(ProtectedEntity::class));
784
    }
785
786
    public function testGetEntityManagerException(): void
787
    {
788
        $registry = $this->createMock(ManagerRegistry::class);
789
790
        $model = new ModelManager($registry);
791
792
        $this->expectException(\RuntimeException::class);
793
794
        $model->getEntityManager(VersionedEntity::class);
795
    }
796
797
    public function testGetNewFieldDescriptionInstanceException(): void
798
    {
799
        $registry = $this->createMock(ManagerRegistry::class);
800
801
        $model = new ModelManager($registry);
802
803
        $this->expectException(\RuntimeException::class);
804
805
        $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...
806
    }
807
808
    /**
809
     * @dataProvider createUpdateRemoveData
810
     */
811
    public function testCreate($exception): void
812
    {
813
        $registry = $this->createMock(ManagerRegistry::class);
814
815
        $entityManger = $this->createMock(EntityManager::class);
816
817
        $registry->expects($this->once())
818
            ->method('getManagerForClass')
819
            ->willReturn($entityManger);
820
821
        $entityManger->expects($this->once())
822
            ->method('persist');
823
824
        $entityManger->expects($this->once())
825
            ->method('flush')
826
            ->willThrowException($exception);
827
828
        $model = new ModelManager($registry);
829
830
        $this->expectException(ModelManagerException::class);
831
832
        $model->create(new VersionedEntity());
833
    }
834
835
    public function createUpdateRemoveData()
836
    {
837
        return [
838
            'PDOException' => [
839
                new \PDOException(),
840
            ],
841
            'DBALException' => [
842
                new DBALException(),
843
            ],
844
        ];
845
    }
846
847
    /**
848
     * @dataProvider createUpdateRemoveData
849
     */
850
    public function testUpdate($exception): void
851
    {
852
        $registry = $this->createMock(ManagerRegistry::class);
853
854
        $entityManger = $this->createMock(EntityManager::class);
855
856
        $registry->expects($this->once())
857
            ->method('getManagerForClass')
858
            ->willReturn($entityManger);
859
860
        $entityManger->expects($this->once())
861
            ->method('persist');
862
863
        $entityManger->expects($this->once())
864
            ->method('flush')
865
            ->willThrowException($exception);
866
867
        $model = new ModelManager($registry);
868
869
        $this->expectException(ModelManagerException::class);
870
871
        $model->update(new VersionedEntity());
872
    }
873
874
    /**
875
     * @dataProvider createUpdateRemoveData
876
     */
877
    public function testRemove($exception): void
878
    {
879
        $registry = $this->createMock(ManagerRegistry::class);
880
881
        $entityManger = $this->createMock(EntityManager::class);
882
883
        $registry->expects($this->once())
884
            ->method('getManagerForClass')
885
            ->willReturn($entityManger);
886
887
        $entityManger->expects($this->once())
888
            ->method('remove');
889
890
        $entityManger->expects($this->once())
891
            ->method('flush')
892
            ->willThrowException($exception);
893
894
        $model = new ModelManager($registry);
895
896
        $this->expectException(ModelManagerException::class);
897
898
        $model->delete(new VersionedEntity());
899
    }
900
901
    public function testFindBadId(): void
902
    {
903
        $registry = $this->createMock(ManagerRegistry::class);
904
905
        $model = new ModelManager($registry);
906
907
        $this->assertNull($model->find('notImportant', null));
908
    }
909
910
    public function testGetUrlsafeIdentifierException(): void
911
    {
912
        $registry = $this->createMock(ManagerRegistry::class);
913
914
        $model = new ModelManager($registry);
915
916
        $this->expectException(\RuntimeException::class);
917
918
        $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...
919
    }
920
921
    public function testGetUrlsafeIdentifierNull(): void
922
    {
923
        $registry = $this->createMock(ManagerRegistry::class);
924
925
        $model = new ModelManager($registry);
926
927
        $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...
928
    }
929
930
    private function getMetadata($class, $isVersioned)
931
    {
932
        $metadata = new ClassMetadata($class);
933
934
        $metadata->isVersioned = $isVersioned;
935
936
        if ($isVersioned) {
937
            $versionField = 'version';
938
            $metadata->versionField = $versionField;
939
            $metadata->reflFields[$versionField] = new \ReflectionProperty($class, $versionField);
940
        }
941
942
        return $metadata;
943
    }
944
}
945