Completed
Push — master ( e6c9d7...cc6bd7 )
by Grégoire
12:23
created

tests/Twig/Extension/SonataAdminExtensionTest.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\Twig\Extension;
15
16
use PHPUnit\Framework\TestCase;
17
use Prophecy\Argument;
18
use Psr\Log\LoggerInterface;
19
use Sonata\AdminBundle\Admin\AbstractAdmin;
20
use Sonata\AdminBundle\Admin\AdminInterface;
21
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
22
use Sonata\AdminBundle\Admin\Pool;
23
use Sonata\AdminBundle\Exception\NoValueException;
24
use Sonata\AdminBundle\Templating\TemplateRegistryInterface;
25
use Sonata\AdminBundle\Tests\Fixtures\Entity\FooToString;
26
use Sonata\AdminBundle\Twig\Extension\SonataAdminExtension;
27
use Symfony\Bridge\Twig\AppVariable;
28
use Symfony\Bridge\Twig\Extension\RoutingExtension;
29
use Symfony\Bridge\Twig\Extension\TranslationExtension;
30
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
31
use Symfony\Component\Config\FileLocator;
32
use Symfony\Component\DependencyInjection\ContainerInterface;
33
use Symfony\Component\HttpFoundation\Request;
34
use Symfony\Component\Routing\Generator\UrlGenerator;
35
use Symfony\Component\Routing\Loader\XmlFileLoader;
36
use Symfony\Component\Routing\RequestContext;
37
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
38
use Symfony\Component\Translation\DependencyInjection\TranslationDumperPass;
39
use Symfony\Component\Translation\Loader\XliffFileLoader;
40
use Symfony\Component\Translation\MessageSelector;
41
use Symfony\Component\Translation\Translator;
42
use Symfony\Component\Translation\TranslatorInterface;
43
44
/**
45
 * Test for SonataAdminExtension.
46
 *
47
 * @author Andrej Hudec <[email protected]>
48
 */
49
class SonataAdminExtensionTest extends TestCase
50
{
51
    /**
52
     * @var SonataAdminExtension
53
     */
54
    private $twigExtension;
55
56
    /**
57
     * @var \Twig_Environment
58
     */
59
    private $environment;
60
61
    /**
62
     * @var AdminInterface
63
     */
64
    private $admin;
65
66
    /**
67
     * @var AdminInterface
68
     */
69
    private $adminBar;
70
71
    /**
72
     * @var FieldDescriptionInterface
73
     */
74
    private $fieldDescription;
75
76
    /**
77
     * @var \stdClass
78
     */
79
    private $object;
80
81
    /**
82
     * @var Pool
83
     */
84
    private $pool;
85
86
    /**
87
     * @var LoggerInterface
88
     */
89
    private $logger;
90
91
    /**
92
     * @var string[]
93
     */
94
    private $xEditableTypeMapping;
95
96
    /**
97
     * @var TranslatorInterface
98
     */
99
    private $translator;
100
101
    /**
102
     * @var ContainerInterface
103
     */
104
    private $container;
105
106
    /**
107
     * @var TemplateRegistryInterface
108
     */
109
    private $templateRegistry;
110
111
    /**
112
     * @var AuthorizationCheckerInterface
113
     */
114
    private $securityChecker;
115
116
    public function setUp(): void
117
    {
118
        date_default_timezone_set('Europe/London');
119
120
        $container = $this->getMockForAbstractClass(ContainerInterface::class);
121
122
        $this->pool = new Pool($container, '', '');
123
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
124
        $this->pool->setAdminClasses(['fooClass' => ['sonata_admin_foo_service']]);
125
126
        $this->logger = $this->getMockForAbstractClass(LoggerInterface::class);
127
        $this->xEditableTypeMapping = [
128
            'choice' => 'select',
129
            'boolean' => 'select',
130
            'text' => 'text',
131
            'textarea' => 'textarea',
132
            'html' => 'textarea',
133
            'email' => 'email',
134
            'string' => 'text',
135
            'smallint' => 'text',
136
            'bigint' => 'text',
137
            'integer' => 'number',
138
            'decimal' => 'number',
139
            'currency' => 'number',
140
            'percent' => 'number',
141
            'url' => 'url',
142
        ];
143
144
        // translation extension
145
        $translator = new Translator(
146
            'en',
147
            // NEXT_MAJOR: simplify this when dropping symfony < 3.4
148
            class_exists(TranslationDumperPass::class) ? null : new MessageSelector()
149
        );
150
        $translator->addLoader('xlf', new XliffFileLoader());
151
        $translator->addResource(
152
            'xlf',
153
            __DIR__.'/../../../src/Resources/translations/SonataAdminBundle.en.xliff',
154
            'en',
155
            'SonataAdminBundle'
156
        );
157
158
        $this->translator = $translator;
159
160
        $this->templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
161
        $this->container = $this->prophesize(ContainerInterface::class);
162
        $this->container->get('sonata_admin_foo_service.template_registry')->willReturn($this->templateRegistry->reveal());
163
164
        $this->securityChecker = $this->prophesize(AuthorizationCheckerInterface::class);
165
        $this->securityChecker->isGranted(['foo', 'bar'], null)->willReturn(false);
166
        $this->securityChecker->isGranted(Argument::type('string'), null)->willReturn(true);
167
168
        $this->twigExtension = new SonataAdminExtension(
169
            $this->pool, $this->logger, $this->translator, $this->container->reveal(), $this->securityChecker->reveal()
170
        );
171
        $this->twigExtension->setXEditableTypeMapping($this->xEditableTypeMapping);
172
173
        $request = $this->createMock(Request::class);
174
        $request->expects($this->any())->method('get')->with('_sonata_admin')->willReturn('sonata_admin_foo_service');
175
176
        $loader = new StubFilesystemLoader([
177
            __DIR__.'/../../../src/Resources/views/CRUD',
178
        ]);
179
        $loader->addPath(__DIR__.'/../../../src/Resources/views/', 'SonataAdmin');
180
181
        $this->environment = new \Twig_Environment($loader, [
182
            'strict_variables' => true,
183
            'cache' => false,
184
            'autoescape' => 'html',
185
            'optimizations' => 0,
186
        ]);
187
        $this->environment->addExtension($this->twigExtension);
188
        $this->environment->addExtension(new TranslationExtension($translator));
189
        $this->environment->addExtension(new FakeTemplateRegistryExtension());
190
191
        // routing extension
192
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../../src/Resources/config/routing']));
193
        $routeCollection = $xmlFileLoader->load('sonata_admin.xml');
194
195
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../Fixtures/Resources/config/routing']));
196
        $testRouteCollection = $xmlFileLoader->load('routing.xml');
197
198
        $routeCollection->addCollection($testRouteCollection);
199
        $requestContext = new RequestContext();
200
        $urlGenerator = new UrlGenerator($routeCollection, $requestContext);
201
        $this->environment->addExtension(new RoutingExtension($urlGenerator));
202
        $this->environment->addExtension(new \Twig_Extensions_Extension_Text());
203
204
        // initialize object
205
        $this->object = new \stdClass();
206
207
        // initialize admin
208
        $this->admin = $this->createMock(AbstractAdmin::class);
209
210
        $this->admin->expects($this->any())
211
            ->method('getCode')
212
            ->willReturn('sonata_admin_foo_service');
213
214
        $this->admin->expects($this->any())
215
            ->method('id')
216
            ->with($this->equalTo($this->object))
217
            ->willReturn(12345);
218
219
        $this->admin->expects($this->any())
220
            ->method('getNormalizedIdentifier')
221
            ->with($this->equalTo($this->object))
222
            ->willReturn(12345);
223
224
        $this->admin->expects($this->any())
225
            ->method('trans')
226
            ->willReturnCallback(static function ($id, $parameters = [], $domain = null) use ($translator) {
227
                return $translator->trans($id, $parameters, $domain);
228
            });
229
230
        $this->adminBar = $this->createMock(AbstractAdmin::class);
231
        $this->adminBar->expects($this->any())
232
            ->method('hasAccess')
233
            ->willReturn(true);
234
        $this->adminBar->expects($this->any())
235
            ->method('getNormalizedIdentifier')
236
            ->with($this->equalTo($this->object))
237
            ->willReturn(12345);
238
239
        $container->expects($this->any())
240
            ->method('get')
241
            ->willReturnCallback(function ($id) {
242
                if ('sonata_admin_foo_service' === $id) {
243
                    return $this->admin;
244
                } elseif ('sonata_admin_bar_service' === $id) {
245
                    return $this->adminBar;
246
                }
247
            });
248
249
        // initialize field description
250
        $this->fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
251
252
        $this->fieldDescription->expects($this->any())
253
            ->method('getName')
254
            ->willReturn('fd_name');
255
256
        $this->fieldDescription->expects($this->any())
257
            ->method('getAdmin')
258
            ->willReturn($this->admin);
259
260
        $this->fieldDescription->expects($this->any())
261
            ->method('getLabel')
262
            ->willReturn('Data');
263
    }
264
265
    /**
266
     * @group legacy
267
     * @expectedDeprecation The Sonata\AdminBundle\Admin\AbstractAdmin::getTemplate method is deprecated (since 3.34, will be dropped in 4.0. Use TemplateRegistry services instead).
268
     * @dataProvider getRenderListElementTests
269
     */
270
    public function testRenderListElement($expected, $type, $value, array $options): void
271
    {
272
        $this->admin->expects($this->any())
273
            ->method('getPersistentParameters')
274
            ->willReturn(['context' => 'foo']);
275
276
        $this->admin->expects($this->any())
277
            ->method('hasAccess')
278
            ->willReturn(true);
279
280
        // NEXT_MAJOR: Remove this line
281
        $this->admin->expects($this->any())
282
            ->method('getTemplate')
283
            ->with('base_list_field')
284
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
285
286
        $this->templateRegistry->getTemplate('base_list_field')->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
287
288
        $this->fieldDescription->expects($this->any())
289
            ->method('getValue')
290
            ->willReturn($value);
291
292
        $this->fieldDescription->expects($this->any())
293
            ->method('getType')
294
            ->willReturn($type);
295
296
        $this->fieldDescription->expects($this->any())
297
            ->method('getOptions')
298
            ->willReturn($options);
299
300
        $this->fieldDescription->expects($this->any())
301
            ->method('getOption')
302
            ->willReturnCallback(static function ($name, $default = null) use ($options) {
303
                return $options[$name] ?? $default;
304
            });
305
306
        $this->fieldDescription->expects($this->any())
307
            ->method('getTemplate')
308
            ->willReturnCallback(static function () use ($type) {
309
                switch ($type) {
310
                    case 'string':
311
                        return '@SonataAdmin/CRUD/list_string.html.twig';
312
                    case 'boolean':
313
                        return '@SonataAdmin/CRUD/list_boolean.html.twig';
314
                    case 'datetime':
315
                        return '@SonataAdmin/CRUD/list_datetime.html.twig';
316
                    case 'date':
317
                        return '@SonataAdmin/CRUD/list_date.html.twig';
318
                    case 'time':
319
                        return '@SonataAdmin/CRUD/list_time.html.twig';
320
                    case 'currency':
321
                        return '@SonataAdmin/CRUD/list_currency.html.twig';
322
                    case 'percent':
323
                        return '@SonataAdmin/CRUD/list_percent.html.twig';
324
                    case 'email':
325
                        return '@SonataAdmin/CRUD/list_email.html.twig';
326
                    case 'choice':
327
                        return '@SonataAdmin/CRUD/list_choice.html.twig';
328
                    case 'array':
329
                        return '@SonataAdmin/CRUD/list_array.html.twig';
330
                    case 'trans':
331
                        return '@SonataAdmin/CRUD/list_trans.html.twig';
332
                    case 'url':
333
                        return '@SonataAdmin/CRUD/list_url.html.twig';
334
                    case 'html':
335
                        return '@SonataAdmin/CRUD/list_html.html.twig';
336
                    case 'nonexistent':
337
                        // template doesn't exist
338
                        return '@SonataAdmin/CRUD/list_nonexistent_template.html.twig';
339
                    default:
340
                        return false;
341
                }
342
            });
343
344
        $this->assertSame(
345
            $this->removeExtraWhitespace($expected),
346
            $this->removeExtraWhitespace($this->twigExtension->renderListElement(
347
                $this->environment,
348
                $this->object,
349
                $this->fieldDescription
350
            ))
351
        );
352
    }
353
354
    public function getRenderListElementTests()
355
    {
356
        return [
357
            [
358
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> Example </td>',
359
                'string',
360
                'Example',
361
                [],
362
            ],
363
            [
364
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> </td>',
365
                'string',
366
                null,
367
                [],
368
            ],
369
            [
370
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> Example </td>',
371
                'text',
372
                'Example',
373
                [],
374
            ],
375
            [
376
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> </td>',
377
                'text',
378
                null,
379
                [],
380
            ],
381
            [
382
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> Example </td>',
383
                'textarea',
384
                'Example',
385
                [],
386
            ],
387
            [
388
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> </td>',
389
                'textarea',
390
                null,
391
                [],
392
            ],
393
            'datetime field' => [
394
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
395
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
396
                        December 24, 2013 10:11
397
                    </time>
398
                </td>',
399
                'datetime',
400
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
401
                [],
402
            ],
403
            [
404
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
405
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
406
                        December 24, 2013 18:11
407
                    </time>
408
                </td>',
409
                'datetime',
410
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
411
                ['timezone' => 'Asia/Hong_Kong'],
412
            ],
413
            [
414
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
415
                'datetime',
416
                null,
417
                [],
418
            ],
419
            [
420
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
421
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
422
                        24.12.2013 10:11:12
423
                    </time>
424
                </td>',
425
                'datetime',
426
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
427
                ['format' => 'd.m.Y H:i:s'],
428
            ],
429
            [
430
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
431
                'datetime',
432
                null,
433
                ['format' => 'd.m.Y H:i:s'],
434
            ],
435
            [
436
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
437
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
438
                        24.12.2013 18:11:12
439
                    </time>
440
                </td>',
441
                'datetime',
442
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
443
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
444
            ],
445
            [
446
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
447
                'datetime',
448
                null,
449
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
450
            ],
451
            [
452
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345">
453
                    <time datetime="2013-12-24" title="2013-12-24">
454
                        December 24, 2013
455
                    </time>
456
                </td>',
457
                'date',
458
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
459
                [],
460
            ],
461
            [
462
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
463
                'date',
464
                null,
465
                [],
466
            ],
467
            [
468
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345">
469
                    <time datetime="2013-12-24" title="2013-12-24">
470
                        24.12.2013
471
                    </time>
472
                </td>',
473
                'date',
474
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
475
                ['format' => 'd.m.Y'],
476
            ],
477
            [
478
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
479
                'date',
480
                null,
481
                ['format' => 'd.m.Y'],
482
            ],
483
            [
484
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345">
485
                    <time datetime="10:11:12+00:00" title="10:11:12+00:00">
486
                        10:11:12
487
                    </time>
488
                </td>',
489
                'time',
490
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
491
                [],
492
            ],
493
            [
494
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345">
495
                    <time datetime="10:11:12+00:00" title="10:11:12+00:00">
496
                        18:11:12
497
                    </time>
498
                </td>',
499
                'time',
500
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
501
                ['timezone' => 'Asia/Hong_Kong'],
502
            ],
503
            [
504
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> &nbsp; </td>',
505
                'time',
506
                null,
507
                [],
508
            ],
509
            [
510
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> 10.746135 </td>',
511
                'number', 10.746135,
512
                [],
513
            ],
514
            [
515
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> </td>',
516
                'number',
517
                null,
518
                [],
519
            ],
520
            [
521
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> 5678 </td>',
522
                'integer',
523
                5678,
524
                [],
525
            ],
526
            [
527
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> </td>',
528
                'integer',
529
                null,
530
                [],
531
            ],
532
            [
533
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 1074.6135 % </td>',
534
                'percent',
535
                10.746135,
536
                [],
537
            ],
538
            [
539
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 0 % </td>',
540
                'percent',
541
                null,
542
                [],
543
            ],
544
            [
545
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> EUR 10.746135 </td>',
546
                'currency',
547
                10.746135,
548
                ['currency' => 'EUR'],
549
            ],
550
            [
551
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
552
                'currency',
553
                null,
554
                ['currency' => 'EUR'],
555
            ],
556
            [
557
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> GBP 51.23456 </td>',
558
                'currency',
559
                51.23456,
560
                ['currency' => 'GBP'],
561
            ],
562
            [
563
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
564
                'currency',
565
                null,
566
                ['currency' => 'GBP'],
567
            ],
568
            [
569
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> &nbsp; </td>',
570
                'email',
571
                null,
572
                [],
573
            ],
574
            [
575
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> <a href="mailto:[email protected]">[email protected]</a> </td>',
576
                'email',
577
                '[email protected]',
578
                [],
579
            ],
580
            [
581
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
582
                    <a href="mailto:[email protected]">[email protected]</a> </td>',
583
                'email',
584
                '[email protected]',
585
                ['as_string' => false],
586
            ],
587
            [
588
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
589
                'email',
590
                '[email protected]',
591
                ['as_string' => true],
592
            ],
593
            [
594
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
595
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a>  </td>',
596
                'email',
597
                '[email protected]',
598
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
599
            ],
600
            [
601
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
602
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a>  </td>',
603
                'email',
604
                '[email protected]',
605
                ['subject' => 'Main Theme'],
606
            ],
607
            [
608
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
609
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a>  </td>',
610
                'email',
611
                '[email protected]',
612
                ['body' => 'Message Body'],
613
            ],
614
            [
615
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
616
                'email',
617
                '[email protected]',
618
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
619
            ],
620
            [
621
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
622
                'email',
623
                '[email protected]',
624
                ['as_string' => true, 'body' => 'Message Body'],
625
            ],
626
            [
627
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
628
                'email',
629
                '[email protected]',
630
                ['as_string' => true, 'subject' => 'Main Theme'],
631
            ],
632
            [
633
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345">
634
                    [1 => First] [2 => Second]
635
                </td>',
636
                'array',
637
                [1 => 'First', 2 => 'Second'],
638
                [],
639
            ],
640
            [
641
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345"> </td>',
642
                'array',
643
                null,
644
                [],
645
            ],
646
            [
647
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
648
                    <span class="label label-success">yes</span>
649
                </td>',
650
                'boolean',
651
                true,
652
                ['editable' => false],
653
            ],
654
            [
655
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
656
                    <span class="label label-danger">no</span>
657
                </td>',
658
                'boolean',
659
                false,
660
                ['editable' => false],
661
            ],
662
            [
663
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
664
                    <span class="label label-danger">no</span>
665
                </td>',
666
                'boolean',
667
                null,
668
                ['editable' => false],
669
            ],
670
            [
671
                <<<'EOT'
672
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
673
    <span
674
        class="x-editable"
675
        data-type="select"
676
        data-value="1"
677
        data-title="Data"
678
        data-pk="12345"
679
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
680
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
681
    >
682
        <span class="label label-success">yes</span>
683
    </span>
684
</td>
685
EOT
686
            ,
687
                'boolean',
688
                true,
689
                ['editable' => true],
690
            ],
691
            [
692
                <<<'EOT'
693
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
694
    <span
695
        class="x-editable"
696
        data-type="select"
697
        data-value="0"
698
        data-title="Data"
699
        data-pk="12345"
700
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
701
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
702
    >
703
    <span class="label label-danger">no</span> </span>
704
</td>
705
EOT
706
                ,
707
                'boolean',
708
                false,
709
                ['editable' => true],
710
            ],
711
            [
712
                <<<'EOT'
713
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
714
    <span
715
        class="x-editable"
716
        data-type="select"
717
        data-value="0"
718
        data-title="Data"
719
        data-pk="12345"
720
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
721
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]" >
722
        <span class="label label-danger">no</span> </span>
723
</td>
724
EOT
725
                ,
726
                'boolean',
727
                null,
728
                ['editable' => true],
729
            ],
730
            [
731
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
732
                'trans',
733
                'action_delete',
734
                ['catalogue' => 'SonataAdminBundle'],
735
            ],
736
            [
737
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> </td>',
738
                'trans',
739
                null,
740
                ['catalogue' => 'SonataAdminBundle'],
741
            ],
742
            [
743
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
744
                'trans',
745
                'action_delete',
746
                ['format' => '%s', 'catalogue' => 'SonataAdminBundle'],
747
            ],
748
            [
749
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
750
                action.action_delete
751
                </td>',
752
                'trans',
753
                'action_delete',
754
                ['format' => 'action.%s'],
755
            ],
756
            [
757
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
758
                action.action_delete
759
                </td>',
760
                'trans',
761
                'action_delete',
762
                ['format' => 'action.%s', 'catalogue' => 'SonataAdminBundle'],
763
            ],
764
            [
765
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
766
                'choice',
767
                'Status1',
768
                [],
769
            ],
770
            [
771
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
772
                'choice',
773
                ['Status1'],
774
                ['choices' => [], 'multiple' => true],
775
            ],
776
            [
777
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 </td>',
778
                'choice',
779
                'Status1',
780
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
781
            ],
782
            [
783
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
784
                'choice',
785
                null,
786
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
787
            ],
788
            [
789
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
790
                NoValidKeyInChoices
791
                </td>',
792
                'choice',
793
                'NoValidKeyInChoices',
794
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
795
            ],
796
            [
797
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete </td>',
798
                'choice',
799
                'Foo',
800
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
801
                    'Foo' => 'action_delete',
802
                    'Status2' => 'Alias2',
803
                    'Status3' => 'Alias3',
804
                ]],
805
            ],
806
            [
807
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1, Alias3 </td>',
808
                'choice',
809
                ['Status1', 'Status3'],
810
                ['choices' => [
811
                    'Status1' => 'Alias1',
812
                    'Status2' => 'Alias2',
813
                    'Status3' => 'Alias3',
814
                ], 'multiple' => true], ],
815
            [
816
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 | Alias3 </td>',
817
                'choice',
818
                ['Status1', 'Status3'],
819
                ['choices' => [
820
                    'Status1' => 'Alias1',
821
                    'Status2' => 'Alias2',
822
                    'Status3' => 'Alias3',
823
                ], 'multiple' => true, 'delimiter' => ' | '], ],
824
            [
825
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
826
                'choice',
827
                null,
828
                ['choices' => [
829
                    'Status1' => 'Alias1',
830
                    'Status2' => 'Alias2',
831
                    'Status3' => 'Alias3',
832
                ], 'multiple' => true],
833
            ],
834
            [
835
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
836
                NoValidKeyInChoices
837
                </td>',
838
                'choice',
839
                ['NoValidKeyInChoices'],
840
                ['choices' => [
841
                    'Status1' => 'Alias1',
842
                    'Status2' => 'Alias2',
843
                    'Status3' => 'Alias3',
844
                ], 'multiple' => true],
845
            ],
846
            [
847
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
848
                NoValidKeyInChoices, Alias2
849
                </td>',
850
                'choice',
851
                ['NoValidKeyInChoices', 'Status2'],
852
                ['choices' => [
853
                    'Status1' => 'Alias1',
854
                    'Status2' => 'Alias2',
855
                    'Status3' => 'Alias3',
856
                ], 'multiple' => true],
857
            ],
858
            [
859
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete, Alias3 </td>',
860
                'choice',
861
                ['Foo', 'Status3'],
862
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
863
                    'Foo' => 'action_delete',
864
                    'Status2' => 'Alias2',
865
                    'Status3' => 'Alias3',
866
                ], 'multiple' => true],
867
            ],
868
            [
869
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
870
                &lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;
871
            </td>',
872
                'choice',
873
                ['Status1', 'Status3'],
874
                ['choices' => [
875
                    'Status1' => '<b>Alias1</b>',
876
                    'Status2' => '<b>Alias2</b>',
877
                    'Status3' => '<b>Alias3</b>',
878
                ], 'multiple' => true], ],
879
            [
880
                <<<'EOT'
881
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
882
    <span
883
        class="x-editable"
884
        data-type="select"
885
        data-value="Status1"
886
        data-title="Data"
887
        data-pk="12345"
888
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
889
        data-source="[]"
890
    >
891
        Status1
892
    </span>
893
</td>
894
EOT
895
                ,
896
                'choice',
897
                'Status1',
898
                ['editable' => true],
899
            ],
900
            [
901
                <<<'EOT'
902
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
903
    <span
904
        class="x-editable"
905
        data-type="select"
906
        data-value="Status1"
907
        data-title="Data"
908
        data-pk="12345"
909
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
910
        data-source="[{&quot;value&quot;:&quot;Status1&quot;,&quot;text&quot;:&quot;Alias1&quot;},{&quot;value&quot;:&quot;Status2&quot;,&quot;text&quot;:&quot;Alias2&quot;},{&quot;value&quot;:&quot;Status3&quot;,&quot;text&quot;:&quot;Alias3&quot;}]" >
911
        Alias1 </span>
912
</td>
913
EOT
914
                ,
915
                'choice',
916
                'Status1',
917
                [
918
                    'editable' => true,
919
                    'choices' => [
920
                        'Status1' => 'Alias1',
921
                        'Status2' => 'Alias2',
922
                        'Status3' => 'Alias3',
923
                    ],
924
                ],
925
            ],
926
            [
927
                <<<'EOT'
928
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
929
    <span
930
        class="x-editable"
931
        data-type="select"
932
        data-value=""
933
        data-title="Data"
934
        data-pk="12345"
935
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
936
        data-source="[{&quot;value&quot;:&quot;Status1&quot;,&quot;text&quot;:&quot;Alias1&quot;},{&quot;value&quot;:&quot;Status2&quot;,&quot;text&quot;:&quot;Alias2&quot;},{&quot;value&quot;:&quot;Status3&quot;,&quot;text&quot;:&quot;Alias3&quot;}]" >
937
938
    </span>
939
</td>
940
EOT
941
                ,
942
                'choice',
943
                null,
944
                [
945
                    'editable' => true,
946
                    'choices' => [
947
                        'Status1' => 'Alias1',
948
                        'Status2' => 'Alias2',
949
                        'Status3' => 'Alias3',
950
                    ],
951
                ],
952
            ],
953
            [
954
                <<<'EOT'
955
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
956
    <span
957
        class="x-editable"
958
        data-type="select"
959
        data-value="NoValidKeyInChoices"
960
        data-title="Data" data-pk="12345"
961
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
962
        data-source="[{&quot;value&quot;:&quot;Status1&quot;,&quot;text&quot;:&quot;Alias1&quot;},{&quot;value&quot;:&quot;Status2&quot;,&quot;text&quot;:&quot;Alias2&quot;},{&quot;value&quot;:&quot;Status3&quot;,&quot;text&quot;:&quot;Alias3&quot;}]" >
963
        NoValidKeyInChoices
964
    </span>
965
</td>
966
EOT
967
                ,
968
                'choice',
969
                'NoValidKeyInChoices',
970
                [
971
                    'editable' => true,
972
                    'choices' => [
973
                        'Status1' => 'Alias1',
974
                        'Status2' => 'Alias2',
975
                        'Status3' => 'Alias3',
976
                    ],
977
                ],
978
            ],
979
            [
980
                <<<'EOT'
981
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
982
    <span
983
        class="x-editable"
984
        data-type="select"
985
        data-value="Foo"
986
        data-title="Data"
987
        data-pk="12345"
988
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
989
        data-source="[{&quot;value&quot;:&quot;Foo&quot;,&quot;text&quot;:&quot;Delete&quot;},{&quot;value&quot;:&quot;Status2&quot;,&quot;text&quot;:&quot;Alias2&quot;},{&quot;value&quot;:&quot;Status3&quot;,&quot;text&quot;:&quot;Alias3&quot;}]" >
990
         Delete
991
    </span>
992
</td>
993
EOT
994
                ,
995
                'choice',
996
                'Foo',
997
                [
998
                    'editable' => true,
999
                    'catalogue' => 'SonataAdminBundle',
1000
                    'choices' => [
1001
                        'Foo' => 'action_delete',
1002
                        'Status2' => 'Alias2',
1003
                        'Status3' => 'Alias3',
1004
                    ],
1005
                ],
1006
            ],
1007
            [
1008
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1009
                'url',
1010
                null,
1011
                [],
1012
            ],
1013
            [
1014
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1015
                'url',
1016
                null,
1017
                ['url' => 'http://example.com'],
1018
            ],
1019
            [
1020
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1021
                'url',
1022
                null,
1023
                ['route' => ['name' => 'sonata_admin_foo']],
1024
            ],
1025
            [
1026
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1027
                <a href="http://example.com">http://example.com</a>
1028
                </td>',
1029
                'url',
1030
                'http://example.com',
1031
                [],
1032
            ],
1033
            [
1034
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1035
                <a href="https://example.com">https://example.com</a>
1036
                </td>',
1037
                'url',
1038
                'https://example.com',
1039
                [],
1040
            ],
1041
            [
1042
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1043
                <a href="https://example.com" target="_blank">https://example.com</a>
1044
                </td>',
1045
                'url',
1046
                'https://example.com',
1047
                ['attributes' => ['target' => '_blank']],
1048
            ],
1049
            [
1050
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1051
                <a href="https://example.com" target="_blank" class="fooLink">https://example.com</a>
1052
                </td>',
1053
                'url',
1054
                'https://example.com',
1055
                ['attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1056
            ],
1057
            [
1058
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1059
                <a href="http://example.com">example.com</a>
1060
                </td>',
1061
                'url',
1062
                'http://example.com',
1063
                ['hide_protocol' => true],
1064
            ],
1065
            [
1066
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1067
                <a href="https://example.com">example.com</a>
1068
                </td>',
1069
                'url',
1070
                'https://example.com',
1071
                ['hide_protocol' => true],
1072
            ],
1073
            [
1074
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1075
                <a href="http://example.com">http://example.com</a>
1076
                </td>',
1077
                'url',
1078
                'http://example.com',
1079
                ['hide_protocol' => false],
1080
            ],
1081
            [
1082
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1083
                <a href="https://example.com">https://example.com</a>
1084
                </td>',
1085
                'url',
1086
                'https://example.com',
1087
                ['hide_protocol' => false],
1088
            ],
1089
            [
1090
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1091
                <a href="http://example.com">Foo</a>
1092
                </td>',
1093
                'url',
1094
                'Foo',
1095
                ['url' => 'http://example.com'],
1096
            ],
1097
            [
1098
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1099
                <a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a>
1100
                </td>',
1101
                'url',
1102
                '<b>Foo</b>',
1103
                ['url' => 'http://example.com'],
1104
            ],
1105
            [
1106
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1107
                <a href="/foo">Foo</a>
1108
                </td>',
1109
                'url',
1110
                'Foo',
1111
                ['route' => ['name' => 'sonata_admin_foo']],
1112
            ],
1113
            [
1114
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1115
                <a href="http://localhost/foo">Foo</a>
1116
                </td>',
1117
                'url',
1118
                'Foo',
1119
                ['route' => ['name' => 'sonata_admin_foo', 'absolute' => true]],
1120
            ],
1121
            [
1122
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1123
                <a href="/foo">foo/bar?a=b&amp;c=123456789</a>
1124
                </td>',
1125
                'url',
1126
                'http://foo/bar?a=b&c=123456789',
1127
                ['route' => ['name' => 'sonata_admin_foo'],
1128
                'hide_protocol' => true, ],
1129
            ],
1130
            [
1131
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1132
                <a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a>
1133
                </td>',
1134
                'url',
1135
                'http://foo/bar?a=b&c=123456789',
1136
                [
1137
                    'route' => ['name' => 'sonata_admin_foo', 'absolute' => true],
1138
                    'hide_protocol' => true,
1139
                ],
1140
            ],
1141
            [
1142
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1143
                <a href="/foo/abcd/efgh?param3=ijkl">Foo</a>
1144
                </td>',
1145
                'url',
1146
                'Foo',
1147
                [
1148
                    'route' => ['name' => 'sonata_admin_foo_param',
1149
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1150
                ],
1151
            ],
1152
            [
1153
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1154
                <a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a>
1155
                </td>',
1156
                'url',
1157
                'Foo',
1158
                [
1159
                    'route' => ['name' => 'sonata_admin_foo_param',
1160
                    'absolute' => true,
1161
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1162
                ],
1163
            ],
1164
            [
1165
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1166
                <a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1167
                </td>',
1168
                'url',
1169
                'Foo',
1170
                [
1171
                    'route' => ['name' => 'sonata_admin_foo_object',
1172
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1173
                    'identifier_parameter_name' => 'barId', ],
1174
                ],
1175
            ],
1176
            [
1177
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1178
                <a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1179
                </td>',
1180
                'url',
1181
                'Foo',
1182
                [
1183
                    'route' => ['name' => 'sonata_admin_foo_object',
1184
                    'absolute' => true,
1185
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1186
                    'identifier_parameter_name' => 'barId', ],
1187
                ],
1188
            ],
1189
            [
1190
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1191
                <p><strong>Creating a Template for the Field</strong> and form</p>
1192
                </td>',
1193
                'html',
1194
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1195
                [],
1196
            ],
1197
            [
1198
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1199
                Creating a Template for the Field and form
1200
                </td>',
1201
                'html',
1202
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1203
                ['strip' => true],
1204
            ],
1205
            [
1206
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1207
                Creating a Template for the Fi...
1208
                </td>',
1209
                'html',
1210
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1211
                ['truncate' => true],
1212
            ],
1213
            [
1214
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345"> Creating a... </td>',
1215
                'html',
1216
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1217
                ['truncate' => ['length' => 10]],
1218
            ],
1219
            [
1220
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1221
                Creating a Template for the Field...
1222
                </td>',
1223
                'html',
1224
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1225
                ['truncate' => ['preserve' => true]],
1226
            ],
1227
            [
1228
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1229
                Creating a Template for the Fi etc.
1230
                </td>',
1231
                'html',
1232
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1233
                ['truncate' => ['separator' => ' etc.']],
1234
            ],
1235
            [
1236
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1237
                Creating a Template for[...]
1238
                </td>',
1239
                'html',
1240
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1241
                [
1242
                    'truncate' => [
1243
                        'length' => 20,
1244
                        'preserve' => true,
1245
                        'separator' => '[...]',
1246
                    ],
1247
                ],
1248
            ],
1249
1250
            [
1251
                <<<'EOT'
1252
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1253
<div
1254
    class="sonata-readmore"
1255
    data-readmore-height="40"
1256
    data-readmore-more="Read more"
1257
    data-readmore-less="Close">A very long string</div>
1258
</td>
1259
EOT
1260
                ,
1261
                'text',
1262
                'A very long string',
1263
                [
1264
                    'collapse' => true,
1265
                ],
1266
            ],
1267
            [
1268
                <<<'EOT'
1269
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1270
<div
1271
    class="sonata-readmore"
1272
    data-readmore-height="10"
1273
    data-readmore-more="More"
1274
    data-readmore-less="Less">A very long string</div>
1275
</td>
1276
EOT
1277
                ,
1278
                'text',
1279
                'A very long string',
1280
                [
1281
                    'collapse' => [
1282
                        'height' => 10,
1283
                        'more' => 'More',
1284
                        'less' => 'Less',
1285
                    ],
1286
                ],
1287
            ],
1288
        ];
1289
    }
1290
1291
    /**
1292
     * @dataProvider getRenderViewElementTests
1293
     */
1294
    public function testRenderViewElement($expected, $type, $value, array $options): void
1295
    {
1296
        $this->admin->expects($this->any())
1297
            ->method('getTemplate')
1298
            ->willReturn('@SonataAdmin/CRUD/base_show_field.html.twig');
1299
1300
        $this->fieldDescription->expects($this->any())
1301
            ->method('getValue')
1302
            ->willReturnCallback(static function () use ($value) {
1303
                if ($value instanceof NoValueException) {
1304
                    throw  $value;
1305
                }
1306
1307
                return $value;
1308
            });
1309
1310
        $this->fieldDescription->expects($this->any())
1311
            ->method('getType')
1312
            ->willReturn($type);
1313
1314
        $this->fieldDescription->expects($this->any())
1315
            ->method('getOptions')
1316
            ->willReturn($options);
1317
1318
        $this->fieldDescription->expects($this->any())
1319
            ->method('getTemplate')
1320
            ->willReturnCallback(static function () use ($type) {
1321
                switch ($type) {
1322
                    case 'boolean':
1323
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
1324
                    case 'datetime':
1325
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
1326
                    case 'date':
1327
                        return '@SonataAdmin/CRUD/show_date.html.twig';
1328
                    case 'time':
1329
                        return '@SonataAdmin/CRUD/show_time.html.twig';
1330
                    case 'currency':
1331
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
1332
                    case 'percent':
1333
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
1334
                    case 'email':
1335
                        return '@SonataAdmin/CRUD/show_email.html.twig';
1336
                    case 'choice':
1337
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
1338
                    case 'array':
1339
                        return '@SonataAdmin/CRUD/show_array.html.twig';
1340
                    case 'trans':
1341
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
1342
                    case 'url':
1343
                        return '@SonataAdmin/CRUD/show_url.html.twig';
1344
                    case 'html':
1345
                        return '@SonataAdmin/CRUD/show_html.html.twig';
1346
                    default:
1347
                        return false;
1348
                }
1349
            });
1350
1351
        $this->assertSame(
1352
                $this->removeExtraWhitespace($expected),
1353
                $this->removeExtraWhitespace(
1354
                    $this->twigExtension->renderViewElement(
1355
                        $this->environment,
1356
                        $this->fieldDescription,
1357
                        $this->object
1358
                    )
1359
                )
1360
            );
1361
    }
1362
1363
    public function getRenderViewElementTests()
1364
    {
1365
        return [
1366
            ['<th>Data</th> <td>Example</td>', 'string', 'Example', ['safe' => false]],
1367
            ['<th>Data</th> <td>Example</td>', 'text', 'Example', ['safe' => false]],
1368
            ['<th>Data</th> <td>Example</td>', 'textarea', 'Example', ['safe' => false]],
1369
            [
1370
                '<th>Data</th> <td><time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00"> December 24, 2013 10:11 </time></td>',
1371
                'datetime',
1372
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), [],
1373
            ],
1374
            [
1375
                '<th>Data</th> <td><time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00"> 24.12.2013 10:11:12 </time></td>',
1376
                'datetime',
1377
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1378
                ['format' => 'd.m.Y H:i:s'],
1379
            ],
1380
            [
1381
                '<th>Data</th> <td><time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00"> December 24, 2013 18:11 </time></td>',
1382
                'datetime',
1383
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1384
                ['timezone' => 'Asia/Hong_Kong'],
1385
            ],
1386
            [
1387
                '<th>Data</th> <td><time datetime="2013-12-24" title="2013-12-24"> December 24, 2013 </time></td>',
1388
                'date',
1389
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1390
                [],
1391
            ],
1392
            [
1393
                '<th>Data</th> <td><time datetime="2013-12-24" title="2013-12-24"> 24.12.2013 </time></td>',
1394
                'date',
1395
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1396
                ['format' => 'd.m.Y'],
1397
            ],
1398
            [
1399
                '<th>Data</th> <td><time datetime="10:11:12+00:00" title="10:11:12+00:00"> 10:11:12 </time></td>',
1400
                'time',
1401
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1402
                [],
1403
            ],
1404
            [
1405
                '<th>Data</th> <td><time datetime="10:11:12+00:00" title="10:11:12+00:00"> 18:11:12 </time></td>',
1406
                'time',
1407
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1408
                ['timezone' => 'Asia/Hong_Kong'],
1409
            ],
1410
            ['<th>Data</th> <td>10.746135</td>', 'number', 10.746135, ['safe' => false]],
1411
            ['<th>Data</th> <td>5678</td>', 'integer', 5678, ['safe' => false]],
1412
            ['<th>Data</th> <td> 1074.6135 % </td>', 'percent', 10.746135, []],
1413
            ['<th>Data</th> <td> EUR 10.746135 </td>', 'currency', 10.746135, ['currency' => 'EUR']],
1414
            ['<th>Data</th> <td> GBP 51.23456 </td>', 'currency', 51.23456, ['currency' => 'GBP']],
1415
            [
1416
                '<th>Data</th> <td> [1 => First] <br> [2 => Second] </td>',
1417
                'array',
1418
                [1 => 'First', 2 => 'Second'],
1419
                ['safe' => false],
1420
            ],
1421
            [
1422
                '<th>Data</th> <td> [1 => First] [2 => Second] </td>',
1423
                'array',
1424
                [1 => 'First', 2 => 'Second'],
1425
                ['safe' => false, 'inline' => true],
1426
            ],
1427
            [
1428
                '<th>Data</th> <td><span class="label label-success">yes</span></td>',
1429
                'boolean',
1430
                true,
1431
                [],
1432
            ],
1433
            [
1434
                '<th>Data</th> <td><span class="label label-danger">yes</span></td>',
1435
                'boolean',
1436
                true,
1437
                ['inverse' => true],
1438
            ],
1439
            ['<th>Data</th> <td><span class="label label-danger">no</span></td>', 'boolean', false, []],
1440
            [
1441
                '<th>Data</th> <td><span class="label label-success">no</span></td>',
1442
                'boolean',
1443
                false,
1444
                ['inverse' => true],
1445
            ],
1446
            [
1447
                '<th>Data</th> <td> Delete </td>',
1448
                'trans',
1449
                'action_delete',
1450
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1451
            ],
1452
            ['<th>Data</th> <td>Status1</td>', 'choice', 'Status1', ['safe' => false]],
1453
            [
1454
                '<th>Data</th> <td>Alias1</td>',
1455
                'choice',
1456
                'Status1',
1457
                ['safe' => false, 'choices' => [
1458
                    'Status1' => 'Alias1',
1459
                    'Status2' => 'Alias2',
1460
                    'Status3' => 'Alias3',
1461
                ]],
1462
            ],
1463
            [
1464
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1465
                'choice',
1466
                'NoValidKeyInChoices',
1467
                ['safe' => false, 'choices' => [
1468
                    'Status1' => 'Alias1',
1469
                    'Status2' => 'Alias2',
1470
                    'Status3' => 'Alias3',
1471
                ]],
1472
            ],
1473
            [
1474
                '<th>Data</th> <td>Delete</td>',
1475
                'choice',
1476
                'Foo',
1477
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1478
                    'Foo' => 'action_delete',
1479
                    'Status2' => 'Alias2',
1480
                    'Status3' => 'Alias3',
1481
                ]],
1482
            ],
1483
            [
1484
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1485
                'choice',
1486
                ['NoValidKeyInChoices'],
1487
                ['safe' => false, 'choices' => [
1488
                    'Status1' => 'Alias1',
1489
                    'Status2' => 'Alias2',
1490
                    'Status3' => 'Alias3',
1491
                ], 'multiple' => true],
1492
            ],
1493
            [
1494
                '<th>Data</th> <td>NoValidKeyInChoices, Alias2</td>',
1495
                'choice',
1496
                ['NoValidKeyInChoices', 'Status2'],
1497
                ['safe' => false, 'choices' => [
1498
                    'Status1' => 'Alias1',
1499
                    'Status2' => 'Alias2',
1500
                    'Status3' => 'Alias3',
1501
                ], 'multiple' => true],
1502
            ],
1503
            [
1504
                '<th>Data</th> <td>Alias1, Alias3</td>',
1505
                'choice',
1506
                ['Status1', 'Status3'],
1507
                ['safe' => false, 'choices' => [
1508
                    'Status1' => 'Alias1',
1509
                    'Status2' => 'Alias2',
1510
                    'Status3' => 'Alias3',
1511
                ], 'multiple' => true],
1512
            ],
1513
            [
1514
                '<th>Data</th> <td>Alias1 | Alias3</td>',
1515
                'choice',
1516
                ['Status1', 'Status3'], ['safe' => false, 'choices' => [
1517
                    'Status1' => 'Alias1',
1518
                    'Status2' => 'Alias2',
1519
                    'Status3' => 'Alias3',
1520
                ], 'multiple' => true, 'delimiter' => ' | '],
1521
            ],
1522
            [
1523
                '<th>Data</th> <td>Delete, Alias3</td>',
1524
                'choice',
1525
                ['Foo', 'Status3'],
1526
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1527
                    'Foo' => 'action_delete',
1528
                    'Status2' => 'Alias2',
1529
                    'Status3' => 'Alias3',
1530
                ], 'multiple' => true],
1531
            ],
1532
            [
1533
                '<th>Data</th> <td><b>Alias1</b>, <b>Alias3</b></td>',
1534
                'choice',
1535
                ['Status1', 'Status3'],
1536
                ['safe' => true, 'choices' => [
1537
                    'Status1' => '<b>Alias1</b>',
1538
                    'Status2' => '<b>Alias2</b>',
1539
                    'Status3' => '<b>Alias3</b>',
1540
                ], 'multiple' => true],
1541
            ],
1542
            [
1543
                '<th>Data</th> <td>&lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;</td>',
1544
                'choice',
1545
                ['Status1', 'Status3'],
1546
                ['safe' => false, 'choices' => [
1547
                    'Status1' => '<b>Alias1</b>',
1548
                    'Status2' => '<b>Alias2</b>',
1549
                    'Status3' => '<b>Alias3</b>',
1550
                ], 'multiple' => true],
1551
            ],
1552
            [
1553
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1554
                'url',
1555
                'http://example.com',
1556
                ['safe' => false],
1557
            ],
1558
            [
1559
                '<th>Data</th> <td><a href="http://example.com" target="_blank">http://example.com</a></td>',
1560
                'url',
1561
                'http://example.com',
1562
                ['safe' => false, 'attributes' => ['target' => '_blank']],
1563
            ],
1564
            [
1565
                '<th>Data</th> <td><a href="http://example.com" target="_blank" class="fooLink">http://example.com</a></td>',
1566
                'url',
1567
                'http://example.com',
1568
                ['safe' => false, 'attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1569
            ],
1570
            [
1571
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1572
                'url',
1573
                'https://example.com',
1574
                ['safe' => false],
1575
            ],
1576
            [
1577
                '<th>Data</th> <td><a href="http://example.com">example.com</a></td>',
1578
                'url',
1579
                'http://example.com',
1580
                ['safe' => false, 'hide_protocol' => true],
1581
            ],
1582
            [
1583
                '<th>Data</th> <td><a href="https://example.com">example.com</a></td>',
1584
                'url',
1585
                'https://example.com',
1586
                ['safe' => false, 'hide_protocol' => true],
1587
            ],
1588
            [
1589
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1590
                'url',
1591
                'http://example.com',
1592
                ['safe' => false, 'hide_protocol' => false],
1593
            ],
1594
            [
1595
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1596
                'url',
1597
                'https://example.com',
1598
                ['safe' => false,
1599
                'hide_protocol' => false, ],
1600
            ],
1601
            [
1602
                '<th>Data</th> <td><a href="http://example.com">Foo</a></td>',
1603
                'url',
1604
                'Foo',
1605
                ['safe' => false, 'url' => 'http://example.com'],
1606
            ],
1607
            [
1608
                '<th>Data</th> <td><a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a></td>',
1609
                'url',
1610
                '<b>Foo</b>',
1611
                ['safe' => false, 'url' => 'http://example.com'],
1612
            ],
1613
            [
1614
                '<th>Data</th> <td><a href="http://example.com"><b>Foo</b></a></td>',
1615
                'url',
1616
                '<b>Foo</b>',
1617
                ['safe' => true, 'url' => 'http://example.com'],
1618
            ],
1619
            [
1620
                '<th>Data</th> <td><a href="/foo">Foo</a></td>',
1621
                'url',
1622
                'Foo',
1623
                ['safe' => false, 'route' => ['name' => 'sonata_admin_foo']],
1624
            ],
1625
            [
1626
                '<th>Data</th> <td><a href="http://localhost/foo">Foo</a></td>',
1627
                'url',
1628
                'Foo',
1629
                ['safe' => false, 'route' => [
1630
                    'name' => 'sonata_admin_foo',
1631
                    'absolute' => true,
1632
                ]],
1633
            ],
1634
            [
1635
                '<th>Data</th> <td><a href="/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1636
                'url',
1637
                'http://foo/bar?a=b&c=123456789',
1638
                [
1639
                    'safe' => false,
1640
                    'route' => ['name' => 'sonata_admin_foo'],
1641
                    'hide_protocol' => true,
1642
                ],
1643
            ],
1644
            [
1645
                '<th>Data</th> <td><a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1646
                'url',
1647
                'http://foo/bar?a=b&c=123456789',
1648
                ['safe' => false, 'route' => [
1649
                    'name' => 'sonata_admin_foo',
1650
                    'absolute' => true,
1651
                ], 'hide_protocol' => true],
1652
            ],
1653
            [
1654
                '<th>Data</th> <td><a href="/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1655
                'url',
1656
                'Foo',
1657
                ['safe' => false, 'route' => [
1658
                    'name' => 'sonata_admin_foo_param',
1659
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1660
                ]],
1661
            ],
1662
            [
1663
                '<th>Data</th> <td><a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1664
                'url',
1665
                'Foo',
1666
                ['safe' => false, 'route' => [
1667
                    'name' => 'sonata_admin_foo_param',
1668
                    'absolute' => true,
1669
                    'parameters' => [
1670
                        'param1' => 'abcd',
1671
                        'param2' => 'efgh',
1672
                        'param3' => 'ijkl',
1673
                    ],
1674
                ]],
1675
            ],
1676
            [
1677
                '<th>Data</th> <td><a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1678
                'url',
1679
                'Foo',
1680
                ['safe' => false, 'route' => [
1681
                    'name' => 'sonata_admin_foo_object',
1682
                    'parameters' => [
1683
                        'param1' => 'abcd',
1684
                        'param2' => 'efgh',
1685
                        'param3' => 'ijkl',
1686
                    ],
1687
                    'identifier_parameter_name' => 'barId',
1688
                ]],
1689
            ],
1690
            [
1691
                '<th>Data</th> <td><a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1692
                'url',
1693
                'Foo',
1694
                ['safe' => false, 'route' => [
1695
                    'name' => 'sonata_admin_foo_object',
1696
                    'absolute' => true,
1697
                    'parameters' => [
1698
                        'param1' => 'abcd',
1699
                        'param2' => 'efgh',
1700
                        'param3' => 'ijkl',
1701
                    ],
1702
                    'identifier_parameter_name' => 'barId',
1703
                ]],
1704
            ],
1705
            [
1706
                '<th>Data</th> <td> &nbsp;</td>',
1707
                'email',
1708
                null,
1709
                [],
1710
            ],
1711
            [
1712
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1713
                'email',
1714
                '[email protected]',
1715
                [],
1716
            ],
1717
            [
1718
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a></td>',
1719
                'email',
1720
                '[email protected]',
1721
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
1722
            ],
1723
            [
1724
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a></td>',
1725
                'email',
1726
                '[email protected]',
1727
                ['subject' => 'Main Theme'],
1728
            ],
1729
            [
1730
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a></td>',
1731
                'email',
1732
                '[email protected]',
1733
                ['body' => 'Message Body'],
1734
            ],
1735
            [
1736
                '<th>Data</th> <td> [email protected]</td>',
1737
                'email',
1738
                '[email protected]',
1739
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
1740
            ],
1741
            [
1742
                '<th>Data</th> <td> [email protected]</td>',
1743
                'email',
1744
                '[email protected]',
1745
                ['as_string' => true, 'subject' => 'Main Theme'],
1746
            ],
1747
            [
1748
                '<th>Data</th> <td> [email protected]</td>',
1749
                'email',
1750
                '[email protected]',
1751
                ['as_string' => true, 'body' => 'Message Body'],
1752
            ],
1753
            [
1754
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1755
                'email',
1756
                '[email protected]',
1757
                ['as_string' => false],
1758
            ],
1759
            [
1760
                '<th>Data</th> <td> [email protected]</td>',
1761
                'email',
1762
                '[email protected]',
1763
                ['as_string' => true],
1764
            ],
1765
            [
1766
                '<th>Data</th> <td><p><strong>Creating a Template for the Field</strong> and form</p> </td>',
1767
                'html',
1768
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1769
                [],
1770
            ],
1771
            [
1772
                '<th>Data</th> <td>Creating a Template for the Field and form </td>',
1773
                'html',
1774
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1775
                ['strip' => true],
1776
            ],
1777
            [
1778
                '<th>Data</th> <td> Creating a Template for the Fi... </td>',
1779
                'html',
1780
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1781
                ['truncate' => true],
1782
            ],
1783
            [
1784
                '<th>Data</th> <td> Creating a... </td>',
1785
                'html',
1786
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1787
                ['truncate' => ['length' => 10]],
1788
            ],
1789
            [
1790
                '<th>Data</th> <td> Creating a Template for the Field... </td>',
1791
                'html',
1792
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1793
                ['truncate' => ['preserve' => true]],
1794
            ],
1795
            [
1796
                '<th>Data</th> <td> Creating a Template for the Fi etc. </td>',
1797
                'html',
1798
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1799
                ['truncate' => ['separator' => ' etc.']],
1800
            ],
1801
            [
1802
                '<th>Data</th> <td> Creating a Template for[...] </td>',
1803
                'html',
1804
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1805
                [
1806
                    'truncate' => [
1807
                        'length' => 20,
1808
                        'preserve' => true,
1809
                        'separator' => '[...]',
1810
                    ],
1811
                ],
1812
            ],
1813
1814
            // NoValueException
1815
            ['<th>Data</th> <td></td>', 'string', new NoValueException(), ['safe' => false]],
1816
            ['<th>Data</th> <td></td>', 'text', new NoValueException(), ['safe' => false]],
1817
            ['<th>Data</th> <td></td>', 'textarea', new NoValueException(), ['safe' => false]],
1818
            ['<th>Data</th> <td>&nbsp;</td>', 'datetime', new NoValueException(), []],
1819
            [
1820
                '<th>Data</th> <td>&nbsp;</td>',
1821
                'datetime',
1822
                new NoValueException(),
1823
                ['format' => 'd.m.Y H:i:s'],
1824
            ],
1825
            ['<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), []],
1826
            ['<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), ['format' => 'd.m.Y']],
1827
            ['<th>Data</th> <td>&nbsp;</td>', 'time', new NoValueException(), []],
1828
            ['<th>Data</th> <td></td>', 'number', new NoValueException(), ['safe' => false]],
1829
            ['<th>Data</th> <td></td>', 'integer', new NoValueException(), ['safe' => false]],
1830
            ['<th>Data</th> <td> 0 % </td>', 'percent', new NoValueException(), []],
1831
            ['<th>Data</th> <td> </td>', 'currency', new NoValueException(), ['currency' => 'EUR']],
1832
            ['<th>Data</th> <td> </td>', 'currency', new NoValueException(), ['currency' => 'GBP']],
1833
            ['<th>Data</th> <td> </td>', 'array', new NoValueException(), ['safe' => false]],
1834
            [
1835
                '<th>Data</th> <td><span class="label label-danger">no</span></td>',
1836
                'boolean',
1837
                new NoValueException(),
1838
                [],
1839
            ],
1840
            [
1841
                '<th>Data</th> <td> </td>',
1842
                'trans',
1843
                new NoValueException(),
1844
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1845
            ],
1846
            [
1847
                '<th>Data</th> <td></td>',
1848
                'choice',
1849
                new NoValueException(),
1850
                ['safe' => false, 'choices' => []],
1851
            ],
1852
            [
1853
                '<th>Data</th> <td></td>',
1854
                'choice',
1855
                new NoValueException(),
1856
                ['safe' => false, 'choices' => [], 'multiple' => true],
1857
            ],
1858
            ['<th>Data</th> <td>&nbsp;</td>', 'url', new NoValueException(), []],
1859
            [
1860
                '<th>Data</th> <td>&nbsp;</td>',
1861
                'url',
1862
                new NoValueException(),
1863
                ['url' => 'http://example.com'],
1864
            ],
1865
            [
1866
                '<th>Data</th> <td>&nbsp;</td>',
1867
                'url',
1868
                new NoValueException(),
1869
                ['route' => ['name' => 'sonata_admin_foo']],
1870
            ],
1871
1872
            [
1873
                <<<'EOT'
1874
<th>Data</th> <td><div
1875
        class="sonata-readmore"
1876
        data-readmore-height="40"
1877
        data-readmore-more="Read more"
1878
        data-readmore-less="Close">
1879
            A very long string
1880
</div></td>
1881
EOT
1882
                ,
1883
                'text',
1884
                ' A very long string ',
1885
                [
1886
                    'collapse' => true,
1887
                    'safe' => false,
1888
                ],
1889
            ],
1890
            [
1891
                <<<'EOT'
1892
<th>Data</th> <td><div
1893
        class="sonata-readmore"
1894
        data-readmore-height="10"
1895
        data-readmore-more="More"
1896
        data-readmore-less="Less">
1897
            A very long string
1898
</div></td>
1899
EOT
1900
                ,
1901
                'text',
1902
                ' A very long string ',
1903
                [
1904
                    'collapse' => [
1905
                        'height' => 10,
1906
                        'more' => 'More',
1907
                        'less' => 'Less',
1908
                    ],
1909
                    'safe' => false,
1910
                ],
1911
            ],
1912
        ];
1913
    }
1914
1915
    public function testGetValueFromFieldDescription(): void
1916
    {
1917
        $object = new \stdClass();
1918
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1919
1920
        $fieldDescription->expects($this->any())
1921
            ->method('getValue')
1922
            ->willReturn('test123');
1923
1924
        $this->assertSame(
1925
            'test123',
1926
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1927
                $this->twigExtension,
1928
                $object,
1929
                $fieldDescription
1930
            )
1931
        );
1932
    }
1933
1934
    public function testGetValueFromFieldDescriptionWithRemoveLoopException(): void
1935
    {
1936
        $object = $this->createMock(\ArrayAccess::class);
1937
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1938
1939
        $this->expectException(\RuntimeException::class, 'remove the loop requirement');
1940
1941
        $this->assertSame(
1942
            'anything',
1943
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1944
                $this->twigExtension,
1945
                $object,
1946
                $fieldDescription,
1947
                ['loop' => true]
1948
            )
1949
        );
1950
    }
1951
1952
    public function testGetValueFromFieldDescriptionWithNoValueException(): void
1953
    {
1954
        $object = new \stdClass();
1955
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1956
1957
        $fieldDescription->expects($this->any())
1958
            ->method('getValue')
1959
            ->willReturnCallback(static function (): void {
1960
                throw new NoValueException();
1961
            });
1962
1963
        $fieldDescription->expects($this->any())
1964
            ->method('getAssociationAdmin')
1965
            ->willReturn(null);
1966
1967
        $this->assertNull(
1968
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1969
                $this->twigExtension,
1970
                $object,
1971
                $fieldDescription
1972
            )
1973
        );
1974
    }
1975
1976
    public function testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance(): void
1977
    {
1978
        $object = new \stdClass();
1979
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1980
1981
        $fieldDescription->expects($this->any())
1982
            ->method('getValue')
1983
            ->willReturnCallback(static function (): void {
1984
                throw new NoValueException();
1985
            });
1986
1987
        $fieldDescription->expects($this->any())
1988
            ->method('getAssociationAdmin')
1989
            ->willReturn($this->admin);
1990
1991
        $this->admin->expects($this->once())
1992
            ->method('getNewInstance')
1993
            ->willReturn('foo');
1994
1995
        $this->assertSame(
1996
            'foo',
1997
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1998
                $this->twigExtension,
1999
                $object,
2000
                $fieldDescription
2001
            )
2002
        );
2003
    }
2004
2005
    /**
2006
     * @group legacy
2007
     * @expectedDeprecation The Sonata\AdminBundle\Admin\AbstractAdmin::getTemplate method is deprecated (since 3.34, will be dropped in 4.0. Use TemplateRegistry services instead).
2008
     */
2009
    public function testRenderWithDebug(): void
2010
    {
2011
        $this->fieldDescription->expects($this->any())
2012
            ->method('getTemplate')
2013
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
2014
2015
        $this->fieldDescription->expects($this->any())
2016
            ->method('getFieldName')
2017
            ->willReturn('fd_name');
2018
2019
        $this->fieldDescription->expects($this->any())
2020
            ->method('getValue')
2021
            ->willReturn('foo');
2022
2023
        $parameters = [
2024
            'admin' => $this->admin,
2025
            'value' => 'foo',
2026
            'field_description' => $this->fieldDescription,
2027
            'object' => $this->object,
2028
        ];
2029
2030
        $this->environment->enableDebug();
2031
2032
        $this->assertSame(
2033
            $this->removeExtraWhitespace(<<<'EOT'
2034
<!-- START
2035
    fieldName: fd_name
2036
    template: @SonataAdmin/CRUD/base_list_field.html.twig
2037
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
2038
-->
2039
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
2040
<!-- END - fieldName: fd_name -->
2041
EOT
2042
            ),
2043
            $this->removeExtraWhitespace(
2044
                $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription, $parameters)
2045
            )
2046
        );
2047
    }
2048
2049
    public function testRenderRelationElementNoObject(): void
2050
    {
2051
        $this->assertSame('foo', $this->twigExtension->renderRelationElement('foo', $this->fieldDescription));
2052
    }
2053
2054
    public function testRenderRelationElementToString(): void
2055
    {
2056
        $this->fieldDescription->expects($this->exactly(2))
2057
            ->method('getOption')
2058
            ->willReturnCallback(static function ($value, $default = null) {
2059
                if ('associated_property' === $value) {
2060
                    return $default;
2061
                }
2062
            });
2063
2064
        $element = new FooToString();
2065
        $this->assertSame('salut', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2066
    }
2067
2068
    /**
2069
     * @group legacy
2070
     */
2071
    public function testDeprecatedRelationElementToString(): void
2072
    {
2073
        $this->fieldDescription->expects($this->exactly(2))
2074
            ->method('getOption')
2075
            ->willReturnCallback(static function ($value, $default = null) {
2076
                if ('associated_tostring' === $value) {
2077
                    return '__toString';
2078
                }
2079
            });
2080
2081
        $element = new FooToString();
2082
        $this->assertSame(
2083
            'salut',
2084
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2085
        );
2086
    }
2087
2088
    /**
2089
     * @group legacy
2090
     */
2091
    public function testRenderRelationElementCustomToString(): void
2092
    {
2093
        $this->fieldDescription->expects($this->exactly(2))
2094
            ->method('getOption')
2095
            ->willReturnCallback(static function ($value, $default = null) {
2096
                if ('associated_property' === $value) {
2097
                    return $default;
2098
                }
2099
2100
                if ('associated_tostring' === $value) {
2101
                    return 'customToString';
2102
                }
2103
            });
2104
2105
        $element = $this->getMockBuilder('stdClass')
2106
            ->setMethods(['customToString'])
2107
            ->getMock();
2108
        $element->expects($this->any())
2109
            ->method('customToString')
2110
            ->willReturn('fooBar');
2111
2112
        $this->assertSame('fooBar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2113
    }
2114
2115
    /**
2116
     * @group legacy
2117
     */
2118
    public function testRenderRelationElementMethodNotExist(): void
2119
    {
2120
        $this->fieldDescription->expects($this->exactly(2))
2121
            ->method('getOption')
2122
2123
            ->willReturnCallback(static function ($value, $default = null) {
2124
                if ('associated_tostring' === $value) {
2125
                    return 'nonExistedMethod';
2126
                }
2127
            });
2128
2129
        $element = new \stdClass();
2130
        $this->expectException(\RuntimeException::class, 'You must define an `associated_property` option or create a `stdClass::__toString');
2131
2132
        $this->twigExtension->renderRelationElement($element, $this->fieldDescription);
2133
    }
2134
2135
    public function testRenderRelationElementWithPropertyPath(): void
2136
    {
2137
        $this->fieldDescription->expects($this->exactly(1))
2138
            ->method('getOption')
2139
2140
            ->willReturnCallback(static function ($value, $default = null) {
2141
                if ('associated_property' === $value) {
2142
                    return 'foo';
2143
                }
2144
            });
2145
2146
        $element = new \stdClass();
2147
        $element->foo = 'bar';
2148
2149
        $this->assertSame('bar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2150
    }
2151
2152
    public function testRenderRelationElementWithClosure(): void
2153
    {
2154
        $this->fieldDescription->expects($this->exactly(1))
2155
            ->method('getOption')
2156
2157
            ->willReturnCallback(static function ($value, $default = null) {
2158
                if ('associated_property' === $value) {
2159
                    return static function ($element) {
2160
                        return 'closure '.$element->foo;
2161
                    };
2162
                }
2163
            });
2164
2165
        $element = new \stdClass();
2166
        $element->foo = 'bar';
2167
2168
        $this->assertSame(
2169
            'closure bar',
2170
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2171
        );
2172
    }
2173
2174
    public function testGetUrlsafeIdentifier(): void
2175
    {
2176
        $entity = new \stdClass();
2177
2178
        // set admin to pool
2179
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
2180
        $this->pool->setAdminClasses(['stdClass' => ['sonata_admin_foo_service']]);
2181
2182
        $this->admin->expects($this->once())
2183
            ->method('getUrlsafeIdentifier')
2184
            ->with($this->equalTo($entity))
2185
            ->willReturn(1234567);
2186
2187
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity));
2188
    }
2189
2190
    public function testGetUrlsafeIdentifier_GivenAdmin_Foo(): void
2191
    {
2192
        $entity = new \stdClass();
2193
2194
        // set admin to pool
2195
        $this->pool->setAdminServiceIds([
2196
            'sonata_admin_foo_service',
2197
            'sonata_admin_bar_service',
2198
        ]);
2199
        $this->pool->setAdminClasses(['stdClass' => [
2200
            'sonata_admin_foo_service',
2201
            'sonata_admin_bar_service',
2202
        ]]);
2203
2204
        $this->admin->expects($this->once())
2205
            ->method('getUrlsafeIdentifier')
2206
            ->with($this->equalTo($entity))
2207
            ->willReturn(1234567);
2208
2209
        $this->adminBar->expects($this->never())
2210
            ->method('getUrlsafeIdentifier');
2211
2212
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->admin));
2213
    }
2214
2215
    public function testGetUrlsafeIdentifier_GivenAdmin_Bar(): void
2216
    {
2217
        $entity = new \stdClass();
2218
2219
        // set admin to pool
2220
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service', 'sonata_admin_bar_service']);
2221
        $this->pool->setAdminClasses(['stdClass' => [
2222
            'sonata_admin_foo_service',
2223
            'sonata_admin_bar_service',
2224
        ]]);
2225
2226
        $this->admin->expects($this->never())
2227
            ->method('getUrlsafeIdentifier');
2228
2229
        $this->adminBar->expects($this->once())
2230
            ->method('getUrlsafeIdentifier')
2231
            ->with($this->equalTo($entity))
2232
            ->willReturn(1234567);
2233
2234
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->adminBar));
2235
    }
2236
2237
    public function xEditableChoicesProvider()
2238
    {
2239
        return [
2240
            'needs processing' => [
2241
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2']],
2242
                [
2243
                    ['value' => 'Status1', 'text' => 'Alias1'],
2244
                    ['value' => 'Status2', 'text' => 'Alias2'],
2245
                ],
2246
            ],
2247
            'already processed' => [
2248
                ['choices' => [
2249
                    ['value' => 'Status1', 'text' => 'Alias1'],
2250
                    ['value' => 'Status2', 'text' => 'Alias2'],
2251
                ]],
2252
                [
2253
                    ['value' => 'Status1', 'text' => 'Alias1'],
2254
                    ['value' => 'Status2', 'text' => 'Alias2'],
2255
                ],
2256
            ],
2257
            'not required' => [
2258
                [
2259
                    'required' => false,
2260
                    'choices' => ['' => '', 'Status1' => 'Alias1', 'Status2' => 'Alias2'],
2261
                ],
2262
                [
2263
                    ['value' => '', 'text' => ''],
2264
                    ['value' => 'Status1', 'text' => 'Alias1'],
2265
                    ['value' => 'Status2', 'text' => 'Alias2'],
2266
                ],
2267
            ],
2268
            'not required multiple' => [
2269
                [
2270
                    'required' => false,
2271
                    'multiple' => true,
2272
                    'choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2'],
2273
                ],
2274
                [
2275
                    ['value' => 'Status1', 'text' => 'Alias1'],
2276
                    ['value' => 'Status2', 'text' => 'Alias2'],
2277
                ],
2278
            ],
2279
        ];
2280
    }
2281
2282
    /**
2283
     * @dataProvider xEditablechoicesProvider
2284
     */
2285
    public function testGetXEditableChoicesIsIdempotent(array $options, $expectedChoices): void
2286
    {
2287
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2288
        $fieldDescription->expects($this->any())
2289
            ->method('getOption')
2290
            ->withConsecutive(
2291
                ['choices', []],
2292
                ['catalogue'],
2293
                ['required'],
2294
                ['multiple']
2295
            )
2296
            ->will($this->onConsecutiveCalls(
2297
                $options['choices'],
2298
                'MyCatalogue',
2299
                $options['multiple'] ?? null
2300
            ));
2301
2302
        $this->assertSame($expectedChoices, $this->twigExtension->getXEditableChoices($fieldDescription));
0 ignored issues
show
$fieldDescription is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Sonata\AdminBundl...ldDescriptionInterface>.

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...
2303
    }
2304
2305
    public function select2LocalesProvider()
2306
    {
2307
        return [
2308
            ['ar', 'ar'],
2309
            ['az', 'az'],
2310
            ['bg', 'bg'],
2311
            ['ca', 'ca'],
2312
            ['cs', 'cs'],
2313
            ['da', 'da'],
2314
            ['de', 'de'],
2315
            ['el', 'el'],
2316
            [null, 'en'],
2317
            ['es', 'es'],
2318
            ['et', 'et'],
2319
            ['eu', 'eu'],
2320
            ['fa', 'fa'],
2321
            ['fi', 'fi'],
2322
            ['fr', 'fr'],
2323
            ['gl', 'gl'],
2324
            ['he', 'he'],
2325
            ['hr', 'hr'],
2326
            ['hu', 'hu'],
2327
            ['id', 'id'],
2328
            ['is', 'is'],
2329
            ['it', 'it'],
2330
            ['ja', 'ja'],
2331
            ['ka', 'ka'],
2332
            ['ko', 'ko'],
2333
            ['lt', 'lt'],
2334
            ['lv', 'lv'],
2335
            ['mk', 'mk'],
2336
            ['ms', 'ms'],
2337
            ['nb', 'nb'],
2338
            ['nl', 'nl'],
2339
            ['pl', 'pl'],
2340
            ['pt-PT', 'pt'],
2341
            ['pt-BR', 'pt-BR'],
2342
            ['pt-PT', 'pt-PT'],
2343
            ['ro', 'ro'],
2344
            ['rs', 'rs'],
2345
            ['ru', 'ru'],
2346
            ['sk', 'sk'],
2347
            ['sv', 'sv'],
2348
            ['th', 'th'],
2349
            ['tr', 'tr'],
2350
            ['ug-CN', 'ug'],
2351
            ['ug-CN', 'ug-CN'],
2352
            ['uk', 'uk'],
2353
            ['vi', 'vi'],
2354
            ['zh-CN', 'zh'],
2355
            ['zh-CN', 'zh-CN'],
2356
            ['zh-TW', 'zh-TW'],
2357
        ];
2358
    }
2359
2360
    /**
2361
     * @dataProvider select2LocalesProvider
2362
     */
2363
    public function testCanonicalizedLocaleForSelect2($expected, $original): void
2364
    {
2365
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForSelect2($this->mockExtensionContext($original)));
2366
    }
2367
2368
    public function momentLocalesProvider()
2369
    {
2370
        return [
2371
            ['af', 'af'],
2372
            ['ar-dz', 'ar-dz'],
2373
            ['ar', 'ar'],
2374
            ['ar-ly', 'ar-ly'],
2375
            ['ar-ma', 'ar-ma'],
2376
            ['ar-sa', 'ar-sa'],
2377
            ['ar-tn', 'ar-tn'],
2378
            ['az', 'az'],
2379
            ['be', 'be'],
2380
            ['bg', 'bg'],
2381
            ['bn', 'bn'],
2382
            ['bo', 'bo'],
2383
            ['br', 'br'],
2384
            ['bs', 'bs'],
2385
            ['ca', 'ca'],
2386
            ['cs', 'cs'],
2387
            ['cv', 'cv'],
2388
            ['cy', 'cy'],
2389
            ['da', 'da'],
2390
            ['de-at', 'de-at'],
2391
            ['de', 'de'],
2392
            ['de', 'de-de'],
2393
            ['dv', 'dv'],
2394
            ['el', 'el'],
2395
            [null, 'en'],
2396
            [null, 'en-us'],
2397
            ['en-au', 'en-au'],
2398
            ['en-ca', 'en-ca'],
2399
            ['en-gb', 'en-gb'],
2400
            ['en-ie', 'en-ie'],
2401
            ['en-nz', 'en-nz'],
2402
            ['eo', 'eo'],
2403
            ['es-do', 'es-do'],
2404
            ['es', 'es-ar'],
2405
            ['es', 'es-mx'],
2406
            ['es', 'es'],
2407
            ['et', 'et'],
2408
            ['eu', 'eu'],
2409
            ['fa', 'fa'],
2410
            ['fi', 'fi'],
2411
            ['fo', 'fo'],
2412
            ['fr-ca', 'fr-ca'],
2413
            ['fr-ch', 'fr-ch'],
2414
            ['fr', 'fr-fr'],
2415
            ['fr', 'fr'],
2416
            ['fy', 'fy'],
2417
            ['gd', 'gd'],
2418
            ['gl', 'gl'],
2419
            ['he', 'he'],
2420
            ['hi', 'hi'],
2421
            ['hr', 'hr'],
2422
            ['hu', 'hu'],
2423
            ['hy-am', 'hy-am'],
2424
            ['id', 'id'],
2425
            ['is', 'is'],
2426
            ['it', 'it'],
2427
            ['ja', 'ja'],
2428
            ['jv', 'jv'],
2429
            ['ka', 'ka'],
2430
            ['kk', 'kk'],
2431
            ['km', 'km'],
2432
            ['ko', 'ko'],
2433
            ['ky', 'ky'],
2434
            ['lb', 'lb'],
2435
            ['lo', 'lo'],
2436
            ['lt', 'lt'],
2437
            ['lv', 'lv'],
2438
            ['me', 'me'],
2439
            ['mi', 'mi'],
2440
            ['mk', 'mk'],
2441
            ['ml', 'ml'],
2442
            ['mr', 'mr'],
2443
            ['ms', 'ms'],
2444
            ['ms-my', 'ms-my'],
2445
            ['my', 'my'],
2446
            ['nb', 'nb'],
2447
            ['ne', 'ne'],
2448
            ['nl-be', 'nl-be'],
2449
            ['nl', 'nl'],
2450
            ['nl', 'nl-nl'],
2451
            ['nn', 'nn'],
2452
            ['pa-in', 'pa-in'],
2453
            ['pl', 'pl'],
2454
            ['pt-br', 'pt-br'],
2455
            ['pt', 'pt'],
2456
            ['ro', 'ro'],
2457
            ['ru', 'ru'],
2458
            ['se', 'se'],
2459
            ['si', 'si'],
2460
            ['sk', 'sk'],
2461
            ['sl', 'sl'],
2462
            ['sq', 'sq'],
2463
            ['sr-cyrl', 'sr-cyrl'],
2464
            ['sr', 'sr'],
2465
            ['ss', 'ss'],
2466
            ['sv', 'sv'],
2467
            ['sw', 'sw'],
2468
            ['ta', 'ta'],
2469
            ['te', 'te'],
2470
            ['tet', 'tet'],
2471
            ['th', 'th'],
2472
            ['tlh', 'tlh'],
2473
            ['tl-ph', 'tl-ph'],
2474
            ['tr', 'tr'],
2475
            ['tzl', 'tzl'],
2476
            ['tzm', 'tzm'],
2477
            ['tzm-latn', 'tzm-latn'],
2478
            ['uk', 'uk'],
2479
            ['uz', 'uz'],
2480
            ['vi', 'vi'],
2481
            ['x-pseudo', 'x-pseudo'],
2482
            ['yo', 'yo'],
2483
            ['zh-cn', 'zh-cn'],
2484
            ['zh-hk', 'zh-hk'],
2485
            ['zh-tw', 'zh-tw'],
2486
        ];
2487
    }
2488
2489
    /**
2490
     * @dataProvider momentLocalesProvider
2491
     */
2492
    public function testCanonicalizedLocaleForMoment($expected, $original): void
2493
    {
2494
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForMoment($this->mockExtensionContext($original)));
2495
    }
2496
2497
    public function testIsGrantedAffirmative(): void
2498
    {
2499
        $this->assertTrue(
2500
            $this->twigExtension->isGrantedAffirmative(['foo', 'bar'])
2501
        );
2502
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('foo'));
2503
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('bar'));
2504
    }
2505
2506
    /**
2507
     * This method generates url part for Twig layout.
2508
     */
2509
    private function buildTwigLikeUrl(array $url): string
2510
    {
2511
        return htmlspecialchars(http_build_query($url, '', '&', PHP_QUERY_RFC3986));
2512
    }
2513
2514
    private function getMethodAsPublic($privateMethod): \ReflectionMethod
2515
    {
2516
        $reflection = new \ReflectionMethod('Sonata\AdminBundle\Twig\Extension\SonataAdminExtension', $privateMethod);
2517
        $reflection->setAccessible(true);
2518
2519
        return $reflection;
2520
    }
2521
2522
    private function removeExtraWhitespace($string): string
2523
    {
2524
        return trim(preg_replace(
2525
            '/\s+/',
2526
            ' ',
2527
            $string
2528
        ));
2529
    }
2530
2531
    private function mockExtensionContext($locale): array
2532
    {
2533
        $request = $this->createMock(Request::class);
2534
        $request->method('getLocale')->willReturn($locale);
2535
        $appVariable = $this->createMock(AppVariable::class);
2536
        $appVariable->method('getRequest')->willReturn($request);
2537
2538
        return ['app' => $appVariable];
2539
    }
2540
}
2541