Completed
Pull Request — 3.x (#935)
by Peter
01:48
created

ModelManagerTest::testUpdate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

Loading history...
243
            ->willReturnMap(
244
245
                    [
246
                        [$containerEntityClass, $containerEntityMetadata],
247
                        [$embeddedEntityClass, $embeddedEntityMetadata],
248
                        [$associatedEntityClass, $associatedEntityMetadata],
249
                    ]
250
251
            );
252
253
        /** @var ClassMetadata $metadata */
254
        list($metadata, $lastPropertyName) = $modelManager
255
            ->getParentMetadataForProperty($containerEntityClass, 'plainField');
256
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'integer');
257
258
        list($metadata, $lastPropertyName) = $modelManager
259
            ->getParentMetadataForProperty($containerEntityClass, 'associatedEntity.plainField');
260
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'string');
261
262
        list($metadata, $lastPropertyName) = $modelManager
263
            ->getParentMetadataForProperty($containerEntityClass, 'embeddedEntity.plainField');
264
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
265
266
        list($metadata, $lastPropertyName) = $modelManager
267
            ->getParentMetadataForProperty($containerEntityClass, 'associatedEntity.embeddedEntity.plainField');
268
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
269
270
        list($metadata, $lastPropertyName) = $modelManager
271
            ->getParentMetadataForProperty(
272
                $containerEntityClass,
273
                'associatedEntity.embeddedEntity.subEmbeddedEntity.plainField'
274
            );
275
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
276
    }
277
278
    public function getMetadataForEmbeddedEntity()
279
    {
280
        $metadata = new ClassMetadata(EmbeddedEntity::class);
281
282
        $metadata->fieldMappings = [
283
            'plainField' => [
284
                'fieldName' => 'plainField',
285
                'columnName' => 'plainField',
286
                'type' => 'boolean',
287
            ],
288
        ];
289
290
        return $metadata;
291
    }
292
293
    public function getMetadataForSubEmbeddedEntity()
294
    {
295
        $metadata = new ClassMetadata(SubEmbeddedEntity::class);
296
297
        $metadata->fieldMappings = [
298
            'plainField' => [
299
                'fieldName' => 'plainField',
300
                'columnName' => 'plainField',
301
                'type' => 'boolean',
302
            ],
303
        ];
304
305
        return $metadata;
306
    }
307
308
    public function getMetadataForAssociatedEntity()
309
    {
310
        $embeddedEntityClass = EmbeddedEntity::class;
311
        $subEmbeddedEntityClass = SubEmbeddedEntity::class;
312
313
        $metadata = new ClassMetadata(AssociatedEntity::class);
314
315
        $metadata->fieldMappings = [
316
            'plainField' => [
317
                'fieldName' => 'plainField',
318
                'columnName' => 'plainField',
319
                'type' => 'string',
320
            ],
321
        ];
322
323
        $metadata->embeddedClasses['embeddedEntity'] = [
324
            'class' => $embeddedEntityClass,
325
            'columnPrefix' => 'embedded_entity_',
326
        ];
327
        $metadata->embeddedClasses['embeddedEntity.subEmbeddedEntity'] = [
328
            'class' => $subEmbeddedEntityClass,
329
            'columnPrefix' => 'embedded_entity_sub_embedded_entity_',
330
            'declaredField' => 'embeddedEntity',
331
            'originalField' => 'subEmbeddedEntity',
332
        ];
333
334
        $metadata->inlineEmbeddable('embeddedEntity', $this->getMetadataForEmbeddedEntity());
335
        $metadata->inlineEmbeddable('embeddedEntity.subEmbeddedEntity', $this->getMetadataForSubEmbeddedEntity());
336
337
        return $metadata;
338
    }
339
340
    public function getMetadataForContainerEntity()
341
    {
342
        $containerEntityClass = ContainerEntity::class;
343
        $associatedEntityClass = AssociatedEntity::class;
344
        $embeddedEntityClass = EmbeddedEntity::class;
345
        $subEmbeddedEntityClass = SubEmbeddedEntity::class;
346
347
        $metadata = new ClassMetadata($containerEntityClass);
348
349
        $metadata->fieldMappings = [
350
            'plainField' => [
351
                'fieldName' => 'plainField',
352
                'columnName' => 'plainField',
353
                'type' => 'integer',
354
            ],
355
        ];
356
357
        $metadata->associationMappings['associatedEntity'] = [
358
            'fieldName' => 'associatedEntity',
359
            'targetEntity' => $associatedEntityClass,
360
            'sourceEntity' => $containerEntityClass,
361
        ];
362
363
        $metadata->embeddedClasses['embeddedEntity'] = [
364
            'class' => $embeddedEntityClass,
365
            'columnPrefix' => 'embeddedEntity',
366
        ];
367
        $metadata->embeddedClasses['embeddedEntity.subEmbeddedEntity'] = [
368
            'class' => $subEmbeddedEntityClass,
369
            'columnPrefix' => 'embedded_entity_sub_embedded_entity_',
370
            'declaredField' => 'embeddedEntity',
371
            'originalField' => 'subEmbeddedEntity',
372
        ];
373
374
        $metadata->inlineEmbeddable('embeddedEntity', $this->getMetadataForEmbeddedEntity());
375
        $metadata->inlineEmbeddable('embeddedEntity.subEmbeddedEntity', $this->getMetadataForSubEmbeddedEntity());
376
377
        return $metadata;
378
    }
379
380
    public function testGetIdentifierValuesForIdInObjectTypeBinaryToStringSupport(): void
381
    {
382
        $uuid = new NonIntegerIdentifierTestClass('efbcfc4b-8c43-4d42-aa4c-d707e55151ac');
383
384
        $entity = new UuidEntity($uuid);
385
386
        $meta = $this->createMock(ClassMetadata::class);
387
        $meta->expects($this->any())
388
            ->method('getIdentifierValues')
389
            ->willReturn([$entity->getId()]);
390
        $meta->expects($this->any())
391
            ->method('getTypeOfField')
392
            ->willReturn(UuidBinaryType::NAME); //'uuid_binary'
393
394
        $mf = $this->createMock(ClassMetadataFactory::class);
395
        $mf->expects($this->any())
396
            ->method('getMetadataFor')
397
            ->willReturn($meta);
398
399
        $platform = $this->createMock(PostgreSqlPlatform::class);
400
        $platform->expects($this->any())
401
            ->method('hasDoctrineTypeMappingFor')
402
            ->with(UuidBinaryType::NAME)
403
            ->willReturn(true);
404
        $platform->expects($this->any())
405
            ->method('getDoctrineTypeMapping')
406
            ->with(UuidBinaryType::NAME)
407
            ->willReturn('binary');
408
409
        $conn = $this->createMock(Connection::class);
410
        $conn->expects($this->any())
411
            ->method('getDatabasePlatform')
412
            ->willReturn($platform);
413
414
        $em = $this->createMock(EntityManager::class);
415
        $em->expects($this->any())
416
            ->method('getMetadataFactory')
417
            ->willReturn($mf);
418
        $em->expects($this->any())
419
            ->method('getConnection')
420
            ->willReturn($conn);
421
422
        $registry = $this->createMock(RegistryInterface::class);
423
        $registry->expects($this->any())
424
            ->method('getManagerForClass')
425
            ->willReturn($em);
426
427
        $manager = new ModelManager($registry);
428
        $result = $manager->getIdentifierValues($entity);
429
430
        $this->assertSame($entity->getId()->toString(), $result[0]);
431
    }
432
433
    public function testNonIntegerIdentifierType(): void
434
    {
435
        $uuid = new NonIntegerIdentifierTestClass('efbcfc4b-8c43-4d42-aa4c-d707e55151ac');
436
        $entity = new UuidEntity($uuid);
437
438
        $meta = $this->createMock(ClassMetadata::class);
439
        $meta->expects($this->any())
440
            ->method('getIdentifierValues')
441
            ->willReturn([$entity->getId()]);
442
        $meta->expects($this->any())
443
            ->method('getTypeOfField')
444
            ->willReturn(UuidType::NAME);
445
446
        $mf = $this->createMock(ClassMetadataFactory::class);
447
        $mf->expects($this->any())
448
            ->method('getMetadataFor')
449
            ->willReturn($meta);
450
451
        $platform = $this->createMock(PostgreSqlPlatform::class);
452
        $platform->expects($this->any())
453
            ->method('hasDoctrineTypeMappingFor')
454
            ->with(UuidType::NAME)
455
            ->willReturn(false);
456
457
        $conn = $this->createMock(Connection::class);
458
        $conn->expects($this->any())
459
            ->method('getDatabasePlatform')
460
            ->willReturn($platform);
461
462
        $em = $this->createMock(EntityManager::class);
463
        $em->expects($this->any())
464
            ->method('getMetadataFactory')
465
            ->willReturn($mf);
466
        $em->expects($this->any())
467
            ->method('getConnection')
468
            ->willReturn($conn);
469
470
        $registry = $this->createMock(RegistryInterface::class);
471
        $registry->expects($this->any())
472
            ->method('getManagerForClass')
473
            ->willReturn($em);
474
475
        $manager = new ModelManager($registry);
476
        $result = $manager->getIdentifierValues($entity);
477
478
        $this->assertSame($entity->getId()->toString(), $result[0]);
479
    }
480
481
    public function testIntegerIdentifierType(): void
482
    {
483
        $id = new ProductId(12345);
484
        $entity = new Product($id, 'Some product');
485
486
        $meta = $this->createMock(ClassMetadata::class);
487
        $meta->expects($this->any())
488
            ->method('getIdentifierValues')
489
            ->willReturn([$entity->getId()]);
490
        $meta->expects($this->any())
491
            ->method('getTypeOfField')
492
            ->willReturn(ProductIdType::NAME);
493
494
        $mf = $this->createMock(ClassMetadataFactory::class);
495
        $mf->expects($this->any())
496
            ->method('getMetadataFor')
497
            ->willReturn($meta);
498
499
        $platform = $this->createMock(PostgreSqlPlatform::class);
500
        $platform->expects($this->any())
501
            ->method('hasDoctrineTypeMappingFor')
502
            ->with(ProductIdType::NAME)
503
            ->willReturn(false);
504
505
        $conn = $this->createMock(Connection::class);
506
        $conn->expects($this->any())
507
            ->method('getDatabasePlatform')
508
            ->willReturn($platform);
509
510
        $em = $this->createMock(EntityManager::class);
511
        $em->expects($this->any())
512
            ->method('getMetadataFactory')
513
            ->willReturn($mf);
514
        $em->expects($this->any())
515
            ->method('getConnection')
516
            ->willReturn($conn);
517
518
        $registry = $this->createMock(RegistryInterface::class);
519
        $registry->expects($this->any())
520
            ->method('getManagerForClass')
521
            ->willReturn($em);
522
523
        $manager = new ModelManager($registry);
524
        $result = $manager->getIdentifierValues($entity);
525
526
        $this->assertSame((string) $entity->getId()->getId(), $result[0]);
527
    }
528
529
    public function testAssociationIdentifierType(): void
530
    {
531
        $entity = new ContainerEntity(new AssociatedEntity(42, new EmbeddedEntity()), new EmbeddedEntity());
532
533
        $meta = $this->createMock(ClassMetadata::class);
534
        $meta->expects($this->any())
535
            ->method('getIdentifierValues')
536
            ->willReturn([$entity->getAssociatedEntity()->getPlainField()]);
537
        $meta->expects($this->any())
538
            ->method('getTypeOfField')
539
            ->willReturn(null);
540
541
        $mf = $this->createMock(ClassMetadataFactory::class);
542
        $mf->expects($this->any())
543
            ->method('getMetadataFor')
544
            ->willReturn($meta);
545
546
        $platform = $this->createMock(PostgreSqlPlatform::class);
547
        $platform->expects($this->never())
548
            ->method('hasDoctrineTypeMappingFor');
549
550
        $conn = $this->createMock(Connection::class);
551
        $conn->expects($this->any())
552
            ->method('getDatabasePlatform')
553
            ->willReturn($platform);
554
555
        $em = $this->createMock(EntityManager::class);
556
        $em->expects($this->any())
557
            ->method('getMetadataFactory')
558
            ->willReturn($mf);
559
        $em->expects($this->any())
560
            ->method('getConnection')
561
            ->willReturn($conn);
562
563
        $registry = $this->createMock(RegistryInterface::class);
564
        $registry->expects($this->any())
565
            ->method('getManagerForClass')
566
            ->willReturn($em);
567
568
        $manager = new ModelManager($registry);
569
        $result = $manager->getIdentifierValues($entity);
570
571
        $this->assertSame(42, $result[0]);
572
    }
573
574
    /**
575
     * [sortBy, sortOrder, isAddOrderBy].
576
     *
577
     * @return array
578
     */
579
    public function getSortableInDataSourceIteratorDataProvider()
580
    {
581
        return [
582
            [null, null, false],
583
            ['', 'ASC', false],
584
            ['field', 'ASC', true],
585
            ['field', null, true],
586
        ];
587
    }
588
589
    /**
590
     * @dataProvider getSortableInDataSourceIteratorDataProvider
591
     *
592
     * @param string|null $sortBy
593
     * @param string|null $sortOrder
594
     * @param bool        $isAddOrderBy
595
     */
596
    public function testSortableInDataSourceIterator($sortBy, $sortOrder, $isAddOrderBy): void
597
    {
598
        $datagrid = $this->getMockForAbstractClass(DatagridInterface::class);
599
        $configuration = $this->getMockBuilder(Configuration::class)->getMock();
600
        $configuration->expects($this->any())
601
            ->method('getDefaultQueryHints')
602
            ->willReturn([]);
603
604
        $em = $this->getMockBuilder(EntityManager::class)
605
            ->disableOriginalConstructor()
606
            ->getMock();
607
608
        $em->expects($this->any())
609
            ->method('getConfiguration')
610
            ->willReturn($configuration);
611
612
        $queryBuilder = $this->getMockBuilder(QueryBuilder::class)
613
            ->setConstructorArgs([$em])
614
            ->getMock();
615
        $query = new Query($em);
616
617
        $proxyQuery = $this->getMockBuilder(ProxyQuery::class)
618
            ->setConstructorArgs([$queryBuilder])
619
            ->setMethods(['getSortBy', 'getSortOrder', 'getRootAliases'])
620
            ->getMock();
621
622
        $proxyQuery->expects($this->any())
623
            ->method('getSortOrder')
624
            ->willReturn($sortOrder);
625
626
        $proxyQuery->expects($this->any())
627
            ->method('getSortBy')
628
            ->willReturn($sortBy);
629
630
        $queryBuilder->expects($isAddOrderBy ? $this->atLeastOnce() : $this->never())
631
            ->method('addOrderBy');
632
633
        $proxyQuery->expects($this->any())
634
            ->method('getRootAliases')
635
            ->willReturn(['a']);
636
637
        $queryBuilder->expects($this->any())
638
            ->method('getQuery')
639
            ->willReturn($query);
640
641
        $datagrid->expects($this->any())
642
            ->method('getQuery')
643
            ->willReturn($proxyQuery);
644
645
        $registry = $this->getMockBuilder(RegistryInterface::class)->getMock();
646
        $manager = new ModelManager($registry);
647
        $manager->getDataSourceIterator($datagrid, []);
648
649
        if ($isAddOrderBy) {
650
            $this->assertArrayHasKey($key = 'doctrine.customTreeWalkers', $hints = $query->getHints());
651
            $this->assertContains(OrderByToSelectWalker::class, $hints[$key]);
652
        }
653
    }
654
655
    public function testModelReverseTransform(): void
656
    {
657
        $class = SimpleEntity::class;
658
659
        $metadataFactory = $this->createMock(ClassMetadataFactory::class);
660
        $modelManager = $this->createMock(ObjectManager::class);
661
        $registry = $this->createMock(RegistryInterface::class);
662
663
        $classMetadata = new ClassMetadata($class);
664
        $classMetadata->reflClass = new \ReflectionClass($class);
665
666
        $modelManager->expects($this->once())
667
            ->method('getMetadataFactory')
668
            ->willReturn($metadataFactory);
669
        $metadataFactory->expects($this->once())
670
            ->method('getMetadataFor')
671
            ->with($class)
672
            ->willReturn($classMetadata);
673
        $registry->expects($this->once())
674
            ->method('getManagerForClass')
675
            ->with($class)
676
            ->willReturn($modelManager);
677
678
        $manager = new ModelManager($registry);
679
        $this->assertInstanceOf($class, $object = $manager->modelReverseTransform(
680
            $class,
681
            [
682
                'schmeckles' => 42,
683
                'multi_word_property' => 'hello',
684
            ]
685
        ));
686
        $this->assertSame(42, $object->getSchmeckles());
687
        $this->assertSame('hello', $object->getMultiWordProperty());
688
    }
689
690
    public function testCollections(): void
691
    {
692
        $registry = $this->createMock(RegistryInterface::class);
693
        $model = new ModelManager($registry);
694
695
        $collection = $model->getModelCollectionInstance('whyDoWeEvenHaveThisParameter');
696
        $this->assertInstanceOf(ArrayCollection::class, $collection);
697
698
        $item1 = 'item1';
699
        $item2 = 'item2';
700
        $model->collectionAddElement($collection, $item1);
701
        $model->collectionAddElement($collection, $item2);
702
703
        $this->assertTrue($model->collectionHasElement($collection, $item1));
704
705
        $model->collectionRemoveElement($collection, $item1);
706
707
        $this->assertFalse($model->collectionHasElement($collection, $item1));
708
709
        $model->collectionClear($collection);
710
711
        $this->assertTrue($collection->isEmpty());
712
    }
713
714
    public function testModelTransform(): void
715
    {
716
        $registry = $this->createMock(RegistryInterface::class);
717
        $model = new ModelManager($registry);
718
719
        $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...
720
721
        $this->assertSame('doWeNeedThisMethod', $result);
722
    }
723
724
    public function testGetPaginationParameters(): void
725
    {
726
        $datagrid = $this->createMock(DatagridInterface::class);
727
        $filter = $this->createMock(FilterInterface::class);
728
        $registry = $this->createMock(RegistryInterface::class);
729
730
        $datagrid->expects($this->once())
731
            ->method('getValues')
732
            ->willReturn(['_sort_by' => $filter]);
733
734
        $filter->expects($this->once())
735
            ->method('getName')
736
            ->willReturn($name = 'test');
737
738
        $model = new ModelManager($registry);
739
740
        $result = $model->getPaginationParameters($datagrid, $page = 5);
741
742
        $this->assertSame($page, $result['filter']['_page']);
743
        $this->assertSame($name, $result['filter']['_sort_by']);
744
    }
745
746
    public function testGetModelInstanceException(): void
747
    {
748
        $registry = $this->createMock(RegistryInterface::class);
749
750
        $model = new ModelManager($registry);
751
752
        $this->expectException(\RuntimeException::class);
753
754
        $model->getModelInstance(AbstractEntity::class);
755
    }
756
757
    public function testGetModelInstanceForProtectedEntity(): void
758
    {
759
        $registry = $this->createMock(RegistryInterface::class);
760
761
        $model = new ModelManager($registry);
762
763
        $this->assertInstanceOf(ProtectedEntity::class, $model->getModelInstance(ProtectedEntity::class));
764
    }
765
766
    public function testGetEntityManagerException(): void
767
    {
768
        $registry = $this->createMock(RegistryInterface::class);
769
770
        $model = new ModelManager($registry);
771
772
        $this->expectException(\RuntimeException::class);
773
774
        $model->getEntityManager(VersionedEntity::class);
775
    }
776
777
    public function testGetNewFieldDescriptionInstanceException(): void
778
    {
779
        $registry = $this->createMock(RegistryInterface::class);
780
781
        $model = new ModelManager($registry);
782
783
        $this->expectException(\RuntimeException::class);
784
785
        $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...
786
    }
787
788
    /**
789
     * @dataProvider createUpdateRemoveData
790
     */
791
    public function testCreate($exception): void
792
    {
793
        $registry = $this->createMock(RegistryInterface::class);
794
795
        $entityManger = $this->createMock(EntityManager::class);
796
797
        $registry->expects($this->once())
798
            ->method('getManagerForClass')
799
            ->willReturn($entityManger);
800
801
        $entityManger->expects($this->once())
802
            ->method('persist');
803
804
        $entityManger->expects($this->once())
805
            ->method('flush')
806
            ->willThrowException($exception);
807
808
        $model = new ModelManager($registry);
809
810
        $this->expectException(ModelManagerException::class);
811
812
        $model->create(new VersionedEntity());
813
    }
814
815
    public function createUpdateRemoveData()
816
    {
817
        return [
818
            'PDOException' => [
819
                new \PDOException(),
820
            ],
821
            'DBALException' => [
822
                new DBALException(),
823
            ],
824
        ];
825
    }
826
827
    /**
828
     * @dataProvider createUpdateRemoveData
829
     */
830
    public function testUpdate($exception): void
831
    {
832
        $registry = $this->createMock(RegistryInterface::class);
833
834
        $entityManger = $this->createMock(EntityManager::class);
835
836
        $registry->expects($this->once())
837
            ->method('getManagerForClass')
838
            ->willReturn($entityManger);
839
840
        $entityManger->expects($this->once())
841
            ->method('persist');
842
843
        $entityManger->expects($this->once())
844
            ->method('flush')
845
            ->willThrowException($exception);
846
847
        $model = new ModelManager($registry);
848
849
        $this->expectException(ModelManagerException::class);
850
851
        $model->update(new VersionedEntity());
852
    }
853
854
    /**
855
     * @dataProvider createUpdateRemoveData
856
     */
857
    public function testRemove($exception): void
858
    {
859
        $registry = $this->createMock(RegistryInterface::class);
860
861
        $entityManger = $this->createMock(EntityManager::class);
862
863
        $registry->expects($this->once())
864
            ->method('getManagerForClass')
865
            ->willReturn($entityManger);
866
867
        $entityManger->expects($this->once())
868
            ->method('remove');
869
870
        $entityManger->expects($this->once())
871
            ->method('flush')
872
            ->willThrowException($exception);
873
874
        $model = new ModelManager($registry);
875
876
        $this->expectException(ModelManagerException::class);
877
878
        $model->delete(new VersionedEntity());
879
    }
880
881
    public function testFindBadId(): void
882
    {
883
        $registry = $this->createMock(RegistryInterface::class);
884
885
        $model = new ModelManager($registry);
886
887
        $this->assertNull($model->find('notImportant', null));
888
    }
889
890
    public function testGetUrlsafeIdentifierException(): void
891
    {
892
        $registry = $this->createMock(RegistryInterface::class);
893
894
        $model = new ModelManager($registry);
895
896
        $this->expectException(\RuntimeException::class);
897
898
        $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...
899
    }
900
901
    public function testGetUrlsafeIdentifierNull(): void
902
    {
903
        $registry = $this->createMock(RegistryInterface::class);
904
905
        $model = new ModelManager($registry);
906
907
        $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...
908
    }
909
910
    private function getMetadata($class, $isVersioned)
911
    {
912
        $metadata = new ClassMetadata($class);
913
914
        $metadata->isVersioned = $isVersioned;
915
916
        if ($isVersioned) {
917
            $versionField = 'version';
918
            $metadata->versionField = $versionField;
919
            $metadata->reflFields[$versionField] = new \ReflectionProperty($class, $versionField);
920
        }
921
922
        return $metadata;
923
    }
924
}
925