Completed
Push — 3.x ( 894c26...ed5f66 )
by Grégoire
10:30
created

testAddNewInstanceWithParentAssociation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.568
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\AdminBundle\Tests\Admin;
15
16
use Doctrine\Common\Collections\Collection;
17
use PHPUnit\Framework\TestCase;
18
use Sonata\AdminBundle\Admin\AdminHelper;
19
use Sonata\AdminBundle\Admin\AdminInterface;
20
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
21
use Sonata\AdminBundle\Admin\Pool;
22
use Sonata\AdminBundle\Tests\Fixtures\Entity\Foo;
23
use Symfony\Component\DependencyInjection\ContainerInterface;
24
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
25
use Symfony\Component\Form\DataMapperInterface;
26
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
27
use Symfony\Component\Form\FormBuilder;
28
use Symfony\Component\Form\FormFactoryInterface;
29
use Symfony\Component\Form\FormView;
30
use Symfony\Component\HttpFoundation\ParameterBag;
31
use Symfony\Component\HttpFoundation\Request;
32
use Symfony\Component\PropertyAccess\PropertyAccessorBuilder;
33
34
class AdminHelperTest extends TestCase
35
{
36
    /**
37
     * @var AdminHelper
38
     */
39
    protected $helper;
40
41
    public function setUp(): void
42
    {
43
        $container = $this->createMock(ContainerInterface::class);
44
45
        $pool = new Pool($container, 'title', 'logo.png');
46
        $this->helper = new AdminHelper($pool);
47
    }
48
49
    public function testGetChildFormBuilder(): void
50
    {
51
        $formFactory = $this->createMock(FormFactoryInterface::class);
52
        $eventDispatcher = $this->createMock(EventDispatcherInterface::class);
53
54
        $formBuilder = new FormBuilder('test', \stdClass::class, $eventDispatcher, $formFactory);
55
56
        $childFormBuilder = new FormBuilder('elementId', \stdClass::class, $eventDispatcher, $formFactory);
57
        $formBuilder->add($childFormBuilder);
58
59
        $this->assertNull($this->helper->getChildFormBuilder($formBuilder, 'foo'));
60
        $this->assertInstanceOf(FormBuilder::class, $this->helper->getChildFormBuilder($formBuilder, 'test_elementId'));
61
    }
62
63
    public function testGetChildFormView(): void
64
    {
65
        $formView = new FormView();
66
        $formView->vars['id'] = 'test';
67
        $child = new FormView($formView);
0 ignored issues
show
Documentation introduced by
$formView is of type object<Symfony\Component\Form\FormView>, but the function expects a null|object<self>.

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...
68
        $formView->children[] = $child;
69
        $child->vars['id'] = 'test_elementId';
70
71
        $this->assertNull($this->helper->getChildFormView($formView, 'foo'));
72
        $this->assertInstanceOf(FormView::class, $this->helper->getChildFormView($formView, 'test_elementId'));
73
    }
74
75
    public function testAddNewInstance(): void
76
    {
77
        $admin = $this->createMock(AdminInterface::class);
78
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
79
80
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
81
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
82
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBar']);
83
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
84
85
        $object = $this->getMockBuilder(\stdClass::class)
86
            ->setMethods(['addFooBar'])
87
            ->getMock();
88
        $object->expects($this->once())->method('addFooBar');
89
90
        $this->helper->addNewInstance($object, $fieldDescription);
91
    }
92
93
    public function testAddNewInstanceWithParentAssociation(): void
94
    {
95
        $admin = $this->createMock(AdminInterface::class);
96
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
97
98
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
99
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
100
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBar']);
101
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([['fieldName' => 'parent']]);
102
103
        $object2 = $this->getMockBuilder(\stdClass::class)
104
            ->setMethods(['addFooBar'])
105
            ->getMock();
106
        $object2->expects($this->once())->method('addFooBar');
107
108
        $object1 = $this->getMockBuilder(\stdClass::class)
109
            ->setMethods(['getParent'])
110
            ->getMock();
111
        $object1->expects($this->once())->method('getParent')->willReturn($object2);
112
113
        $this->helper->addNewInstance($object1, $fieldDescription);
114
    }
115
116
    public function testAddNewInstancePlural(): void
117
    {
118
        $admin = $this->createMock(AdminInterface::class);
119
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
120
121
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
122
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
123
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBars']);
124
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
125
126
        $object = $this->getMockBuilder(\stdClass::class)
127
            ->setMethods(['addFooBar'])
128
            ->getMock();
129
        $object->expects($this->once())->method('addFooBar');
130
131
        $this->helper->addNewInstance($object, $fieldDescription);
132
    }
133
134
    public function testAddNewInstanceInflector(): void
135
    {
136
        $admin = $this->createMock(AdminInterface::class);
137
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
138
139
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
140
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
141
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'entries']);
142
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
143
144
        $object = $this->getMockBuilder(\stdClass::class)
145
            ->setMethods(['addEntry'])
146
            ->getMock();
147
        $object->expects($this->once())->method('addEntry');
148
149
        $this->helper->addNewInstance($object, $fieldDescription);
150
    }
151
152
    public function testGetElementAccessPath(): void
153
    {
154
        $object = $this->getMockBuilder(\stdClass::class)
155
            ->setMethods(['getPathToObject'])
156
            ->getMock();
157
        $subObject = $this->getMockBuilder(\stdClass::class)
158
            ->setMethods(['getAnother'])
159
            ->getMock();
160
        $sub2Object = $this->getMockBuilder(\stdClass::class)
161
            ->setMethods(['getMoreThings'])
162
            ->getMock();
163
164
        $object->expects($this->atLeastOnce())->method('getPathToObject')->willReturn([$subObject]);
165
        $subObject->expects($this->atLeastOnce())->method('getAnother')->willReturn($sub2Object);
166
        $sub2Object->expects($this->atLeastOnce())->method('getMoreThings')->willReturn('Value');
167
168
        $path = $this->helper->getElementAccessPath('uniquePartOfId_path_to_object_0_another_more_things', $object);
169
170
        $this->assertSame('path_to_object[0].another.more_things', $path);
171
    }
172
173
    public function testItThrowsExceptionWhenDoesNotFindTheFullPath(): void
174
    {
175
        $path = 'uniquePartOfId_path_to_object_0_more_calls';
176
        $object = $this->getMockBuilder(\stdClass::class)
177
            ->setMethods(['getPathToObject'])
178
            ->getMock();
179
        $subObject = $this->getMockBuilder(\stdClass::class)
180
            ->setMethods(['getMore'])
181
            ->getMock();
182
183
        $object->expects($this->atLeastOnce())->method('getPathToObject')->willReturn([$subObject]);
184
        $subObject->expects($this->atLeastOnce())->method('getMore')->willReturn('Value');
185
186
        $this->expectException(\Exception::class);
187
        $this->expectExceptionMessage('Could not get element id from '.$path.' Failing part: calls');
188
189
        $this->helper->getElementAccessPath($path, $object);
190
    }
191
192
    public function testAppendFormFieldElement(): void
193
    {
194
        $container = $this->createMock(ContainerInterface::class);
195
196
        $propertyAccessorBuilder = new PropertyAccessorBuilder();
197
        $propertyAccesor = $propertyAccessorBuilder->getPropertyAccessor();
198
        $pool = new Pool($container, 'title', 'logo.png', [], $propertyAccesor);
199
        $helper = new AdminHelper($pool);
200
201
        $admin = $this->createMock(AdminInterface::class);
202
        $admin
203
            ->method('getClass')
204
            ->willReturn(Foo::class);
205
206
        $associationMapping = [
207
            'fieldName' => 'bar',
208
            'targetEntity' => Foo::class,
209
            'sourceEntity' => Foo::class,
210
            'isOwningSide' => false,
211
        ];
212
213
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
214
        $fieldDescription->method('getAssociationAdmin')->willReturn($admin);
215
        $fieldDescription->method('getAssociationMapping')->willReturn($associationMapping);
216
        $fieldDescription->method('getParentAssociationMappings')->willReturn([]);
217
218
        $admin
219
            ->method('getFormFieldDescription')
220
            ->willReturn($fieldDescription);
221
222
        $admin
223
            ->method('getFormFieldDescriptions')
224
            ->willReturn([
225
                'bar' => $fieldDescription,
226
            ]);
227
228
        $request = $this->createMock(Request::class);
229
        $request
230
            ->method('get')
231
            ->willReturn([
232
                'bar' => [
233
                    [
234
                        'baz' => [
235
                            'baz' => true,
236
                        ],
237
                    ],
238
                    ['_delete' => true],
239
                ],
240
            ]);
241
242
        $request->request = new ParameterBag();
243
244
        $admin
245
            ->method('getRequest')
246
            ->will($this->onConsecutiveCalls($request, $request, $request, null, $request, $request, $request, $request, null, $request));
247
248
        $foo = $this->createMock(Foo::class);
249
250
        $collection = $this->createMock(Collection::class);
251
        $foo->setBar($collection);
252
253
        $dataMapper = $this->createMock(DataMapperInterface::class);
254
        $formFactory = $this->createMock(FormFactoryInterface::class);
255
        $eventDispatcher = $this->createMock(EventDispatcherInterface::class);
256
        $formBuilder = new FormBuilder('test', \get_class($foo), $eventDispatcher, $formFactory);
257
        $childFormBuilder = new FormBuilder('bar', \stdClass::class, $eventDispatcher, $formFactory);
258
        $childFormBuilder->setCompound(true);
259
        $childFormBuilder->setDataMapper($dataMapper);
260
        $subChildFormBuilder = new FormBuilder('baz', \stdClass::class, $eventDispatcher, $formFactory);
261
        $subChildFormBuilder->setCompound(true);
262
        $subChildFormBuilder->setDataMapper($dataMapper);
263
        $childFormBuilder->add($subChildFormBuilder);
264
265
        $formBuilder->setCompound(true);
266
        $formBuilder->setDataMapper($dataMapper);
267
        $formBuilder->add($childFormBuilder);
268
269
        $admin->method('getFormBuilder')->willReturn($formBuilder);
270
        $admin->method('getSubject')->willReturn($foo);
271
272
        $finalForm = $helper->appendFormFieldElement($admin, $foo, 'test_bar')[1];
273
274
        foreach ($finalForm->get($childFormBuilder->getName()) as $childField) {
275
            $this->assertFalse($childField->has('_delete'));
276
        }
277
278
        $deleteFormBuilder = new FormBuilder('_delete', null, $eventDispatcher, $formFactory);
279
        $subChildFormBuilder->add($deleteFormBuilder, CheckboxType::class, ['delete' => false]);
280
281
        $finalForm = $helper->appendFormFieldElement($admin, $foo, 'test_bar')[1];
282
283
        foreach ($finalForm->get($childFormBuilder->getName()) as $childField) {
284
            $this->assertTrue($childField->has('_delete'));
285
            $this->assertSame('', $childField->get('_delete')->getData());
286
        }
287
    }
288
289
    public function testAppendFormFieldElementNested(): void
290
    {
291
        $admin = $this->createMock(AdminInterface::class);
292
        $object = $this->getMockBuilder(\stdClass::class)
293
            ->setMethods(['getSubObject'])
294
            ->getMock();
295
        $simpleObject = $this->getMockBuilder(\stdClass::class)
296
            ->setMethods(['getSubObject'])
297
            ->getMock();
298
        $subObject = $this->getMockBuilder(\stdClass::class)
299
            ->setMethods(['getAnd'])
300
            ->getMock();
301
        $sub2Object = $this->getMockBuilder(\stdClass::class)
302
            ->setMethods(['getMore'])
303
            ->getMock();
304
        $sub3Object = $this->getMockBuilder(\stdClass::class)
305
            ->setMethods(['getFinalData'])
306
            ->getMock();
307
        $dataMapper = $this->createMock(DataMapperInterface::class);
308
        $formFactory = $this->createMock(FormFactoryInterface::class);
309
        $eventDispatcher = $this->createMock(EventDispatcherInterface::class);
310
        $formBuilder = new FormBuilder('test', \get_class($simpleObject), $eventDispatcher, $formFactory);
311
        $childFormBuilder = new FormBuilder('subObject', \get_class($subObject), $eventDispatcher, $formFactory);
312
313
        $object->expects($this->atLeastOnce())->method('getSubObject')->willReturn([$subObject]);
314
        $subObject->expects($this->atLeastOnce())->method('getAnd')->willReturn($sub2Object);
315
        $sub2Object->expects($this->atLeastOnce())->method('getMore')->willReturn([$sub3Object]);
316
        $sub3Object->expects($this->atLeastOnce())->method('getFinalData')->willReturn('value');
317
318
        $formBuilder->setCompound(true);
319
        $formBuilder->setDataMapper($dataMapper);
320
        $formBuilder->add($childFormBuilder);
321
322
        $admin->expects($this->once())->method('getFormBuilder')->willReturn($formBuilder);
323
        $admin->expects($this->once())->method('getSubject')->willReturn($object);
324
325
        $this->expectException(\Exception::class);
326
        $this->expectExceptionMessage('unknown collection class');
327
328
        $this->helper->appendFormFieldElement($admin, $simpleObject, 'uniquePartOfId_sub_object_0_and_more_0_final_data');
329
    }
330
}
331