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