Completed
Pull Request — 3.x (#360)
by
unknown
01:21
created

ModelManagerTest::getMetadataForEmbeddedDocument()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 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\DoctrineMongoDBAdminBundle\Tests\Model;
15
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
18
use Doctrine\Common\Persistence\ObjectManager;
19
use Doctrine\ODM\MongoDB\DocumentManager;
20
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
21
use PHPUnit\Framework\TestCase;
22
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
23
use Sonata\AdminBundle\Datagrid\Datagrid;
24
use Sonata\AdminBundle\Datagrid\DatagridInterface;
25
use Sonata\DoctrineMongoDBAdminBundle\Admin\FieldDescription;
26
use Sonata\DoctrineMongoDBAdminBundle\Model\ModelManager;
27
use Sonata\DoctrineMongoDBAdminBundle\Tests\Fixtures\Document\AbstractDocument;
28
use Sonata\DoctrineMongoDBAdminBundle\Tests\Fixtures\Document\AssociatedDocument;
29
use Sonata\DoctrineMongoDBAdminBundle\Tests\Fixtures\Document\ContainerDocument;
30
use Sonata\DoctrineMongoDBAdminBundle\Tests\Fixtures\Document\EmbeddedDocument;
31
use Sonata\DoctrineMongoDBAdminBundle\Tests\Fixtures\Document\ProtectedDocument;
32
use Sonata\DoctrineMongoDBAdminBundle\Tests\Fixtures\Document\SimpleDocument;
33
use Symfony\Bridge\Doctrine\ManagerRegistry;
34
35
class ModelManagerTest extends TestCase
36
{
37
    /**
38
     * @dataProvider getWrongDocuments
39
     *
40
     * @param mixed $document
41
     */
42
    public function testNormalizedIdentifierException($document): void
43
    {
44
        $registry = $this->createStub(ManagerRegistry::class);
45
46
        $model = new ModelManager($registry);
47
48
        $this->expectException(\RuntimeException::class);
49
50
        $model->getNormalizedIdentifier($document);
51
    }
52
53
    public function getWrongDocuments(): iterable
54
    {
55
        yield [0];
56
        yield [1];
57
        yield [false];
58
        yield [true];
59
        yield [[]];
60
        yield [''];
61
        yield ['sonata-project'];
62
    }
63
64
    public function testSortParameters(): void
65
    {
66
        $registry = $this->createStub(ManagerRegistry::class);
67
68
        $manager = new ModelManager($registry);
69
70
        $datagrid1 = $this->createStub(Datagrid::class);
71
        $datagrid2 = $this->createStub(Datagrid::class);
72
73
        $field1 = new FieldDescription();
74
        $field1->setName('field1');
75
76
        $field2 = new FieldDescription();
77
        $field2->setName('field2');
78
79
        $field3 = new FieldDescription();
80
        $field3->setName('field3');
81
        $field3->setOption('sortable', 'field3sortBy');
82
83
        $datagrid1
84
            ->method('getValues')
85
            ->willReturn([
86
                '_sort_by' => $field1,
87
                '_sort_order' => 'ASC',
88
            ]);
89
90
        $datagrid2
91
            ->method('getValues')
92
            ->willReturn([
93
                '_sort_by' => $field3,
94
                '_sort_order' => 'ASC',
95
            ]);
96
97
        $parameters = $manager->getSortParameters($field1, $datagrid1);
98
99
        $this->assertSame('DESC', $parameters['filter']['_sort_order']);
100
        $this->assertSame('field1', $parameters['filter']['_sort_by']);
101
102
        $parameters = $manager->getSortParameters($field2, $datagrid1);
103
104
        $this->assertSame('ASC', $parameters['filter']['_sort_order']);
105
        $this->assertSame('field2', $parameters['filter']['_sort_by']);
106
107
        $parameters = $manager->getSortParameters($field3, $datagrid1);
108
109
        $this->assertSame('ASC', $parameters['filter']['_sort_order']);
110
        $this->assertSame('field3sortBy', $parameters['filter']['_sort_by']);
111
112
        $parameters = $manager->getSortParameters($field3, $datagrid2);
113
114
        $this->assertSame('DESC', $parameters['filter']['_sort_order']);
115
        $this->assertSame('field3sortBy', $parameters['filter']['_sort_by']);
116
    }
117
118
    public function testGetParentMetadataForProperty(): void
119
    {
120
        $containerDocumentClass = ContainerDocument::class;
121
        $associatedDocumentClass = AssociatedDocument::class;
122
        $embeddedDocumentClass = EmbeddedDocument::class;
123
124
        $dm = $this->createStub(DocumentManager::class);
125
126
        $registry = $this->createStub(ManagerRegistry::class);
127
128
        $modelManager = new ModelManager($registry);
129
130
        $registry
131
            ->method('getManagerForClass')
132
            ->willReturn($dm);
133
134
        $metadataFactory = $this->createStub(ClassMetadataFactory::class);
135
136
        $dm
137
            ->method('getMetadataFactory')
138
            ->willReturn($metadataFactory);
139
140
        $containerDocumentMetadata = $this->getMetadataForContainerDocument();
141
        $associatedDocumentMetadata = $this->getMetadataForAssociatedDocument();
142
        $embeddedDocumentMetadata = $this->getMetadataForEmbeddedDocument();
143
144
        $metadataFactory->method('getMetadataFor')
145
            ->willReturnMap(
146
                [
147
                    [$containerDocumentClass, $containerDocumentMetadata],
148
                    [$embeddedDocumentClass, $embeddedDocumentMetadata],
149
                    [$associatedDocumentClass, $associatedDocumentMetadata],
150
                ]
151
            );
152
153
        /** @var ClassMetadata $metadata */
154
        [$metadata, $lastPropertyName] = $modelManager
0 ignored issues
show
Bug introduced by
The variable $metadata does not exist. Did you mean $metadataFactory?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
Bug introduced by
The variable $lastPropertyName does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
155
            ->getParentMetadataForProperty($containerDocumentClass, 'plainField');
156
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'integer');
0 ignored issues
show
Bug introduced by
The variable $metadata does not exist. Did you mean $metadataFactory?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
157
158
        [$metadata, $lastPropertyName] = $modelManager
0 ignored issues
show
Bug introduced by
The variable $metadata does not exist. Did you mean $metadataFactory?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
159
            ->getParentMetadataForProperty($containerDocumentClass, 'associatedDocument.plainField');
160
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'string');
0 ignored issues
show
Bug introduced by
The variable $metadata does not exist. Did you mean $metadataFactory?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
161
162
        [$metadata, $lastPropertyName] = $modelManager
0 ignored issues
show
Bug introduced by
The variable $metadata does not exist. Did you mean $metadataFactory?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
163
            ->getParentMetadataForProperty($containerDocumentClass, 'embeddedDocument.plainField');
164
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
0 ignored issues
show
Bug introduced by
The variable $metadata does not exist. Did you mean $metadataFactory?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
165
166
        $this->assertSame($metadata->fieldMappings[$lastPropertyName]['type'], 'boolean');
0 ignored issues
show
Bug introduced by
The variable $metadata does not exist. Did you mean $metadataFactory?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
167
    }
168
169
    public function testModelReverseTransform(): void
170
    {
171
        $class = SimpleDocument::class;
172
173
        $metadataFactory = $this->createMock(ClassMetadataFactory::class);
174
        $modelManager = $this->createMock(ObjectManager::class);
175
        $registry = $this->createMock(ManagerRegistry::class);
176
177
        $classMetadata = new ClassMetadata($class);
178
        $classMetadata->reflClass = new \ReflectionClass($class);
179
180
        $modelManager->expects($this->once())
181
            ->method('getMetadataFactory')
182
            ->willReturn($metadataFactory);
183
        $metadataFactory->expects($this->once())
184
            ->method('getMetadataFor')
185
            ->with($class)
186
            ->willReturn($classMetadata);
187
        $registry->expects($this->once())
188
            ->method('getManagerForClass')
189
            ->with($class)
190
            ->willReturn($modelManager);
191
192
        $manager = new ModelManager($registry);
193
        $this->assertInstanceOf($class, $object = $manager->modelReverseTransform(
194
            $class,
195
            [
196
                'schmeckles' => 42,
197
                'multi_word_property' => 'hello',
198
            ]
199
        ));
200
        $this->assertSame(42, $object->getSchmeckles());
201
        $this->assertSame('hello', $object->getMultiWordProperty());
202
    }
203
204
    public function testCollections(): void
205
    {
206
        $registry = $this->createStub(ManagerRegistry::class);
207
        $model = new ModelManager($registry);
208
209
        $collection = $model->getModelCollectionInstance('whyDoWeEvenHaveThisParameter');
210
        $this->assertInstanceOf(ArrayCollection::class, $collection);
211
212
        $item1 = new \StdClass();
213
        $item2 = new \StdClass();
214
        $model->collectionAddElement($collection, $item1);
0 ignored issues
show
Bug introduced by
It seems like $collection defined by $model->getModelCollecti...EvenHaveThisParameter') on line 209 can also be of type object<ArrayAccess>; however, Sonata\DoctrineMongoDBAd...: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...
215
        $model->collectionAddElement($collection, $item2);
216
217
        $this->assertTrue($model->collectionHasElement($collection, $item1));
218
219
        $model->collectionRemoveElement($collection, $item1);
220
221
        $this->assertFalse($model->collectionHasElement($collection, $item1));
222
223
        $model->collectionClear($collection);
224
225
        $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...
226
    }
227
228
    public function testModelTransform(): void
229
    {
230
        $registry = $this->createStub(ManagerRegistry::class);
231
        $model = new ModelManager($registry);
232
233
        $instance = new \StdClass();
234
        $result = $model->modelTransform('thisIsNotUsed', $instance);
235
236
        $this->assertSame($instance, $result);
237
    }
238
239
    public function testGetPaginationParameters(): void
240
    {
241
        $datagrid = $this->createMock(DatagridInterface::class);
242
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
243
        $registry = $this->createStub(ManagerRegistry::class);
244
245
        $datagrid->expects($this->once())
246
            ->method('getValues')
247
            ->willReturn(['_sort_by' => $fieldDescription]);
248
249
        $fieldDescription->expects($this->once())
250
            ->method('getName')
251
            ->willReturn($name = 'test');
252
253
        $model = new ModelManager($registry);
254
255
        $result = $model->getPaginationParameters($datagrid, $page = 5);
256
257
        $this->assertSame($page, $result['filter']['_page']);
258
        $this->assertSame($name, $result['filter']['_sort_by']);
259
    }
260
261
    public function testGetModelInstanceException(): void
262
    {
263
        $registry = $this->createStub(ManagerRegistry::class);
264
265
        $model = new ModelManager($registry);
266
267
        $this->expectException(\InvalidArgumentException::class);
268
269
        $model->getModelInstance(AbstractDocument::class);
270
    }
271
272
    public function testGetModelInstanceForProtectedDocument(): void
273
    {
274
        $registry = $this->createStub(ManagerRegistry::class);
275
276
        $model = new ModelManager($registry);
277
278
        $this->assertInstanceOf(ProtectedDocument::class, $model->getModelInstance(ProtectedDocument::class));
279
    }
280
281
    public function testFindBadId(): void
282
    {
283
        $registry = $this->createStub(ManagerRegistry::class);
284
285
        $model = new ModelManager($registry);
286
287
        $this->assertNull($model->find('notImportant', null));
288
    }
289
290
    public function testGetUrlSafeIdentifierException(): void
291
    {
292
        $registry = $this->createStub(ManagerRegistry::class);
293
294
        $model = new ModelManager($registry);
295
296
        $this->expectException(\RuntimeException::class);
297
298
        $model->getNormalizedIdentifier(new \StdClass());
299
    }
300
301
    public function testGetUrlSafeIdentifierNull(): void
302
    {
303
        $registry = $this->createStub(ManagerRegistry::class);
304
305
        $model = new ModelManager($registry);
306
307
        $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...
308
    }
309
310
    private function getMetadataForEmbeddedDocument(): ClassMetadata
311
    {
312
        $metadata = new ClassMetadata(EmbeddedDocument::class);
313
314
        $metadata->fieldMappings = [
315
            'plainField' => [
316
                'fieldName' => 'plainField',
317
                'columnName' => 'plainField',
318
                'type' => 'boolean',
319
            ],
320
        ];
321
322
        return $metadata;
323
    }
324
325
    private function getMetadataForAssociatedDocument(): ClassMetadata
326
    {
327
        $embeddedDocumentClass = EmbeddedDocument::class;
328
329
        $metadata = new ClassMetadata(AssociatedDocument::class);
330
331
        $metadata->fieldMappings = [
332
            'plainField' => [
333
                'fieldName' => 'plainField',
334
                'name' => 'plainField',
335
                'columnName' => 'plainField',
336
                'type' => 'string',
337
            ],
338
        ];
339
340
        $metadata->mapOneEmbedded([
341
            'fieldName' => 'embeddedDocument',
342
            'name' => 'embeddedDocument',
343
            'targetDocument' => $embeddedDocumentClass,
344
        ]);
345
346
        return $metadata;
347
    }
348
349
    private function getMetadataForContainerDocument(): ClassMetadata
350
    {
351
        $containerDocumentClass = ContainerDocument::class;
352
        $associatedDocumentClass = AssociatedDocument::class;
353
        $embeddedDocumentClass = EmbeddedDocument::class;
354
355
        $metadata = new ClassMetadata($containerDocumentClass);
356
357
        $metadata->fieldMappings = [
358
            'plainField' => [
359
                'fieldName' => 'plainField',
360
                'name' => 'plainField',
361
                'columnName' => 'plainField',
362
                'type' => 'integer',
363
            ],
364
        ];
365
366
        $metadata->associationMappings['associatedDocument'] = [
367
            'fieldName' => 'associatedDocument',
368
            'name' => 'associatedDocument',
369
            'targetDocument' => $associatedDocumentClass,
370
            'sourceDocument' => $containerDocumentClass,
371
        ];
372
373
        $metadata->mapOneEmbedded([
374
            'fieldName' => 'embeddedDocument',
375
            'name' => 'embeddedDocument',
376
            'targetDocument' => $embeddedDocumentClass,
377
        ]);
378
379
        return $metadata;
380
    }
381
}
382