Completed
Pull Request — 3.x (#6171)
by Vincent
03:03
created

AdminHelperTest   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 310
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
wmc 12
lcom 1
cbo 8
dl 0
loc 310
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 7 1
A testGetChildFormBuilder() 0 13 1
A testGetChildFormView() 0 11 1
A testAddNewInstance() 0 17 1
A testAddNewInstancePlural() 0 17 1
A testAddNewInstanceInflector() 0 17 1
A testGetElementAccessPath() 0 20 1
A testItThrowsExceptionWhenDoesNotFindTheFullPath() 0 18 1
B testAppendFormFieldElement() 0 112 3
A testAppendFormFieldElementNested() 0 40 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\AdminBundle\Tests\Admin;
15
16
use PHPUnit\Framework\TestCase;
17
use Sonata\AdminBundle\Admin\AdminHelper;
18
use Sonata\AdminBundle\Admin\AdminInterface;
19
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
20
use Sonata\AdminBundle\Admin\Pool;
21
use Sonata\AdminBundle\Tests\Fixtures\Entity\Bar;
22
use Sonata\AdminBundle\Tests\Fixtures\Entity\Foo;
23
use Symfony\Component\DependencyInjection\Container;
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
    protected function setUp(): void
42
    {
43
        $container = new Container();
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
    /**
76
     * NEXT_MAJOR: Remove this test.
77
     *
78
     * @group legacy
79
     *
80
     * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.x. It will be removed in version 4.0. Use Sonata\AdminBundle\Manipulator\ObjectManipulator::addInstance() instead.
81
     */
82
    public function testAddNewInstance(): void
83
    {
84
        $admin = $this->createMock(AdminInterface::class);
85
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
86
87
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
88
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
89
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBar']);
90
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
91
92
        $object = $this->getMockBuilder(\stdClass::class)
93
            ->setMethods(['addFooBar'])
94
            ->getMock();
95
        $object->expects($this->once())->method('addFooBar');
96
97
        $this->helper->addNewInstance($object, $fieldDescription);
0 ignored issues
show
Deprecated Code introduced by
The method Sonata\AdminBundle\Admin...elper::addNewInstance() has been deprecated with message: since sonata-project/admin-bundle 3.x, use to be removed with 4.0. Add a new instance to the related FieldDescriptionInterface value.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
98
    }
99
100
    /**
101
     * NEXT_MAJOR: Remove this test.
102
     *
103
     * @group legacy
104
     *
105
     * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.x. It will be removed in version 4.0. Use Sonata\AdminBundle\Manipulator\ObjectManipulator::addInstance() instead.
106
     */
107
    public function testAddNewInstancePlural(): void
108
    {
109
        $admin = $this->createMock(AdminInterface::class);
110
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
111
112
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
113
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
114
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBars']);
115
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
116
117
        $object = $this->getMockBuilder(\stdClass::class)
118
            ->setMethods(['addFooBar'])
119
            ->getMock();
120
        $object->expects($this->once())->method('addFooBar');
121
122
        $this->helper->addNewInstance($object, $fieldDescription);
0 ignored issues
show
Deprecated Code introduced by
The method Sonata\AdminBundle\Admin...elper::addNewInstance() has been deprecated with message: since sonata-project/admin-bundle 3.x, use to be removed with 4.0. Add a new instance to the related FieldDescriptionInterface value.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
123
    }
124
125
    /**
126
     * NEXT_MAJOR: Remove this test.
127
     *
128
     * @group legacy
129
     *
130
     * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.x. It will be removed in version 4.0. Use Sonata\AdminBundle\Manipulator\ObjectManipulator::addInstance() instead.
131
     */
132
    public function testAddNewInstanceInflector(): void
133
    {
134
        $admin = $this->createMock(AdminInterface::class);
135
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
136
137
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
138
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
139
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'entries']);
140
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
141
142
        $object = $this->getMockBuilder(\stdClass::class)
143
            ->setMethods(['addEntry'])
144
            ->getMock();
145
        $object->expects($this->once())->method('addEntry');
146
147
        $this->helper->addNewInstance($object, $fieldDescription);
0 ignored issues
show
Deprecated Code introduced by
The method Sonata\AdminBundle\Admin...elper::addNewInstance() has been deprecated with message: since sonata-project/admin-bundle 3.x, use to be removed with 4.0. Add a new instance to the related FieldDescriptionInterface value.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
148
    }
149
150
    public function testGetElementAccessPath(): void
151
    {
152
        $object = $this->getMockBuilder(\stdClass::class)
153
            ->setMethods(['getPathToObject'])
154
            ->getMock();
155
        $subObject = $this->getMockBuilder(\stdClass::class)
156
            ->setMethods(['getAnother'])
157
            ->getMock();
158
        $sub2Object = $this->getMockBuilder(\stdClass::class)
159
            ->setMethods(['getMoreThings'])
160
            ->getMock();
161
162
        $object->expects($this->atLeastOnce())->method('getPathToObject')->willReturn([$subObject]);
163
        $subObject->expects($this->atLeastOnce())->method('getAnother')->willReturn($sub2Object);
164
        $sub2Object->expects($this->atLeastOnce())->method('getMoreThings')->willReturn('Value');
165
166
        $path = $this->helper->getElementAccessPath('uniquePartOfId_path_to_object_0_another_more_things', $object);
167
168
        $this->assertSame('path_to_object[0].another.more_things', $path);
169
    }
170
171
    public function testItThrowsExceptionWhenDoesNotFindTheFullPath(): void
172
    {
173
        $path = 'uniquePartOfId_path_to_object_0_more_calls';
174
        $object = $this->getMockBuilder(\stdClass::class)
175
            ->setMethods(['getPathToObject'])
176
            ->getMock();
177
        $subObject = $this->getMockBuilder(\stdClass::class)
178
            ->setMethods(['getMore'])
179
            ->getMock();
180
181
        $object->expects($this->atLeastOnce())->method('getPathToObject')->willReturn([$subObject]);
182
        $subObject->expects($this->atLeastOnce())->method('getMore')->willReturn('Value');
183
184
        $this->expectException(\Exception::class);
185
        $this->expectExceptionMessage(sprintf('Could not get element id from %s Failing part: calls', $path));
186
187
        $this->helper->getElementAccessPath($path, $object);
188
    }
189
190
    public function testAppendFormFieldElement(): void
191
    {
192
        $container = new Container();
193
194
        $propertyAccessorBuilder = new PropertyAccessorBuilder();
195
        $propertyAccessor = $propertyAccessorBuilder->getPropertyAccessor();
196
        $pool = new Pool($container, 'title', 'logo.png', [], $propertyAccessor);
197
        $helper = new AdminHelper($pool);
198
199
        $admin = $this->createMock(AdminInterface::class);
200
        $admin
201
            ->method('getClass')
202
            ->willReturn(Foo::class);
203
204
        $associationAdmin = $this->createMock(AdminInterface::class);
205
        $associationAdmin
206
            ->method('getClass')
207
            ->willReturn(Bar::class);
208
209
        $associationMapping = [
210
            'fieldName' => 'bar',
211
            'targetEntity' => Foo::class,
212
            'sourceEntity' => Foo::class,
213
            'isOwningSide' => false,
214
        ];
215
216
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
217
        $fieldDescription->method('getAssociationAdmin')->willReturn($associationAdmin);
218
        $fieldDescription->method('getAssociationMapping')->willReturn($associationMapping);
219
        $fieldDescription->method('getParentAssociationMappings')->willReturn([]);
220
221
        $admin
222
            ->method('getFormFieldDescription')
223
            ->willReturn($fieldDescription);
224
225
        $associationAdmin
226
            ->method('getFormFieldDescriptions')
227
            ->willReturn([
228
                'bar' => $fieldDescription,
229
            ]);
230
231
        $request = $this->createMock(Request::class);
232
        $request
233
            ->method('get')
234
            ->willReturn([
235
                'bar' => [
236
                    [
237
                        'baz' => [
238
                            'baz' => true,
239
                        ],
240
                    ],
241
                    ['_delete' => true],
242
                ],
243
            ]);
244
245
        $request->request = new ParameterBag();
246
247
        $admin
248
            ->method('getRequest')
249
            ->will($this->onConsecutiveCalls($request, $request, $request, null, $request, $request, $request, $request, null, $request));
250
251
        $foo = $this->createMock(Foo::class);
252
        $admin
253
            ->method('hasSubject')
254
            ->willReturn(true);
255
        $admin
256
            ->method('getSubject')
257
            ->willReturn($foo);
258
259
        $bar = new \stdClass();
260
        $associationAdmin
261
            ->expects($this->atLeastOnce())
262
            ->method('getNewInstance')
263
            ->willReturn($bar);
264
265
        $foo->expects($this->atLeastOnce())->method('addBar')->with($bar);
266
267
        $dataMapper = $this->createMock(DataMapperInterface::class);
268
        $formFactory = $this->createMock(FormFactoryInterface::class);
269
        $eventDispatcher = $this->createMock(EventDispatcherInterface::class);
270
        $formBuilder = new FormBuilder('test', \get_class($foo), $eventDispatcher, $formFactory);
271
        $childFormBuilder = new FormBuilder('bar', \stdClass::class, $eventDispatcher, $formFactory);
272
        $childFormBuilder->setCompound(true);
273
        $childFormBuilder->setDataMapper($dataMapper);
274
        $subChildFormBuilder = new FormBuilder('baz', \stdClass::class, $eventDispatcher, $formFactory);
275
        $subChildFormBuilder->setCompound(true);
276
        $subChildFormBuilder->setDataMapper($dataMapper);
277
        $childFormBuilder->add($subChildFormBuilder);
278
279
        $formBuilder->setCompound(true);
280
        $formBuilder->setDataMapper($dataMapper);
281
        $formBuilder->add($childFormBuilder);
282
283
        $associationAdmin->expects($this->atLeastOnce())->method('setSubject')->with($bar);
284
        $admin->method('getFormBuilder')->willReturn($formBuilder);
285
286
        $finalForm = $helper->appendFormFieldElement($admin, $foo, 'test_bar')[1];
287
288
        foreach ($finalForm->get($childFormBuilder->getName()) as $childField) {
289
            $this->assertFalse($childField->has('_delete'));
290
        }
291
292
        $deleteFormBuilder = new FormBuilder('_delete', null, $eventDispatcher, $formFactory);
293
        $subChildFormBuilder->add($deleteFormBuilder, CheckboxType::class, ['delete' => false]);
294
295
        $finalForm = $helper->appendFormFieldElement($admin, $foo, 'test_bar')[1];
296
297
        foreach ($finalForm->get($childFormBuilder->getName()) as $childField) {
298
            $this->assertTrue($childField->has('_delete'));
299
            $this->assertSame('', $childField->get('_delete')->getData());
300
        }
301
    }
302
303
    public function testAppendFormFieldElementNested(): void
304
    {
305
        $admin = $this->createMock(AdminInterface::class);
306
        $object = $this->getMockBuilder(\stdClass::class)
307
            ->setMethods(['getSubObject'])
308
            ->getMock();
309
310
        $subObject = $this->getMockBuilder(\stdClass::class)
311
            ->setMethods(['getAnd'])
312
            ->getMock();
313
        $sub2Object = $this->getMockBuilder(\stdClass::class)
314
            ->setMethods(['getMore'])
315
            ->getMock();
316
        $sub3Object = $this->getMockBuilder(\stdClass::class)
317
            ->setMethods(['getFinalData'])
318
            ->getMock();
319
        $dataMapper = $this->createMock(DataMapperInterface::class);
320
        $formFactory = $this->createMock(FormFactoryInterface::class);
321
        $eventDispatcher = $this->createMock(EventDispatcherInterface::class);
322
        $formBuilder = new FormBuilder('test', \get_class($object), $eventDispatcher, $formFactory);
323
        $childFormBuilder = new FormBuilder('subObject', \get_class($subObject), $eventDispatcher, $formFactory);
324
325
        $object->expects($this->atLeastOnce())->method('getSubObject')->willReturn([$subObject]);
326
        $subObject->expects($this->atLeastOnce())->method('getAnd')->willReturn($sub2Object);
327
        $sub2Object->expects($this->atLeastOnce())->method('getMore')->willReturn([$sub3Object]);
328
        $sub3Object->expects($this->atLeastOnce())->method('getFinalData')->willReturn('value');
329
330
        $formBuilder->setCompound(true);
331
        $formBuilder->setDataMapper($dataMapper);
332
        $formBuilder->add($childFormBuilder);
333
334
        $admin->method('hasSubject')->willReturn(true);
335
        $admin->method('getSubject')->willReturn($object);
336
        $admin->expects($this->once())->method('getFormBuilder')->willReturn($formBuilder);
337
338
        $this->expectException(\Exception::class);
339
        $this->expectExceptionMessage('unknown collection class');
340
341
        $this->helper->appendFormFieldElement($admin, $object, 'uniquePartOfId_sub_object_0_and_more_0_final_data');
342
    }
343
}
344