Completed
Push — master ( 43b306...d002ef )
by Jordi Sala
14s queued 11s
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\Extension\HttpFoundation\HttpFoundationRequestHandler;
28
use Symfony\Component\Form\FormBuilder;
29
use Symfony\Component\Form\FormFactoryInterface;
30
use Symfony\Component\Form\FormView;
31
use Symfony\Component\HttpFoundation\ParameterBag;
32
use Symfony\Component\HttpFoundation\Request;
33
use Symfony\Component\PropertyAccess\PropertyAccessorBuilder;
34
35
class AdminHelperTest extends TestCase
36
{
37
    /**
38
     * @var AdminHelper
39
     */
40
    protected $helper;
41
42
    protected function setUp(): void
43
    {
44
        $container = new Container();
45
46
        $pool = new Pool($container, 'title', 'logo.png');
47
        $this->helper = new AdminHelper($pool);
48
    }
49
50
    public function testGetChildFormBuilder(): void
51
    {
52
        $formFactory = $this->createMock(FormFactoryInterface::class);
53
        $eventDispatcher = $this->createMock(EventDispatcherInterface::class);
54
55
        $formBuilder = new FormBuilder('test', \stdClass::class, $eventDispatcher, $formFactory);
56
57
        $childFormBuilder = new FormBuilder('elementId', \stdClass::class, $eventDispatcher, $formFactory);
58
        $formBuilder->add($childFormBuilder);
59
60
        $this->assertNull($this->helper->getChildFormBuilder($formBuilder, 'foo'));
61
        $this->assertInstanceOf(FormBuilder::class, $this->helper->getChildFormBuilder($formBuilder, 'test_elementId'));
62
    }
63
64
    public function testGetChildFormView(): void
65
    {
66
        $formView = new FormView();
67
        $formView->vars['id'] = 'test';
68
        $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...
69
        $formView->children[] = $child;
70
        $child->vars['id'] = 'test_elementId';
71
72
        $this->assertNull($this->helper->getChildFormView($formView, 'foo'));
73
        $this->assertInstanceOf(FormView::class, $this->helper->getChildFormView($formView, 'test_elementId'));
74
    }
75
76
    /**
77
     * NEXT_MAJOR: Remove this test.
78
     *
79
     * @group legacy
80
     *
81
     * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.72. It will be removed in version 4.0. Use Sonata\AdminBundle\Manipulator\ObjectManipulator::addInstance() instead.
82
     */
83
    public function testAddNewInstance(): void
84
    {
85
        $admin = $this->createMock(AdminInterface::class);
86
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
87
88
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
89
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
90
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBar']);
91
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
92
93
        $object = $this->getMockBuilder(\stdClass::class)
94
            ->setMethods(['addFooBar'])
95
            ->getMock();
96
        $object->expects($this->once())->method('addFooBar');
97
98
        $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.72, 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...
99
    }
100
101
    /**
102
     * NEXT_MAJOR: Remove this test.
103
     *
104
     * @group legacy
105
     *
106
     * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.72. It will be removed in version 4.0. Use Sonata\AdminBundle\Manipulator\ObjectManipulator::addInstance() instead.
107
     */
108
    public function testAddNewInstancePlural(): void
109
    {
110
        $admin = $this->createMock(AdminInterface::class);
111
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
112
113
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
114
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
115
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBars']);
116
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
117
118
        $object = $this->getMockBuilder(\stdClass::class)
119
            ->setMethods(['addFooBar'])
120
            ->getMock();
121
        $object->expects($this->once())->method('addFooBar');
122
123
        $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.72, 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...
124
    }
125
126
    /**
127
     * NEXT_MAJOR: Remove this test.
128
     *
129
     * @group legacy
130
     *
131
     * @expectedDeprecation Method Sonata\AdminBundle\Admin\AdminHelper::addNewInstance() is deprecated since sonata-project/admin-bundle 3.72. It will be removed in version 4.0. Use Sonata\AdminBundle\Manipulator\ObjectManipulator::addInstance() instead.
132
     */
133
    public function testAddNewInstanceInflector(): void
134
    {
135
        $admin = $this->createMock(AdminInterface::class);
136
        $admin->expects($this->once())->method('getNewInstance')->willReturn(new \stdClass());
137
138
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
139
        $fieldDescription->expects($this->once())->method('getAssociationAdmin')->willReturn($admin);
140
        $fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'entries']);
141
        $fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
142
143
        $object = $this->getMockBuilder(\stdClass::class)
144
            ->setMethods(['addEntry'])
145
            ->getMock();
146
        $object->expects($this->once())->method('addEntry');
147
148
        $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.72, 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...
149
    }
150
151
    public function testGetElementAccessPath(): void
152
    {
153
        $object = $this->getMockBuilder(\stdClass::class)
154
            ->setMethods(['getPathToObject'])
155
            ->getMock();
156
        $subObject = $this->getMockBuilder(\stdClass::class)
157
            ->setMethods(['getAnother'])
158
            ->getMock();
159
        $sub2Object = $this->getMockBuilder(\stdClass::class)
160
            ->setMethods(['getMoreThings'])
161
            ->getMock();
162
163
        $object->expects($this->atLeastOnce())->method('getPathToObject')->willReturn([$subObject]);
164
        $subObject->expects($this->atLeastOnce())->method('getAnother')->willReturn($sub2Object);
165
        $sub2Object->expects($this->atLeastOnce())->method('getMoreThings')->willReturn('Value');
166
167
        $path = $this->helper->getElementAccessPath('uniquePartOfId_path_to_object_0_another_more_things', $object);
168
169
        $this->assertSame('path_to_object[0].another.more_things', $path);
170
    }
171
172
    public function testItThrowsExceptionWhenDoesNotFindTheFullPath(): void
173
    {
174
        $path = 'uniquePartOfId_path_to_object_0_more_calls';
175
        $object = $this->getMockBuilder(\stdClass::class)
176
            ->setMethods(['getPathToObject'])
177
            ->getMock();
178
        $subObject = $this->getMockBuilder(\stdClass::class)
179
            ->setMethods(['getMore'])
180
            ->getMock();
181
182
        $object->expects($this->atLeastOnce())->method('getPathToObject')->willReturn([$subObject]);
183
        $subObject->expects($this->atLeastOnce())->method('getMore')->willReturn('Value');
184
185
        $this->expectException(\Exception::class);
186
        $this->expectExceptionMessage(sprintf('Could not get element id from %s Failing part: calls', $path));
187
188
        $this->helper->getElementAccessPath($path, $object);
189
    }
190
191
    public function testAppendFormFieldElement(): void
192
    {
193
        $container = new Container();
194
195
        $propertyAccessorBuilder = new PropertyAccessorBuilder();
196
        $propertyAccessor = $propertyAccessorBuilder->getPropertyAccessor();
197
        $pool = new Pool($container, 'title', 'logo.png', [], $propertyAccessor);
198
        $helper = new AdminHelper($pool);
199
200
        $admin = $this->createMock(AdminInterface::class);
201
        $admin
202
            ->method('getClass')
203
            ->willReturn(Foo::class);
204
205
        $associationAdmin = $this->createMock(AdminInterface::class);
206
        $associationAdmin
207
            ->method('getClass')
208
            ->willReturn(Bar::class);
209
210
        $associationMapping = [
211
            'fieldName' => 'bar',
212
            'targetEntity' => Foo::class,
213
            'sourceEntity' => Foo::class,
214
            'isOwningSide' => false,
215
        ];
216
217
        $fieldDescription = $this->createMock(FieldDescriptionInterface::class);
218
        $fieldDescription->method('getAssociationAdmin')->willReturn($associationAdmin);
219
        $fieldDescription->method('getAssociationMapping')->willReturn($associationMapping);
220
        $fieldDescription->method('getParentAssociationMappings')->willReturn([]);
221
222
        $admin
223
            ->method('getFormFieldDescription')
224
            ->willReturn($fieldDescription);
225
226
        $associationAdmin
227
            ->method('getFormFieldDescriptions')
228
            ->willReturn([
229
                'bar' => $fieldDescription,
230
            ]);
231
232
        $request = $this->createMock(Request::class);
233
        $request
234
            ->method('get')
235
            ->willReturn([
236
                'bar' => [
237
                    [
238
                        'baz' => [
239
                            'baz' => true,
240
                        ],
241
                    ],
242
                    ['_delete' => true],
243
                ],
244
            ]);
245
246
        $request->request = new ParameterBag();
247
248
        $admin
249
            ->expects($this->atLeastOnce())
250
            ->method('getRequest')
251
            ->willReturn($request);
252
253
        $foo = $this->createMock(Foo::class);
254
        $admin
255
            ->method('hasSubject')
256
            ->willReturn(true);
257
        $admin
258
            ->method('getSubject')
259
            ->willReturn($foo);
260
261
        $bar = new \stdClass();
262
        $associationAdmin
263
            ->expects($this->atLeastOnce())
264
            ->method('getNewInstance')
265
            ->willReturn($bar);
266
267
        $foo->expects($this->atLeastOnce())->method('addBar')->with($bar);
268
269
        $dataMapper = $this->createMock(DataMapperInterface::class);
270
        $formFactory = $this->createMock(FormFactoryInterface::class);
271
        $eventDispatcher = $this->createMock(EventDispatcherInterface::class);
272
        $formBuilder = new FormBuilder('test', \get_class($foo), $eventDispatcher, $formFactory);
273
        $childFormBuilder = new FormBuilder('bar', \stdClass::class, $eventDispatcher, $formFactory);
274
        $childFormBuilder->setCompound(true);
275
        $childFormBuilder->setDataMapper($dataMapper);
276
        $subChildFormBuilder = new FormBuilder('baz', \stdClass::class, $eventDispatcher, $formFactory);
277
        $subChildFormBuilder->setCompound(true);
278
        $subChildFormBuilder->setDataMapper($dataMapper);
279
        $childFormBuilder->add($subChildFormBuilder);
280
281
        $formBuilder->setRequestHandler(new HttpFoundationRequestHandler());
282
        $formBuilder->setCompound(true);
283
        $formBuilder->setDataMapper($dataMapper);
284
        $formBuilder->add($childFormBuilder);
285
286
        $associationAdmin->expects($this->atLeastOnce())->method('setSubject')->with($bar);
287
        $admin->method('getFormBuilder')->willReturn($formBuilder);
288
289
        $finalForm = $helper->appendFormFieldElement($admin, $foo, 'test_bar')[1];
290
291
        foreach ($finalForm->get($childFormBuilder->getName()) as $childField) {
292
            $this->assertFalse($childField->has('_delete'));
293
        }
294
295
        $deleteFormBuilder = new FormBuilder('_delete', null, $eventDispatcher, $formFactory);
296
        $subChildFormBuilder->add($deleteFormBuilder, CheckboxType::class, ['delete' => false]);
297
298
        $finalForm = $helper->appendFormFieldElement($admin, $foo, 'test_bar')[1];
299
300
        foreach ($finalForm->get($childFormBuilder->getName()) as $childField) {
301
            $this->assertTrue($childField->has('_delete'));
302
            $this->assertSame('', $childField->get('_delete')->getData());
303
        }
304
    }
305
306
    public function testAppendFormFieldElementNested(): void
307
    {
308
        $admin = $this->createMock(AdminInterface::class);
309
        $request = $this->createMock(Request::class);
310
        $request
311
            ->method('get')
312
            ->willReturn([
313
                'bar' => [
314
                    [
315
                        'baz' => [
316
                            'baz' => true,
317
                        ],
318
                    ],
319
                    ['_delete' => true],
320
                ],
321
            ]);
322
323
        $request->request = new ParameterBag();
324
325
        $admin
326
            ->expects($this->atLeastOnce())
327
            ->method('getRequest')
328
            ->willReturn($request);
329
        $object = $this->getMockBuilder(\stdClass::class)
330
            ->setMethods(['getSubObject'])
331
            ->getMock();
332
333
        $subObject = $this->getMockBuilder(\stdClass::class)
334
            ->setMethods(['getAnd'])
335
            ->getMock();
336
        $sub2Object = $this->getMockBuilder(\stdClass::class)
337
            ->setMethods(['getMore'])
338
            ->getMock();
339
        $sub3Object = $this->getMockBuilder(\stdClass::class)
340
            ->setMethods(['getFinalData'])
341
            ->getMock();
342
        $dataMapper = $this->createMock(DataMapperInterface::class);
343
        $formFactory = $this->createMock(FormFactoryInterface::class);
344
        $eventDispatcher = $this->createMock(EventDispatcherInterface::class);
345
        $formBuilder = new FormBuilder('test', \get_class($object), $eventDispatcher, $formFactory);
346
        $childFormBuilder = new FormBuilder('subObject', \get_class($subObject), $eventDispatcher, $formFactory);
347
348
        $object->expects($this->atLeastOnce())->method('getSubObject')->willReturn([$subObject]);
349
        $subObject->expects($this->atLeastOnce())->method('getAnd')->willReturn($sub2Object);
350
        $sub2Object->expects($this->atLeastOnce())->method('getMore')->willReturn([$sub3Object]);
351
        $sub3Object->expects($this->atLeastOnce())->method('getFinalData')->willReturn('value');
352
353
        $formBuilder->setRequestHandler(new HttpFoundationRequestHandler());
354
        $formBuilder->setCompound(true);
355
        $formBuilder->setDataMapper($dataMapper);
356
        $formBuilder->add($childFormBuilder);
357
358
        $admin->method('hasSubject')->willReturn(true);
359
        $admin->method('getSubject')->willReturn($object);
360
        $admin->expects($this->once())->method('getFormBuilder')->willReturn($formBuilder);
361
362
        $this->expectException(\Exception::class);
363
        $this->expectExceptionMessage('unknown collection class');
364
365
        $this->helper->appendFormFieldElement($admin, $object, 'uniquePartOfId_sub_object_0_and_more_0_final_data');
366
    }
367
}
368