Completed
Push — master ( 78d40f...28dfb2 )
by Jordi Sala
02:47
created

tests/Action/SetObjectFieldValueActionTest.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Action;
15
16
use PHPUnit\Framework\TestCase;
17
use Prophecy\Argument;
18
use Sonata\AdminBundle\Action\GetShortObjectDescriptionAction;
19
use Sonata\AdminBundle\Action\SetObjectFieldValueAction;
20
use Sonata\AdminBundle\Admin\AbstractAdmin;
21
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
22
use Sonata\AdminBundle\Admin\Pool;
23
use Sonata\AdminBundle\Model\ModelManagerInterface;
24
use Sonata\AdminBundle\Templating\TemplateRegistryInterface;
25
use Sonata\AdminBundle\Twig\Extension\SonataAdminExtension;
26
use Symfony\Component\DependencyInjection\ContainerInterface;
27
use Symfony\Component\HttpFoundation\Request;
28
use Symfony\Component\HttpFoundation\Response;
29
use Symfony\Component\PropertyAccess\PropertyAccessor;
30
use Symfony\Component\Validator\ConstraintViolation;
31
use Symfony\Component\Validator\ConstraintViolationList;
32
use Symfony\Component\Validator\Validator\ValidatorInterface;
33
use Symfony\Contracts\Translation\TranslatorInterface;
34
use Twig\Environment;
35
use Twig\Loader\ArrayLoader;
36
37
final class SetObjectFieldValueActionTest extends TestCase
38
{
39
    /**
40
     * @var Pool
41
     */
42
    private $pool;
43
44
    /**
45
     * @var Environment
46
     */
47
    private $twig;
48
49
    /**
50
     * @var GetShortObjectDescriptionAction
51
     */
52
    private $action;
53
54
    /**
55
     * @var AbstractAdmin
56
     */
57
    private $admin;
58
59
    /**
60
     * @var ValidatorInterface
61
     */
62
    private $validator;
63
64
    protected function setUp(): void
65
    {
66
        $this->twig = new Environment(new ArrayLoader([
67
            'admin_template' => 'renderedTemplate',
68
            'field_template' => 'renderedTemplate',
69
        ]));
70
        $this->pool = $this->prophesize(Pool::class);
71
        $this->admin = $this->prophesize(AbstractAdmin::class);
72
        $this->pool->getInstance(Argument::any())->willReturn($this->admin->reveal());
73
        $this->admin->setRequest(Argument::type(Request::class))->shouldBeCalled();
74
        $this->validator = $this->prophesize(ValidatorInterface::class);
75
        $this->action = new SetObjectFieldValueAction(
76
            $this->twig,
77
            $this->pool->reveal(),
78
            $this->validator->reveal()
79
        );
80
    }
81
82
    public function testSetObjectFieldValueAction(): void
83
    {
84
        $object = new Foo();
85
        $request = new Request([
86
            'code' => 'sonata.post.admin',
87
            'objectId' => 42,
88
            'field' => 'enabled',
89
            'value' => 1,
90
            'context' => 'list',
91
        ], [], [], [], [], ['REQUEST_METHOD' => Request::METHOD_POST, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
92
93
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
94
        $pool = $this->prophesize(Pool::class);
95
        $translator = $this->prophesize(TranslatorInterface::class);
96
        $propertyAccessor = new PropertyAccessor();
97
        $templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
98
        $container = $this->prophesize(ContainerInterface::class);
99
100
        $this->admin->getObject(42)->willReturn($object);
101
        $this->admin->getCode()->willReturn('sonata.post.admin');
102
        $this->admin->hasAccess('edit', $object)->willReturn(true);
103
        $this->admin->getListFieldDescription('enabled')->willReturn($fieldDescription->reveal());
104
        $this->admin->update($object)->shouldBeCalled();
105
        $templateRegistry->getTemplate('base_list_field')->willReturn('admin_template');
106
        $container->get('sonata.post.admin.template_registry')->willReturn($templateRegistry->reveal());
107
        $this->pool->getPropertyAccessor()->willReturn($propertyAccessor);
108
        $this->twig->addExtension(new SonataAdminExtension(
109
            $pool->reveal(),
110
            null,
111
            $translator->reveal(),
112
            $container->reveal()
113
        ));
114
        $fieldDescription->getOption('editable')->willReturn(true);
115
        $fieldDescription->getAdmin()->willReturn($this->admin->reveal());
116
        $fieldDescription->getType()->willReturn('boolean');
117
        $fieldDescription->getTemplate()->willReturn('field_template');
118
        $fieldDescription->getValue(Argument::cetera())->willReturn('some value');
119
120
        $this->validator->validate($object)->willReturn(new ConstraintViolationList([]));
121
122
        $response = ($this->action)($request);
123
124
        $this->assertSame(Response::HTTP_OK, $response->getStatusCode());
125
    }
126
127
    public function getTimeZones(): iterable
128
    {
129
        $default = new \DateTimeZone(date_default_timezone_get());
130
        $custom = new \DateTimeZone('Europe/Rome');
131
132
        return [
133
            'empty timezone' => [null, $default],
134
            'disabled timezone' => [false, $default],
135
            'default timezone by name' => [$default->getName(), $default],
136
            'default timezone by object' => [$default, $default],
137
            'custom timezone by name' => [$custom->getName(), $custom],
138
            'custom timezone by object' => [$custom, $custom],
139
        ];
140
    }
141
142
    /**
143
     * @dataProvider getTimeZones
144
     */
145
    public function testSetObjectFieldValueActionWithDate($timezone, \DateTimeZone $expectedTimezone): void
146
    {
147
        $object = new Bafoo();
148
        $request = new Request([
149
            'code' => 'sonata.post.admin',
150
            'objectId' => 42,
151
            'field' => 'dateProp',
152
            'value' => '2020-12-12',
153
            'context' => 'list',
154
        ], [], [], [], [], ['REQUEST_METHOD' => Request::METHOD_POST, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
155
156
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
157
        $pool = $this->prophesize(Pool::class);
158
        $translator = $this->prophesize(TranslatorInterface::class);
159
        $propertyAccessor = new PropertyAccessor();
160
        $templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
161
        $container = $this->prophesize(ContainerInterface::class);
162
163
        $this->admin->getObject(42)->willReturn($object);
164
        $this->admin->getCode()->willReturn('sonata.post.admin');
165
        $this->admin->hasAccess('edit', $object)->willReturn(true);
166
        $this->admin->getListFieldDescription('dateProp')->willReturn($fieldDescription->reveal());
167
        $this->admin->update($object)->shouldBeCalled();
168
169
        $templateRegistry->getTemplate('base_list_field')->willReturn('admin_template');
170
        $container->get('sonata.post.admin.template_registry')->willReturn($templateRegistry->reveal());
171
        $this->pool->getPropertyAccessor()->willReturn($propertyAccessor);
172
        $this->twig->addExtension(new SonataAdminExtension(
173
            $pool->reveal(),
174
            null,
175
            $translator->reveal(),
176
            $container->reveal()
177
        ));
178
        $fieldDescription->getOption('editable')->willReturn(true);
179
        $fieldDescription->getOption('timezone')->willReturn($timezone);
180
        $fieldDescription->getAdmin()->willReturn($this->admin->reveal());
181
        $fieldDescription->getType()->willReturn('date');
182
        $fieldDescription->getTemplate()->willReturn('field_template');
183
        $fieldDescription->getValue(Argument::cetera())->willReturn('some value');
184
185
        $this->validator->validate($object)->willReturn(new ConstraintViolationList([]));
186
187
        $response = ($this->action)($request);
188
189
        $this->assertSame(Response::HTTP_OK, $response->getStatusCode());
190
191
        $defaultTimezone = new \DateTimeZone(date_default_timezone_get());
192
        $expectedDate = new \DateTime($request->query->get('value'), $expectedTimezone);
193
        $expectedDate->setTimezone($defaultTimezone);
194
195
        $this->assertInstanceOf(\DateTime::class, $object->getDateProp());
196
        $this->assertSame($expectedDate->format('Y-m-d'), $object->getDateProp()->format('Y-m-d'));
197
        $this->assertSame($defaultTimezone->getName(), $object->getDateProp()->getTimezone()->getName());
198
    }
199
200
    /**
201
     * @dataProvider getTimeZones
202
     */
203
    public function testSetObjectFieldValueActionWithDateTime($timezone, \DateTimeZone $expectedTimezone): void
204
    {
205
        $object = new Bafoo();
206
        $request = new Request([
207
            'code' => 'sonata.post.admin',
208
            'objectId' => 42,
209
            'field' => 'datetimeProp',
210
            'value' => '2020-12-12 23:11:23',
211
            'context' => 'list',
212
        ], [], [], [], [], ['REQUEST_METHOD' => Request::METHOD_POST, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
213
214
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
215
        $pool = $this->prophesize(Pool::class);
216
        $translator = $this->prophesize(TranslatorInterface::class);
217
        $propertyAccessor = new PropertyAccessor();
218
        $templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
219
        $container = $this->prophesize(ContainerInterface::class);
220
221
        $this->admin->getObject(42)->willReturn($object);
222
        $this->admin->getCode()->willReturn('sonata.post.admin');
223
        $this->admin->hasAccess('edit', $object)->willReturn(true);
224
        $this->admin->getListFieldDescription('datetimeProp')->willReturn($fieldDescription->reveal());
225
        $this->admin->update($object)->shouldBeCalled();
0 ignored issues
show
$object is of type object<Sonata\AdminBundle\Tests\Action\Bafoo>, but the function expects a object<Sonata\AdminBundle\Admin\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...
226
227
        $templateRegistry->getTemplate('base_list_field')->willReturn('admin_template');
228
        $container->get('sonata.post.admin.template_registry')->willReturn($templateRegistry->reveal());
229
        $this->pool->getPropertyAccessor()->willReturn($propertyAccessor);
230
        $this->twig->addExtension(new SonataAdminExtension(
231
            $pool->reveal(),
232
            null,
233
            $translator->reveal(),
234
            $container->reveal()
235
        ));
236
        $fieldDescription->getOption('editable')->willReturn(true);
237
        $fieldDescription->getOption('timezone')->willReturn($timezone);
238
        $fieldDescription->getAdmin()->willReturn($this->admin->reveal());
239
        $fieldDescription->getType()->willReturn('datetime');
240
        $fieldDescription->getTemplate()->willReturn('field_template');
241
        $fieldDescription->getValue(Argument::cetera())->willReturn('some value');
242
243
        $this->validator->validate($object)->willReturn(new ConstraintViolationList([]));
244
245
        $response = ($this->action)($request);
246
247
        $this->assertSame(Response::HTTP_OK, $response->getStatusCode());
248
249
        $defaultTimezone = new \DateTimeZone(date_default_timezone_get());
250
        $expectedDate = new \DateTime($request->query->get('value'), $expectedTimezone);
251
        $expectedDate->setTimezone($defaultTimezone);
252
253
        $this->assertInstanceOf(\DateTime::class, $object->getDatetimeProp());
254
        $this->assertSame($expectedDate->format('Y-m-d H:i:s'), $object->getDatetimeProp()->format('Y-m-d H:i:s'));
255
        $this->assertSame($defaultTimezone->getName(), $object->getDatetimeProp()->getTimezone()->getName());
256
    }
257
258
    public function testSetObjectFieldValueActionOnARelationField(): void
259
    {
260
        $object = new Baz();
261
        $associationObject = new Bar();
262
        $request = new Request([
263
            'code' => 'sonata.post.admin',
264
            'objectId' => 42,
265
            'field' => 'bar',
266
            'value' => 1,
267
            'context' => 'list',
268
        ], [], [], [], [], ['REQUEST_METHOD' => Request::METHOD_POST, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
269
270
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
271
        $modelManager = $this->prophesize(ModelManagerInterface::class);
272
        $translator = $this->prophesize(TranslatorInterface::class);
273
        $propertyAccessor = new PropertyAccessor();
274
        $templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
275
        $container = $this->prophesize(ContainerInterface::class);
276
277
        $this->admin->getObject(42)->willReturn($object);
278
        $this->admin->getCode()->willReturn('sonata.post.admin');
279
        $this->admin->hasAccess('edit', $object)->willReturn(true);
280
        $this->admin->getListFieldDescription('bar')->willReturn($fieldDescription->reveal());
281
        $this->admin->getClass()->willReturn(\get_class($object));
282
        $this->admin->update($object)->shouldBeCalled();
283
        $container->get('sonata.post.admin.template_registry')->willReturn($templateRegistry->reveal());
284
        $templateRegistry->getTemplate('base_list_field')->willReturn('admin_template');
285
        $this->admin->getModelManager()->willReturn($modelManager->reveal());
286
        $this->twig->addExtension(new SonataAdminExtension(
287
            $this->pool->reveal(),
288
            null,
289
            $translator->reveal(),
290
            $container->reveal()
291
        ));
292
        $this->pool->getPropertyAccessor()->willReturn($propertyAccessor);
293
        $fieldDescription->getType()->willReturn('choice');
294
        $fieldDescription->getOption('editable')->willReturn(true);
295
        $fieldDescription->getOption('class')->willReturn(Bar::class);
296
        $fieldDescription->getTargetModel()->willReturn(Bar::class);
297
        $fieldDescription->getAdmin()->willReturn($this->admin->reveal());
298
        $fieldDescription->getTemplate()->willReturn('field_template');
299
        $fieldDescription->getValue(Argument::cetera())->willReturn('some value');
300
        $modelManager->find(\get_class($associationObject), 1)->willReturn($associationObject);
301
302
        $this->validator->validate($object)->willReturn(new ConstraintViolationList([]));
303
304
        $response = ($this->action)($request);
305
306
        $this->assertSame(Response::HTTP_OK, $response->getStatusCode());
307
    }
308
309
    public function testSetObjectFieldValueActionWithViolations(): void
310
    {
311
        $bar = new Bar();
312
        $object = new Baz();
313
        $object->setBar($bar);
314
        $request = new Request([
315
            'code' => 'sonata.post.admin',
316
            'objectId' => 42,
317
            'field' => 'bar.enabled',
318
            'value' => 1,
319
            'context' => 'list',
320
        ], [], [], [], [], ['REQUEST_METHOD' => Request::METHOD_POST, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
321
322
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
323
        $propertyAccessor = new PropertyAccessor();
324
325
        $this->pool->getPropertyAccessor()->willReturn($propertyAccessor);
326
        $this->admin->getObject(42)->willReturn($object);
327
        $this->admin->hasAccess('edit', $object)->willReturn(true);
328
        $this->admin->getListFieldDescription('bar.enabled')->willReturn($fieldDescription->reveal());
329
        $this->validator->validate($bar)->willReturn(new ConstraintViolationList([
330
            new ConstraintViolation('error1', null, [], null, 'enabled', null),
331
            new ConstraintViolation('error2', null, [], null, 'enabled', null),
332
        ]));
333
        $fieldDescription->getOption('editable')->willReturn(true);
334
        $fieldDescription->getType()->willReturn('boolean');
335
336
        $response = ($this->action)($request);
337
338
        $this->assertSame(Response::HTTP_BAD_REQUEST, $response->getStatusCode());
339
        $this->assertSame(json_encode("error1\nerror2"), $response->getContent());
340
    }
341
342
    public function testSetObjectFieldEditableMultipleValue(): void
343
    {
344
        $object = new StatusMultiple();
345
        $request = new Request([
346
            'code' => 'sonata.post.admin',
347
            'objectId' => 42,
348
            'field' => 'status',
349
            'value' => [1, 2],
350
            'context' => 'list',
351
        ], [], [], [], [], ['REQUEST_METHOD' => Request::METHOD_POST, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest']);
352
353
        $fieldDescription = $this->prophesize(FieldDescriptionInterface::class);
354
        $pool = $this->prophesize(Pool::class);
355
        $template = $this->prophesize(Template::class);
356
        $translator = $this->prophesize(TranslatorInterface::class);
357
        $propertyAccessor = new PropertyAccessor();
358
        $templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
359
        $container = $this->prophesize(ContainerInterface::class);
360
361
        $this->admin->getObject(42)->willReturn($object);
362
        $this->admin->getCode()->willReturn('sonata.post.admin');
363
        $this->admin->hasAccess('edit', $object)->willReturn(true);
364
        $this->admin->getListFieldDescription('status')->willReturn($fieldDescription->reveal());
365
        $this->admin->update($object)->shouldBeCalled();
366
        $templateRegistry->getTemplate('base_list_field')->willReturn('admin_template');
367
        $container->get('sonata.post.admin.template_registry')->willReturn($templateRegistry->reveal());
368
        $this->pool->getPropertyAccessor()->willReturn($propertyAccessor);
369
        $this->twig->addExtension(new SonataAdminExtension(
370
            $pool->reveal(),
371
            null,
372
            $translator->reveal(),
373
            $container->reveal()
374
        ));
375
        $fieldDescription->getOption('editable')->willReturn(true);
376
        $fieldDescription->getOption('multiple')->willReturn(true);
377
        $fieldDescription->getAdmin()->willReturn($this->admin->reveal());
378
        $fieldDescription->getType()->willReturn('boolean');
379
        $fieldDescription->getTemplate()->willReturn('field_template');
380
        $fieldDescription->getValue(Argument::cetera())->willReturn(['some value']);
381
382
        $this->validator->validate($object)->willReturn(new ConstraintViolationList([]));
383
384
        $response = ($this->action)($request);
385
386
        $this->assertSame(Response::HTTP_OK, $response->getStatusCode());
387
    }
388
}
389