Completed
Push — master ( d156ed...4d76a5 )
by
unknown
03:07 queued 11s
created

SonataAdminExtensionTest   F

Complexity

Total Complexity 67

Size/Duplication

Total Lines 2509
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 0
Metric Value
wmc 67
lcom 1
cbo 17
dl 0
loc 2509
rs 1.84
c 0
b 0
f 0

32 Methods

Rating   Name   Duplication   Size   Complexity  
B setUp() 0 152 3
B getRenderListElementTests() 0 968 1
C testRenderViewElement() 0 58 13
B getRenderViewElementTests() 0 498 1
B getRenderViewElementWithNoValueTests() 0 55 1
A testGetValueFromFieldDescription() 0 18 1
A testGetValueFromFieldDescriptionWithRemoveLoopException() 0 18 1
A testGetValueFromFieldDescriptionWithNoValueException() 0 23 1
A testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance() 0 30 1
A testRenderRelationElementNoObject() 0 4 1
A testRenderRelationElementToString() 0 13 2
A testDeprecatedRelationElementToString() 0 16 2
A testRenderRelationElementCustomToString() 0 23 3
A testRenderRelationElementMethodNotExist() 0 17 2
A testRenderRelationElementWithPropertyPath() 0 16 2
A testRenderRelationElementWithClosure() 0 21 2
A testGetUrlsafeIdentifier() 0 15 1
A testGetUrlsafeIdentifier_GivenAdmin_Foo() 0 24 1
A testGetUrlsafeIdentifier_GivenAdmin_Bar() 0 21 1
A xEditableChoicesProvider() 0 44 1
A testGetXEditableChoicesIsIdempotent() 0 19 1
A select2LocalesProvider() 0 54 1
A testCanonicalizedLocaleForSelect2() 0 4 1
B momentLocalesProvider() 0 120 1
A testCanonicalizedLocaleForMoment() 0 4 1
A testIsGrantedAffirmative() 0 8 1
C testRenderViewElementCompare() 0 75 15
A getRenderViewElementCompareTests() 0 37 1
A buildTwigLikeUrl() 0 4 1
A getMethodAsPublic() 0 7 1
A removeExtraWhitespace() 0 8 1
A mockExtensionContext() 0 9 1

How to fix   Complexity   

Complex Class

Complex classes like SonataAdminExtensionTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SonataAdminExtensionTest, and based on these observations, apply Extract Interface, too.

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 Sonata\AdminBundle\Twig\Extension\StringExtension;
28
use Symfony\Bridge\Twig\AppVariable;
29
use Symfony\Bridge\Twig\Extension\RoutingExtension;
30
use Symfony\Bridge\Twig\Extension\TranslationExtension;
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\Loader\XliffFileLoader;
39
use Symfony\Component\Translation\Translator;
40
use Symfony\Contracts\Translation\TranslatorInterface;
41
use Twig\Environment;
42
use Twig\Loader\FilesystemLoader;
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 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
    protected function setUp(): void
117
    {
118
        date_default_timezone_set('Europe/London');
119
120
        $container = $this->createMock(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 = [
0 ignored issues
show
Documentation Bug introduced by
It seems like array('choice' => 'selec...umber', 'url' => 'url') of type array<string,string,{"ch...tring","url":"string"}> is incompatible with the declared type array<integer,string> of property $xEditableTypeMapping.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
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('en');
146
        $translator->addLoader('xlf', new XliffFileLoader());
147
        $translator->addResource(
148
            'xlf',
149
            __DIR__.'/../../../src/Resources/translations/SonataAdminBundle.en.xliff',
150
            'en',
151
            'SonataAdminBundle'
152
        );
153
154
        $this->translator = $translator;
155
156
        $this->templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
157
        $this->container = $this->prophesize(ContainerInterface::class);
158
        $this->container->get('sonata_admin_foo_service.template_registry')->willReturn($this->templateRegistry->reveal());
159
160
        $this->securityChecker = $this->prophesize(AuthorizationCheckerInterface::class);
161
        $this->securityChecker->isGranted(['foo', 'bar'], null)->willReturn(false);
162
        $this->securityChecker->isGranted(Argument::type('string'), null)->willReturn(true);
163
164
        $this->twigExtension = new SonataAdminExtension(
165
            $this->pool,
166
            $this->logger,
167
            $this->translator,
168
            $this->container->reveal(),
169
            $this->securityChecker->reveal()
170
        );
171
        $this->twigExtension->setXEditableTypeMapping($this->xEditableTypeMapping);
172
173
        $request = $this->createMock(Request::class);
174
        $request->method('get')->with('_sonata_admin')->willReturn('sonata_admin_foo_service');
175
176
        $loader = new FilesystemLoader([
177
            __DIR__.'/../../../src/Resources/views/CRUD',
178
            __DIR__.'/../../Fixtures/Resources/views/CRUD',
179
        ]);
180
        $loader->addPath(__DIR__.'/../../../src/Resources/views/', 'SonataAdmin');
181
        $loader->addPath(__DIR__.'/../../Fixtures/Resources/views/', 'App');
182
183
        $this->environment = new Environment($loader, [
184
            'strict_variables' => true,
185
            'cache' => false,
186
            'autoescape' => 'html',
187
            'optimizations' => 0,
188
        ]);
189
        $this->environment->addExtension($this->twigExtension);
190
        $this->environment->addExtension(new TranslationExtension($translator));
191
        $this->environment->addExtension(new FakeTemplateRegistryExtension());
192
193
        // routing extension
194
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../../src/Resources/config/routing']));
195
        $routeCollection = $xmlFileLoader->load('sonata_admin.xml');
196
197
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../Fixtures/Resources/config/routing']));
198
        $testRouteCollection = $xmlFileLoader->load('routing.xml');
199
200
        $routeCollection->addCollection($testRouteCollection);
0 ignored issues
show
Documentation introduced by
$testRouteCollection is of type object<Symfony\Component\Routing\RouteCollection>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
201
        $requestContext = new RequestContext();
202
        $urlGenerator = new UrlGenerator($routeCollection, $requestContext);
203
        $this->environment->addExtension(new RoutingExtension($urlGenerator));
204
        $this->environment->addExtension(new StringExtension());
205
206
        // initialize object
207
        $this->object = new \stdClass();
208
209
        // initialize admin
210
        $this->admin = $this->createMock(AbstractAdmin::class);
211
212
        $this->admin
213
            ->method('getCode')
214
            ->willReturn('sonata_admin_foo_service');
215
216
        $this->admin
217
            ->method('id')
218
            ->with($this->equalTo($this->object))
219
            ->willReturn('12345');
220
221
        $this->admin
222
            ->method('getNormalizedIdentifier')
223
            ->with($this->equalTo($this->object))
224
            ->willReturn('12345');
225
226
        $this->admin
227
            ->method('trans')
228
            ->willReturnCallback(static function ($id, $parameters = [], $domain = null) use ($translator) {
229
                return $translator->trans($id, $parameters, $domain);
230
            });
231
232
        $this->adminBar = $this->createMock(AbstractAdmin::class);
233
        $this->adminBar
234
            ->method('hasAccess')
235
            ->willReturn(true);
236
        $this->adminBar
237
            ->method('getNormalizedIdentifier')
238
            ->with($this->equalTo($this->object))
239
            ->willReturn('12345');
240
241
        $container
242
            ->method('get')
243
            ->willReturnCallback(function (string $id) {
244
                if ('sonata_admin_foo_service' === $id) {
245
                    return $this->admin;
246
                }
247
248
                if ('sonata_admin_bar_service' === $id) {
249
                    return $this->adminBar;
250
                }
251
            });
252
253
        // initialize field description
254
        $this->fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
255
256
        $this->fieldDescription
257
            ->method('getName')
258
            ->willReturn('fd_name');
259
260
        $this->fieldDescription
261
            ->method('getAdmin')
262
            ->willReturn($this->admin);
263
264
        $this->fieldDescription
265
            ->method('getLabel')
266
            ->willReturn('Data');
267
    }
268
269
    public function getRenderListElementTests()
270
    {
271
        return [
272
            [
273
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> Example </td>',
274
                'string',
275
                'Example',
276
                [],
277
            ],
278
            [
279
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> </td>',
280
                'string',
281
                null,
282
                [],
283
            ],
284
            [
285
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> Example </td>',
286
                'text',
287
                'Example',
288
                [],
289
            ],
290
            [
291
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> </td>',
292
                'text',
293
                null,
294
                [],
295
            ],
296
            [
297
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> Example </td>',
298
                'textarea',
299
                'Example',
300
                [],
301
            ],
302
            [
303
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> </td>',
304
                'textarea',
305
                null,
306
                [],
307
            ],
308
            'datetime field' => [
309
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
310
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
311
                        December 24, 2013 10:11
312
                    </time>
313
                </td>',
314
                'datetime',
315
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
316
                [],
317
            ],
318
            [
319
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
320
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
321
                        December 24, 2013 18:11
322
                    </time>
323
                </td>',
324
                'datetime',
325
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
326
                ['timezone' => 'Asia/Hong_Kong'],
327
            ],
328
            [
329
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
330
                'datetime',
331
                null,
332
                [],
333
            ],
334
            [
335
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
336
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
337
                        24.12.2013 10:11:12
338
                    </time>
339
                </td>',
340
                'datetime',
341
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
342
                ['format' => 'd.m.Y H:i:s'],
343
            ],
344
            [
345
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
346
                'datetime',
347
                null,
348
                ['format' => 'd.m.Y H:i:s'],
349
            ],
350
            [
351
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
352
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
353
                        24.12.2013 18:11:12
354
                    </time>
355
                </td>',
356
                'datetime',
357
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
358
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
359
            ],
360
            [
361
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
362
                'datetime',
363
                null,
364
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
365
            ],
366
            [
367
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345">
368
                    <time datetime="2013-12-24" title="2013-12-24">
369
                        December 24, 2013
370
                    </time>
371
                </td>',
372
                'date',
373
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
374
                [],
375
            ],
376
            [
377
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
378
                'date',
379
                null,
380
                [],
381
            ],
382
            [
383
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345">
384
                    <time datetime="2013-12-24" title="2013-12-24">
385
                        24.12.2013
386
                    </time>
387
                </td>',
388
                'date',
389
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
390
                ['format' => 'd.m.Y'],
391
            ],
392
            [
393
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
394
                'date',
395
                null,
396
                ['format' => 'd.m.Y'],
397
            ],
398
            [
399
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345">
400
                    <time datetime="10:11:12+00:00" title="10:11:12+00:00">
401
                        10:11:12
402
                    </time>
403
                </td>',
404
                'time',
405
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
406
                [],
407
            ],
408
            [
409
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345">
410
                    <time datetime="10:11:12+00:00" title="10:11:12+00:00">
411
                        18:11:12
412
                    </time>
413
                </td>',
414
                'time',
415
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
416
                ['timezone' => 'Asia/Hong_Kong'],
417
            ],
418
            [
419
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> &nbsp; </td>',
420
                'time',
421
                null,
422
                [],
423
            ],
424
            [
425
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> 10.746135 </td>',
426
                'number', 10.746135,
427
                [],
428
            ],
429
            [
430
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> </td>',
431
                'number',
432
                null,
433
                [],
434
            ],
435
            [
436
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> 5678 </td>',
437
                'integer',
438
                5678,
439
                [],
440
            ],
441
            [
442
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> </td>',
443
                'integer',
444
                null,
445
                [],
446
            ],
447
            [
448
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 1074.6135 % </td>',
449
                'percent',
450
                10.746135,
451
                [],
452
            ],
453
            [
454
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 0 % </td>',
455
                'percent',
456
                null,
457
                [],
458
            ],
459
            [
460
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> EUR 10.746135 </td>',
461
                'currency',
462
                10.746135,
463
                ['currency' => 'EUR'],
464
            ],
465
            [
466
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
467
                'currency',
468
                null,
469
                ['currency' => 'EUR'],
470
            ],
471
            [
472
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> GBP 51.23456 </td>',
473
                'currency',
474
                51.23456,
475
                ['currency' => 'GBP'],
476
            ],
477
            [
478
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
479
                'currency',
480
                null,
481
                ['currency' => 'GBP'],
482
            ],
483
            [
484
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> &nbsp; </td>',
485
                'email',
486
                null,
487
                [],
488
            ],
489
            [
490
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> <a href="mailto:[email protected]">[email protected]</a> </td>',
491
                'email',
492
                '[email protected]',
493
                [],
494
            ],
495
            [
496
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
497
                    <a href="mailto:[email protected]">[email protected]</a> </td>',
498
                'email',
499
                '[email protected]',
500
                ['as_string' => false],
501
            ],
502
            [
503
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
504
                'email',
505
                '[email protected]',
506
                ['as_string' => true],
507
            ],
508
            [
509
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
510
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a>  </td>',
511
                'email',
512
                '[email protected]',
513
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
514
            ],
515
            [
516
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
517
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a>  </td>',
518
                'email',
519
                '[email protected]',
520
                ['subject' => 'Main Theme'],
521
            ],
522
            [
523
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
524
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a>  </td>',
525
                'email',
526
                '[email protected]',
527
                ['body' => 'Message Body'],
528
            ],
529
            [
530
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
531
                'email',
532
                '[email protected]',
533
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
534
            ],
535
            [
536
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
537
                'email',
538
                '[email protected]',
539
                ['as_string' => true, 'body' => 'Message Body'],
540
            ],
541
            [
542
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
543
                'email',
544
                '[email protected]',
545
                ['as_string' => true, 'subject' => 'Main Theme'],
546
            ],
547
            [
548
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345">
549
                    [1&nbsp;=>&nbsp;First, 2&nbsp;=>&nbsp;Second]
550
                </td>',
551
                'array',
552
                [1 => 'First', 2 => 'Second'],
553
                [],
554
            ],
555
            [
556
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345"> [] </td>',
557
                'array',
558
                null,
559
                [],
560
            ],
561
            [
562
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
563
                    <span class="label label-success">yes</span>
564
                </td>',
565
                'boolean',
566
                true,
567
                ['editable' => false],
568
            ],
569
            [
570
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
571
                    <span class="label label-danger">no</span>
572
                </td>',
573
                'boolean',
574
                false,
575
                ['editable' => false],
576
            ],
577
            [
578
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
579
                    <span class="label label-danger">no</span>
580
                </td>',
581
                'boolean',
582
                null,
583
                ['editable' => false],
584
            ],
585
            [
586
                <<<'EOT'
587
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
588
    <span
589
        class="x-editable"
590
        data-type="select"
591
        data-value="1"
592
        data-title="Data"
593
        data-pk="12345"
594
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
595
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
596
    >
597
        <span class="label label-success">yes</span>
598
    </span>
599
</td>
600
EOT
601
            ,
602
                'boolean',
603
                true,
604
                ['editable' => true],
605
            ],
606
            [
607
                <<<'EOT'
608
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
609
    <span
610
        class="x-editable"
611
        data-type="select"
612
        data-value="0"
613
        data-title="Data"
614
        data-pk="12345"
615
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
616
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
617
    >
618
    <span class="label label-danger">no</span> </span>
619
</td>
620
EOT
621
                ,
622
                'boolean',
623
                false,
624
                ['editable' => true],
625
            ],
626
            [
627
                <<<'EOT'
628
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
629
    <span
630
        class="x-editable"
631
        data-type="select"
632
        data-value="0"
633
        data-title="Data"
634
        data-pk="12345"
635
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
636
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]" >
637
        <span class="label label-danger">no</span> </span>
638
</td>
639
EOT
640
                ,
641
                'boolean',
642
                null,
643
                ['editable' => true],
644
            ],
645
            [
646
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
647
                'trans',
648
                'action_delete',
649
                ['catalogue' => 'SonataAdminBundle'],
650
            ],
651
            [
652
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> </td>',
653
                'trans',
654
                null,
655
                ['catalogue' => 'SonataAdminBundle'],
656
            ],
657
            [
658
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
659
                'trans',
660
                'action_delete',
661
                ['format' => '%s', 'catalogue' => 'SonataAdminBundle'],
662
            ],
663
            [
664
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
665
                action.action_delete
666
                </td>',
667
                'trans',
668
                'action_delete',
669
                ['format' => 'action.%s'],
670
            ],
671
            [
672
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
673
                action.action_delete
674
                </td>',
675
                'trans',
676
                'action_delete',
677
                ['format' => 'action.%s', 'catalogue' => 'SonataAdminBundle'],
678
            ],
679
            [
680
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
681
                'choice',
682
                'Status1',
683
                [],
684
            ],
685
            [
686
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
687
                'choice',
688
                ['Status1'],
689
                ['choices' => [], 'multiple' => true],
690
            ],
691
            [
692
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 </td>',
693
                'choice',
694
                'Status1',
695
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
696
            ],
697
            [
698
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
699
                'choice',
700
                null,
701
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
702
            ],
703
            [
704
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
705
                NoValidKeyInChoices
706
                </td>',
707
                'choice',
708
                'NoValidKeyInChoices',
709
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
710
            ],
711
            [
712
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete </td>',
713
                'choice',
714
                'Foo',
715
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
716
                    'Foo' => 'action_delete',
717
                    'Status2' => 'Alias2',
718
                    'Status3' => 'Alias3',
719
                ]],
720
            ],
721
            [
722
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1, Alias3 </td>',
723
                'choice',
724
                ['Status1', 'Status3'],
725
                ['choices' => [
726
                    'Status1' => 'Alias1',
727
                    'Status2' => 'Alias2',
728
                    'Status3' => 'Alias3',
729
                ], 'multiple' => true], ],
730
            [
731
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 | Alias3 </td>',
732
                'choice',
733
                ['Status1', 'Status3'],
734
                ['choices' => [
735
                    'Status1' => 'Alias1',
736
                    'Status2' => 'Alias2',
737
                    'Status3' => 'Alias3',
738
                ], 'multiple' => true, 'delimiter' => ' | '], ],
739
            [
740
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
741
                'choice',
742
                null,
743
                ['choices' => [
744
                    'Status1' => 'Alias1',
745
                    'Status2' => 'Alias2',
746
                    'Status3' => 'Alias3',
747
                ], 'multiple' => true],
748
            ],
749
            [
750
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
751
                NoValidKeyInChoices
752
                </td>',
753
                'choice',
754
                ['NoValidKeyInChoices'],
755
                ['choices' => [
756
                    'Status1' => 'Alias1',
757
                    'Status2' => 'Alias2',
758
                    'Status3' => 'Alias3',
759
                ], 'multiple' => true],
760
            ],
761
            [
762
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
763
                NoValidKeyInChoices, Alias2
764
                </td>',
765
                'choice',
766
                ['NoValidKeyInChoices', 'Status2'],
767
                ['choices' => [
768
                    'Status1' => 'Alias1',
769
                    'Status2' => 'Alias2',
770
                    'Status3' => 'Alias3',
771
                ], 'multiple' => true],
772
            ],
773
            [
774
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete, Alias3 </td>',
775
                'choice',
776
                ['Foo', 'Status3'],
777
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
778
                    'Foo' => 'action_delete',
779
                    'Status2' => 'Alias2',
780
                    'Status3' => 'Alias3',
781
                ], 'multiple' => true],
782
            ],
783
            [
784
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
785
                &lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;
786
            </td>',
787
                'choice',
788
                ['Status1', 'Status3'],
789
                ['choices' => [
790
                    'Status1' => '<b>Alias1</b>',
791
                    'Status2' => '<b>Alias2</b>',
792
                    'Status3' => '<b>Alias3</b>',
793
                ], 'multiple' => true], ],
794
            [
795
                <<<'EOT'
796
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
797
    <span
798
        class="x-editable"
799
        data-type="select"
800
        data-value="Status1"
801
        data-title="Data"
802
        data-pk="12345"
803
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
804
        data-source="[]"
805
    >
806
        Status1
807
    </span>
808
</td>
809
EOT
810
                ,
811
                'choice',
812
                'Status1',
813
                ['editable' => true],
814
            ],
815
            [
816
                <<<'EOT'
817
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
818
    <span
819
        class="x-editable"
820
        data-type="select"
821
        data-value="Status1"
822
        data-title="Data"
823
        data-pk="12345"
824
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
825
        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;}]" >
826
        Alias1 </span>
827
</td>
828
EOT
829
                ,
830
                'choice',
831
                'Status1',
832
                [
833
                    'editable' => true,
834
                    'choices' => [
835
                        'Status1' => 'Alias1',
836
                        'Status2' => 'Alias2',
837
                        'Status3' => 'Alias3',
838
                    ],
839
                ],
840
            ],
841
            [
842
                <<<'EOT'
843
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
844
    <span
845
        class="x-editable"
846
        data-type="select"
847
        data-value=""
848
        data-title="Data"
849
        data-pk="12345"
850
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
851
        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;}]" >
852
853
    </span>
854
</td>
855
EOT
856
                ,
857
                'choice',
858
                null,
859
                [
860
                    'editable' => true,
861
                    'choices' => [
862
                        'Status1' => 'Alias1',
863
                        'Status2' => 'Alias2',
864
                        'Status3' => 'Alias3',
865
                    ],
866
                ],
867
            ],
868
            [
869
                <<<'EOT'
870
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
871
    <span
872
        class="x-editable"
873
        data-type="select"
874
        data-value="NoValidKeyInChoices"
875
        data-title="Data" data-pk="12345"
876
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
877
        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;}]" >
878
        NoValidKeyInChoices
879
    </span>
880
</td>
881
EOT
882
                ,
883
                'choice',
884
                'NoValidKeyInChoices',
885
                [
886
                    'editable' => true,
887
                    'choices' => [
888
                        'Status1' => 'Alias1',
889
                        'Status2' => 'Alias2',
890
                        'Status3' => 'Alias3',
891
                    ],
892
                ],
893
            ],
894
            [
895
                <<<'EOT'
896
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
897
    <span
898
        class="x-editable"
899
        data-type="select"
900
        data-value="Foo"
901
        data-title="Data"
902
        data-pk="12345"
903
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
904
        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;}]" >
905
         Delete
906
    </span>
907
</td>
908
EOT
909
                ,
910
                'choice',
911
                'Foo',
912
                [
913
                    'editable' => true,
914
                    'catalogue' => 'SonataAdminBundle',
915
                    'choices' => [
916
                        'Foo' => 'action_delete',
917
                        'Status2' => 'Alias2',
918
                        'Status3' => 'Alias3',
919
                    ],
920
                ],
921
            ],
922
            [
923
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
924
                'url',
925
                null,
926
                [],
927
            ],
928
            [
929
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
930
                'url',
931
                null,
932
                ['url' => 'http://example.com'],
933
            ],
934
            [
935
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
936
                'url',
937
                null,
938
                ['route' => ['name' => 'sonata_admin_foo']],
939
            ],
940
            [
941
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
942
                <a href="http://example.com">http://example.com</a>
943
                </td>',
944
                'url',
945
                'http://example.com',
946
                [],
947
            ],
948
            [
949
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
950
                <a href="https://example.com">https://example.com</a>
951
                </td>',
952
                'url',
953
                'https://example.com',
954
                [],
955
            ],
956
            [
957
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
958
                <a href="https://example.com" target="_blank">https://example.com</a>
959
                </td>',
960
                'url',
961
                'https://example.com',
962
                ['attributes' => ['target' => '_blank']],
963
            ],
964
            [
965
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
966
                <a href="https://example.com" target="_blank" class="fooLink">https://example.com</a>
967
                </td>',
968
                'url',
969
                'https://example.com',
970
                ['attributes' => ['target' => '_blank', 'class' => 'fooLink']],
971
            ],
972
            [
973
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
974
                <a href="http://example.com">example.com</a>
975
                </td>',
976
                'url',
977
                'http://example.com',
978
                ['hide_protocol' => true],
979
            ],
980
            [
981
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
982
                <a href="https://example.com">example.com</a>
983
                </td>',
984
                'url',
985
                'https://example.com',
986
                ['hide_protocol' => true],
987
            ],
988
            [
989
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
990
                <a href="http://example.com">http://example.com</a>
991
                </td>',
992
                'url',
993
                'http://example.com',
994
                ['hide_protocol' => false],
995
            ],
996
            [
997
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
998
                <a href="https://example.com">https://example.com</a>
999
                </td>',
1000
                'url',
1001
                'https://example.com',
1002
                ['hide_protocol' => false],
1003
            ],
1004
            [
1005
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1006
                <a href="http://example.com">Foo</a>
1007
                </td>',
1008
                'url',
1009
                'Foo',
1010
                ['url' => 'http://example.com'],
1011
            ],
1012
            [
1013
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1014
                <a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a>
1015
                </td>',
1016
                'url',
1017
                '<b>Foo</b>',
1018
                ['url' => 'http://example.com'],
1019
            ],
1020
            [
1021
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1022
                <a href="/foo">Foo</a>
1023
                </td>',
1024
                'url',
1025
                'Foo',
1026
                ['route' => ['name' => 'sonata_admin_foo']],
1027
            ],
1028
            [
1029
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1030
                <a href="http://localhost/foo">Foo</a>
1031
                </td>',
1032
                'url',
1033
                'Foo',
1034
                ['route' => ['name' => 'sonata_admin_foo', 'absolute' => true]],
1035
            ],
1036
            [
1037
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1038
                <a href="/foo">foo/bar?a=b&amp;c=123456789</a>
1039
                </td>',
1040
                'url',
1041
                'http://foo/bar?a=b&c=123456789',
1042
                ['route' => ['name' => 'sonata_admin_foo'],
1043
                'hide_protocol' => true, ],
1044
            ],
1045
            [
1046
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1047
                <a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a>
1048
                </td>',
1049
                'url',
1050
                'http://foo/bar?a=b&c=123456789',
1051
                [
1052
                    'route' => ['name' => 'sonata_admin_foo', 'absolute' => true],
1053
                    'hide_protocol' => true,
1054
                ],
1055
            ],
1056
            [
1057
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1058
                <a href="/foo/abcd/efgh?param3=ijkl">Foo</a>
1059
                </td>',
1060
                'url',
1061
                'Foo',
1062
                [
1063
                    'route' => ['name' => 'sonata_admin_foo_param',
1064
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1065
                ],
1066
            ],
1067
            [
1068
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1069
                <a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a>
1070
                </td>',
1071
                'url',
1072
                'Foo',
1073
                [
1074
                    'route' => ['name' => 'sonata_admin_foo_param',
1075
                    'absolute' => true,
1076
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1077
                ],
1078
            ],
1079
            [
1080
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1081
                <a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1082
                </td>',
1083
                'url',
1084
                'Foo',
1085
                [
1086
                    'route' => ['name' => 'sonata_admin_foo_object',
1087
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1088
                    'identifier_parameter_name' => 'barId', ],
1089
                ],
1090
            ],
1091
            [
1092
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1093
                <a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1094
                </td>',
1095
                'url',
1096
                'Foo',
1097
                [
1098
                    'route' => ['name' => 'sonata_admin_foo_object',
1099
                    'absolute' => true,
1100
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1101
                    'identifier_parameter_name' => 'barId', ],
1102
                ],
1103
            ],
1104
            [
1105
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1106
                <p><strong>Creating a Template for the Field</strong> and form</p>
1107
                </td>',
1108
                'html',
1109
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1110
                [],
1111
            ],
1112
            [
1113
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1114
                Creating a Template for the Field and form
1115
                </td>',
1116
                'html',
1117
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1118
                ['strip' => true],
1119
            ],
1120
            [
1121
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1122
                Creating a Template for the...
1123
                </td>',
1124
                'html',
1125
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1126
                ['truncate' => true],
1127
            ],
1128
            [
1129
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345"> Creatin... </td>',
1130
                'html',
1131
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1132
                ['truncate' => ['length' => 10]],
1133
            ],
1134
            [
1135
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1136
                Creating a Template for the Field...
1137
                </td>',
1138
                'html',
1139
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1140
                ['truncate' => ['cut' => false]],
1141
            ],
1142
            [
1143
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1144
                Creating a Template for t etc.
1145
                </td>',
1146
                'html',
1147
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1148
                ['truncate' => ['ellipsis' => ' etc.']],
1149
            ],
1150
            [
1151
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1152
                Creating a Template[...]
1153
                </td>',
1154
                'html',
1155
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1156
                [
1157
                    'truncate' => [
1158
                        'length' => 20,
1159
                        'cut' => false,
1160
                        'ellipsis' => '[...]',
1161
                    ],
1162
                ],
1163
            ],
1164
1165
            [
1166
                <<<'EOT'
1167
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1168
<div
1169
    class="sonata-readmore"
1170
    data-readmore-height="40"
1171
    data-readmore-more="Read more"
1172
    data-readmore-less="Close">A very long string</div>
1173
</td>
1174
EOT
1175
                ,
1176
                'text',
1177
                'A very long string',
1178
                [
1179
                    'collapse' => true,
1180
                ],
1181
            ],
1182
            [
1183
                <<<'EOT'
1184
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1185
<div
1186
    class="sonata-readmore"
1187
    data-readmore-height="10"
1188
    data-readmore-more="More"
1189
    data-readmore-less="Less">A very long string</div>
1190
</td>
1191
EOT
1192
                ,
1193
                'text',
1194
                'A very long string',
1195
                [
1196
                    'collapse' => [
1197
                        'height' => 10,
1198
                        'more' => 'More',
1199
                        'less' => 'Less',
1200
                    ],
1201
                ],
1202
            ],
1203
            [
1204
                <<<'EOT'
1205
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1206
    <span
1207
        class="x-editable"
1208
        data-type="checklist"
1209
        data-value="[&quot;Status1&quot;,&quot;Status2&quot;]"
1210
        data-title="Data"
1211
        data-pk="12345"
1212
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1213
        data-source="[{&quot;value&quot;:&quot;Status1&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;}]" >
1214
         Delete, Alias2
1215
    </span>
1216
</td>
1217
EOT
1218
                ,
1219
                'choice',
1220
                [
1221
                    'Status1',
1222
                    'Status2',
1223
                ],
1224
                [
1225
                    'editable' => true,
1226
                    'multiple' => true,
1227
                    'catalogue' => 'SonataAdminBundle',
1228
                    'choices' => [
1229
                        'Status1' => 'action_delete',
1230
                        'Status2' => 'Alias2',
1231
                        'Status3' => 'Alias3',
1232
                    ],
1233
                ],
1234
            ],
1235
        ];
1236
    }
1237
1238
    /**
1239
     * @dataProvider getRenderViewElementTests
1240
     */
1241
    public function testRenderViewElement(string $expected, string $type, $value, array $options): void
1242
    {
1243
        $this->fieldDescription
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1244
            ->method('getValue')
1245
            ->willReturn($value);
1246
1247
        $this->fieldDescription
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1248
            ->method('getType')
1249
            ->willReturn($type);
1250
1251
        $this->fieldDescription
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1252
            ->method('getOptions')
1253
            ->willReturn($options);
1254
1255
        $this->fieldDescription
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1256
            ->method('getTemplate')
1257
            ->willReturnCallback(static function () use ($type): ?string {
1258
                switch ($type) {
1259
                    case 'boolean':
1260
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
1261
                    case 'datetime':
1262
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
1263
                    case 'date':
1264
                        return '@SonataAdmin/CRUD/show_date.html.twig';
1265
                    case 'time':
1266
                        return '@SonataAdmin/CRUD/show_time.html.twig';
1267
                    case 'currency':
1268
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
1269
                    case 'percent':
1270
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
1271
                    case 'email':
1272
                        return '@SonataAdmin/CRUD/show_email.html.twig';
1273
                    case 'choice':
1274
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
1275
                    case 'array':
1276
                        return '@SonataAdmin/CRUD/show_array.html.twig';
1277
                    case 'trans':
1278
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
1279
                    case 'url':
1280
                        return '@SonataAdmin/CRUD/show_url.html.twig';
1281
                    case 'html':
1282
                        return '@SonataAdmin/CRUD/show_html.html.twig';
1283
                    default:
1284
                        return null;
1285
                }
1286
            });
1287
1288
        $this->assertSame(
1289
            $this->removeExtraWhitespace($expected),
1290
            $this->removeExtraWhitespace(
1291
                $this->twigExtension->renderViewElement(
1292
                    $this->environment,
1293
                    $this->fieldDescription,
1294
                    $this->object
1295
                )
1296
            )
1297
        );
1298
    }
1299
1300
    public function getRenderViewElementTests()
1301
    {
1302
        return [
1303
            ['<th>Data</th> <td>Example</td>', 'string', 'Example', ['safe' => false]],
1304
            ['<th>Data</th> <td>Example</td>', 'text', 'Example', ['safe' => false]],
1305
            ['<th>Data</th> <td>Example</td>', 'textarea', 'Example', ['safe' => false]],
1306
            [
1307
                '<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>',
1308
                'datetime',
1309
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), [],
1310
            ],
1311
            [
1312
                '<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>',
1313
                'datetime',
1314
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1315
                ['format' => 'd.m.Y H:i:s'],
1316
            ],
1317
            [
1318
                '<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>',
1319
                'datetime',
1320
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1321
                ['timezone' => 'Asia/Hong_Kong'],
1322
            ],
1323
            [
1324
                '<th>Data</th> <td><time datetime="2013-12-24" title="2013-12-24"> December 24, 2013 </time></td>',
1325
                'date',
1326
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1327
                [],
1328
            ],
1329
            [
1330
                '<th>Data</th> <td><time datetime="2013-12-24" title="2013-12-24"> 24.12.2013 </time></td>',
1331
                'date',
1332
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1333
                ['format' => 'd.m.Y'],
1334
            ],
1335
            [
1336
                '<th>Data</th> <td><time datetime="10:11:12+00:00" title="10:11:12+00:00"> 10:11:12 </time></td>',
1337
                'time',
1338
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1339
                [],
1340
            ],
1341
            [
1342
                '<th>Data</th> <td><time datetime="10:11:12+00:00" title="10:11:12+00:00"> 18:11:12 </time></td>',
1343
                'time',
1344
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1345
                ['timezone' => 'Asia/Hong_Kong'],
1346
            ],
1347
            ['<th>Data</th> <td>10.746135</td>', 'number', 10.746135, ['safe' => false]],
1348
            ['<th>Data</th> <td>5678</td>', 'integer', 5678, ['safe' => false]],
1349
            ['<th>Data</th> <td> 1074.6135 % </td>', 'percent', 10.746135, []],
1350
            ['<th>Data</th> <td> EUR 10.746135 </td>', 'currency', 10.746135, ['currency' => 'EUR']],
1351
            ['<th>Data</th> <td> GBP 51.23456 </td>', 'currency', 51.23456, ['currency' => 'GBP']],
1352
            [
1353
                '<th>Data</th> <td> <ul><li>1&nbsp;=>&nbsp;First</li><li>2&nbsp;=>&nbsp;Second</li></ul> </td>',
1354
                'array',
1355
                [1 => 'First', 2 => 'Second'],
1356
                ['safe' => false],
1357
            ],
1358
            [
1359
                '<th>Data</th> <td> [1&nbsp;=>&nbsp;First, 2&nbsp;=>&nbsp;Second] </td>',
1360
                'array',
1361
                [1 => 'First', 2 => 'Second'],
1362
                ['safe' => false, 'inline' => true],
1363
            ],
1364
            [
1365
                '<th>Data</th> <td><span class="label label-success">yes</span></td>',
1366
                'boolean',
1367
                true,
1368
                [],
1369
            ],
1370
            [
1371
                '<th>Data</th> <td><span class="label label-danger">yes</span></td>',
1372
                'boolean',
1373
                true,
1374
                ['inverse' => true],
1375
            ],
1376
            ['<th>Data</th> <td><span class="label label-danger">no</span></td>', 'boolean', false, []],
1377
            [
1378
                '<th>Data</th> <td><span class="label label-success">no</span></td>',
1379
                'boolean',
1380
                false,
1381
                ['inverse' => true],
1382
            ],
1383
            [
1384
                '<th>Data</th> <td> Delete </td>',
1385
                'trans',
1386
                'action_delete',
1387
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1388
            ],
1389
            [
1390
                '<th>Data</th> <td> Delete </td>',
1391
                'trans',
1392
                'delete',
1393
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'format' => 'action_%s'],
1394
            ],
1395
            ['<th>Data</th> <td>Status1</td>', 'choice', 'Status1', ['safe' => false]],
1396
            [
1397
                '<th>Data</th> <td>Alias1</td>',
1398
                'choice',
1399
                'Status1',
1400
                ['safe' => false, 'choices' => [
1401
                    'Status1' => 'Alias1',
1402
                    'Status2' => 'Alias2',
1403
                    'Status3' => 'Alias3',
1404
                ]],
1405
            ],
1406
            [
1407
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1408
                'choice',
1409
                'NoValidKeyInChoices',
1410
                ['safe' => false, 'choices' => [
1411
                    'Status1' => 'Alias1',
1412
                    'Status2' => 'Alias2',
1413
                    'Status3' => 'Alias3',
1414
                ]],
1415
            ],
1416
            [
1417
                '<th>Data</th> <td>Delete</td>',
1418
                'choice',
1419
                'Foo',
1420
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1421
                    'Foo' => 'action_delete',
1422
                    'Status2' => 'Alias2',
1423
                    'Status3' => 'Alias3',
1424
                ]],
1425
            ],
1426
            [
1427
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1428
                'choice',
1429
                ['NoValidKeyInChoices'],
1430
                ['safe' => false, 'choices' => [
1431
                    'Status1' => 'Alias1',
1432
                    'Status2' => 'Alias2',
1433
                    'Status3' => 'Alias3',
1434
                ], 'multiple' => true],
1435
            ],
1436
            [
1437
                '<th>Data</th> <td>NoValidKeyInChoices, Alias2</td>',
1438
                'choice',
1439
                ['NoValidKeyInChoices', 'Status2'],
1440
                ['safe' => false, 'choices' => [
1441
                    'Status1' => 'Alias1',
1442
                    'Status2' => 'Alias2',
1443
                    'Status3' => 'Alias3',
1444
                ], 'multiple' => true],
1445
            ],
1446
            [
1447
                '<th>Data</th> <td>Alias1, Alias3</td>',
1448
                'choice',
1449
                ['Status1', 'Status3'],
1450
                ['safe' => false, 'choices' => [
1451
                    'Status1' => 'Alias1',
1452
                    'Status2' => 'Alias2',
1453
                    'Status3' => 'Alias3',
1454
                ], 'multiple' => true],
1455
            ],
1456
            [
1457
                '<th>Data</th> <td>Alias1 | Alias3</td>',
1458
                'choice',
1459
                ['Status1', 'Status3'], ['safe' => false, 'choices' => [
1460
                    'Status1' => 'Alias1',
1461
                    'Status2' => 'Alias2',
1462
                    'Status3' => 'Alias3',
1463
                ], 'multiple' => true, 'delimiter' => ' | '],
1464
            ],
1465
            [
1466
                '<th>Data</th> <td>Delete, Alias3</td>',
1467
                'choice',
1468
                ['Foo', 'Status3'],
1469
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1470
                    'Foo' => 'action_delete',
1471
                    'Status2' => 'Alias2',
1472
                    'Status3' => 'Alias3',
1473
                ], 'multiple' => true],
1474
            ],
1475
            [
1476
                '<th>Data</th> <td><b>Alias1</b>, <b>Alias3</b></td>',
1477
                'choice',
1478
                ['Status1', 'Status3'],
1479
                ['safe' => true, 'choices' => [
1480
                    'Status1' => '<b>Alias1</b>',
1481
                    'Status2' => '<b>Alias2</b>',
1482
                    'Status3' => '<b>Alias3</b>',
1483
                ], 'multiple' => true],
1484
            ],
1485
            [
1486
                '<th>Data</th> <td>&lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;</td>',
1487
                'choice',
1488
                ['Status1', 'Status3'],
1489
                ['safe' => false, 'choices' => [
1490
                    'Status1' => '<b>Alias1</b>',
1491
                    'Status2' => '<b>Alias2</b>',
1492
                    'Status3' => '<b>Alias3</b>',
1493
                ], 'multiple' => true],
1494
            ],
1495
            [
1496
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1497
                'url',
1498
                'http://example.com',
1499
                ['safe' => false],
1500
            ],
1501
            [
1502
                '<th>Data</th> <td><a href="http://example.com" target="_blank">http://example.com</a></td>',
1503
                'url',
1504
                'http://example.com',
1505
                ['safe' => false, 'attributes' => ['target' => '_blank']],
1506
            ],
1507
            [
1508
                '<th>Data</th> <td><a href="http://example.com" target="_blank" class="fooLink">http://example.com</a></td>',
1509
                'url',
1510
                'http://example.com',
1511
                ['safe' => false, 'attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1512
            ],
1513
            [
1514
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1515
                'url',
1516
                'https://example.com',
1517
                ['safe' => false],
1518
            ],
1519
            [
1520
                '<th>Data</th> <td><a href="http://example.com">example.com</a></td>',
1521
                'url',
1522
                'http://example.com',
1523
                ['safe' => false, 'hide_protocol' => true],
1524
            ],
1525
            [
1526
                '<th>Data</th> <td><a href="https://example.com">example.com</a></td>',
1527
                'url',
1528
                'https://example.com',
1529
                ['safe' => false, 'hide_protocol' => true],
1530
            ],
1531
            [
1532
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1533
                'url',
1534
                'http://example.com',
1535
                ['safe' => false, 'hide_protocol' => false],
1536
            ],
1537
            [
1538
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1539
                'url',
1540
                'https://example.com',
1541
                ['safe' => false,
1542
                'hide_protocol' => false, ],
1543
            ],
1544
            [
1545
                '<th>Data</th> <td><a href="http://example.com">Foo</a></td>',
1546
                'url',
1547
                'Foo',
1548
                ['safe' => false, 'url' => 'http://example.com'],
1549
            ],
1550
            [
1551
                '<th>Data</th> <td><a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a></td>',
1552
                'url',
1553
                '<b>Foo</b>',
1554
                ['safe' => false, 'url' => 'http://example.com'],
1555
            ],
1556
            [
1557
                '<th>Data</th> <td><a href="http://example.com"><b>Foo</b></a></td>',
1558
                'url',
1559
                '<b>Foo</b>',
1560
                ['safe' => true, 'url' => 'http://example.com'],
1561
            ],
1562
            [
1563
                '<th>Data</th> <td><a href="/foo">Foo</a></td>',
1564
                'url',
1565
                'Foo',
1566
                ['safe' => false, 'route' => ['name' => 'sonata_admin_foo']],
1567
            ],
1568
            [
1569
                '<th>Data</th> <td><a href="http://localhost/foo">Foo</a></td>',
1570
                'url',
1571
                'Foo',
1572
                ['safe' => false, 'route' => [
1573
                    'name' => 'sonata_admin_foo',
1574
                    'absolute' => true,
1575
                ]],
1576
            ],
1577
            [
1578
                '<th>Data</th> <td><a href="/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1579
                'url',
1580
                'http://foo/bar?a=b&c=123456789',
1581
                [
1582
                    'safe' => false,
1583
                    'route' => ['name' => 'sonata_admin_foo'],
1584
                    'hide_protocol' => true,
1585
                ],
1586
            ],
1587
            [
1588
                '<th>Data</th> <td><a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1589
                'url',
1590
                'http://foo/bar?a=b&c=123456789',
1591
                ['safe' => false, 'route' => [
1592
                    'name' => 'sonata_admin_foo',
1593
                    'absolute' => true,
1594
                ], 'hide_protocol' => true],
1595
            ],
1596
            [
1597
                '<th>Data</th> <td><a href="/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1598
                'url',
1599
                'Foo',
1600
                ['safe' => false, 'route' => [
1601
                    'name' => 'sonata_admin_foo_param',
1602
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1603
                ]],
1604
            ],
1605
            [
1606
                '<th>Data</th> <td><a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1607
                'url',
1608
                'Foo',
1609
                ['safe' => false, 'route' => [
1610
                    'name' => 'sonata_admin_foo_param',
1611
                    'absolute' => true,
1612
                    'parameters' => [
1613
                        'param1' => 'abcd',
1614
                        'param2' => 'efgh',
1615
                        'param3' => 'ijkl',
1616
                    ],
1617
                ]],
1618
            ],
1619
            [
1620
                '<th>Data</th> <td><a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1621
                'url',
1622
                'Foo',
1623
                ['safe' => false, 'route' => [
1624
                    'name' => 'sonata_admin_foo_object',
1625
                    'parameters' => [
1626
                        'param1' => 'abcd',
1627
                        'param2' => 'efgh',
1628
                        'param3' => 'ijkl',
1629
                    ],
1630
                    'identifier_parameter_name' => 'barId',
1631
                ]],
1632
            ],
1633
            [
1634
                '<th>Data</th> <td><a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1635
                'url',
1636
                'Foo',
1637
                ['safe' => false, 'route' => [
1638
                    'name' => 'sonata_admin_foo_object',
1639
                    'absolute' => true,
1640
                    'parameters' => [
1641
                        'param1' => 'abcd',
1642
                        'param2' => 'efgh',
1643
                        'param3' => 'ijkl',
1644
                    ],
1645
                    'identifier_parameter_name' => 'barId',
1646
                ]],
1647
            ],
1648
            [
1649
                '<th>Data</th> <td> &nbsp;</td>',
1650
                'email',
1651
                null,
1652
                [],
1653
            ],
1654
            [
1655
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1656
                'email',
1657
                '[email protected]',
1658
                [],
1659
            ],
1660
            [
1661
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a></td>',
1662
                'email',
1663
                '[email protected]',
1664
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
1665
            ],
1666
            [
1667
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a></td>',
1668
                'email',
1669
                '[email protected]',
1670
                ['subject' => 'Main Theme'],
1671
            ],
1672
            [
1673
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a></td>',
1674
                'email',
1675
                '[email protected]',
1676
                ['body' => 'Message Body'],
1677
            ],
1678
            [
1679
                '<th>Data</th> <td> [email protected]</td>',
1680
                'email',
1681
                '[email protected]',
1682
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
1683
            ],
1684
            [
1685
                '<th>Data</th> <td> [email protected]</td>',
1686
                'email',
1687
                '[email protected]',
1688
                ['as_string' => true, 'subject' => 'Main Theme'],
1689
            ],
1690
            [
1691
                '<th>Data</th> <td> [email protected]</td>',
1692
                'email',
1693
                '[email protected]',
1694
                ['as_string' => true, 'body' => 'Message Body'],
1695
            ],
1696
            [
1697
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1698
                'email',
1699
                '[email protected]',
1700
                ['as_string' => false],
1701
            ],
1702
            [
1703
                '<th>Data</th> <td> [email protected]</td>',
1704
                'email',
1705
                '[email protected]',
1706
                ['as_string' => true],
1707
            ],
1708
            [
1709
                '<th>Data</th> <td><p><strong>Creating a Template for the Field</strong> and form</p> </td>',
1710
                'html',
1711
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1712
                [],
1713
            ],
1714
            [
1715
                '<th>Data</th> <td>Creating a Template for the Field and form </td>',
1716
                'html',
1717
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1718
                ['strip' => true],
1719
            ],
1720
            [
1721
                '<th>Data</th> <td> Creating a Template for the... </td>',
1722
                'html',
1723
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1724
                ['truncate' => true],
1725
            ],
1726
            [
1727
                '<th>Data</th> <td> Creatin... </td>',
1728
                'html',
1729
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1730
                ['truncate' => ['length' => 10]],
1731
            ],
1732
            [
1733
                '<th>Data</th> <td> Creating a Template for the Field... </td>',
1734
                'html',
1735
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1736
                ['truncate' => ['cut' => false]],
1737
            ],
1738
            [
1739
                '<th>Data</th> <td> Creating a Template for t etc. </td>',
1740
                'html',
1741
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1742
                ['truncate' => ['ellipsis' => ' etc.']],
1743
            ],
1744
            [
1745
                '<th>Data</th> <td> Creating a Template[...] </td>',
1746
                'html',
1747
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1748
                [
1749
                    'truncate' => [
1750
                        'length' => 20,
1751
                        'cut' => false,
1752
                        'ellipsis' => '[...]',
1753
                    ],
1754
                ],
1755
            ],
1756
            [
1757
                <<<'EOT'
1758
<th>Data</th> <td><div
1759
        class="sonata-readmore"
1760
        data-readmore-height="40"
1761
        data-readmore-more="Read more"
1762
        data-readmore-less="Close">
1763
            A very long string
1764
</div></td>
1765
EOT
1766
                ,
1767
                'text',
1768
                ' A very long string ',
1769
                [
1770
                    'collapse' => true,
1771
                    'safe' => false,
1772
                ],
1773
            ],
1774
            [
1775
                <<<'EOT'
1776
<th>Data</th> <td><div
1777
        class="sonata-readmore"
1778
        data-readmore-height="10"
1779
        data-readmore-more="More"
1780
        data-readmore-less="Less">
1781
            A very long string
1782
</div></td>
1783
EOT
1784
                ,
1785
                'text',
1786
                ' A very long string ',
1787
                [
1788
                    'collapse' => [
1789
                        'height' => 10,
1790
                        'more' => 'More',
1791
                        'less' => 'Less',
1792
                    ],
1793
                    'safe' => false,
1794
                ],
1795
            ],
1796
        ];
1797
    }
1798
1799
    public function getRenderViewElementWithNoValueTests(): iterable
1800
    {
1801
        return [
1802
            // NoValueException
1803
            ['<th>Data</th> <td></td>', 'string', ['safe' => false]],
1804
            ['<th>Data</th> <td></td>', 'text', ['safe' => false]],
1805
            ['<th>Data</th> <td></td>', 'textarea', ['safe' => false]],
1806
            ['<th>Data</th> <td>&nbsp;</td>', 'datetime', []],
1807
            [
1808
                '<th>Data</th> <td>&nbsp;</td>',
1809
                'datetime',
1810
                ['format' => 'd.m.Y H:i:s'],
1811
            ],
1812
            ['<th>Data</th> <td>&nbsp;</td>', 'date', []],
1813
            ['<th>Data</th> <td>&nbsp;</td>', 'date', ['format' => 'd.m.Y']],
1814
            ['<th>Data</th> <td>&nbsp;</td>', 'time', []],
1815
            ['<th>Data</th> <td></td>', 'number', ['safe' => false]],
1816
            ['<th>Data</th> <td></td>', 'integer', ['safe' => false]],
1817
            ['<th>Data</th> <td> 0 % </td>', 'percent', []],
1818
            ['<th>Data</th> <td> </td>', 'currency', ['currency' => 'EUR']],
1819
            ['<th>Data</th> <td> </td>', 'currency', ['currency' => 'GBP']],
1820
            ['<th>Data</th> <td> <ul></ul> </td>', 'array', ['safe' => false]],
1821
            [
1822
                '<th>Data</th> <td><span class="label label-danger">no</span></td>',
1823
                'boolean',
1824
                [],
1825
            ],
1826
            [
1827
                '<th>Data</th> <td> </td>',
1828
                'trans',
1829
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1830
            ],
1831
            [
1832
                '<th>Data</th> <td></td>',
1833
                'choice',
1834
                ['safe' => false, 'choices' => []],
1835
            ],
1836
            [
1837
                '<th>Data</th> <td></td>',
1838
                'choice',
1839
                ['safe' => false, 'choices' => [], 'multiple' => true],
1840
            ],
1841
            ['<th>Data</th> <td>&nbsp;</td>', 'url', []],
1842
            [
1843
                '<th>Data</th> <td>&nbsp;</td>',
1844
                'url',
1845
                ['url' => 'http://example.com'],
1846
            ],
1847
            [
1848
                '<th>Data</th> <td>&nbsp;</td>',
1849
                'url',
1850
                ['route' => ['name' => 'sonata_admin_foo']],
1851
            ],
1852
        ];
1853
    }
1854
1855
    public function testGetValueFromFieldDescription(): void
1856
    {
1857
        $object = new \stdClass();
1858
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1859
1860
        $fieldDescription
1861
            ->method('getValue')
1862
            ->willReturn('test123');
1863
1864
        $this->assertSame(
1865
            'test123',
1866
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1867
                $this->twigExtension,
1868
                $object,
1869
                $fieldDescription
1870
            )
1871
        );
1872
    }
1873
1874
    public function testGetValueFromFieldDescriptionWithRemoveLoopException(): void
1875
    {
1876
        $object = $this->createMock(\ArrayAccess::class);
1877
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1878
1879
        $this->expectException(\RuntimeException::class);
1880
        $this->expectExceptionMessage('remove the loop requirement');
1881
1882
        $this->assertSame(
1883
            'anything',
1884
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1885
                $this->twigExtension,
1886
                $object,
1887
                $fieldDescription,
1888
                ['loop' => true]
1889
            )
1890
        );
1891
    }
1892
1893
    public function testGetValueFromFieldDescriptionWithNoValueException(): void
1894
    {
1895
        $object = new \stdClass();
1896
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1897
1898
        $fieldDescription
1899
            ->method('getValue')
1900
            ->willReturnCallback(static function (): void {
1901
                throw new NoValueException();
1902
            });
1903
1904
        $fieldDescription
1905
            ->method('getAssociationAdmin')
1906
            ->willReturn(null);
1907
1908
        $this->assertNull(
1909
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1910
                $this->twigExtension,
1911
                $object,
1912
                $fieldDescription
1913
            )
1914
        );
1915
    }
1916
1917
    public function testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance(): void
1918
    {
1919
        $object = new \stdClass();
1920
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1921
1922
        $fieldDescription
1923
            ->method('getValue')
1924
            ->willReturnCallback(static function (): void {
1925
                throw new NoValueException();
1926
            });
1927
1928
        $fieldDescription
1929
            ->method('getAssociationAdmin')
1930
            ->willReturn($this->admin);
1931
1932
        $newInstance = new \stdClass();
1933
1934
        $this->admin->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1935
            ->method('getNewInstance')
1936
            ->willReturn($newInstance);
1937
1938
        $this->assertSame(
1939
            $newInstance,
1940
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1941
                $this->twigExtension,
1942
                $object,
1943
                $fieldDescription
1944
            )
1945
        );
1946
    }
1947
1948
    public function testRenderRelationElementNoObject(): void
1949
    {
1950
        $this->assertSame('foo', $this->twigExtension->renderRelationElement('foo', $this->fieldDescription));
1951
    }
1952
1953
    public function testRenderRelationElementToString(): void
1954
    {
1955
        $this->fieldDescription->expects($this->exactly(2))
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1956
            ->method('getOption')
1957
            ->willReturnCallback(static function ($value, $default = null) {
1958
                if ('associated_property' === $value) {
1959
                    return $default;
1960
                }
1961
            });
1962
1963
        $element = new FooToString();
1964
        $this->assertSame('salut', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
1965
    }
1966
1967
    /**
1968
     * @group legacy
1969
     */
1970
    public function testDeprecatedRelationElementToString(): void
1971
    {
1972
        $this->fieldDescription->expects($this->exactly(2))
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1973
            ->method('getOption')
1974
            ->willReturnCallback(static function ($value, $default = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $default is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1975
                if ('associated_tostring' === $value) {
1976
                    return '__toString';
1977
                }
1978
            });
1979
1980
        $element = new FooToString();
1981
        $this->assertSame(
1982
            'salut',
1983
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
1984
        );
1985
    }
1986
1987
    /**
1988
     * @group legacy
1989
     */
1990
    public function testRenderRelationElementCustomToString(): void
1991
    {
1992
        $this->fieldDescription->expects($this->exactly(2))
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1993
            ->method('getOption')
1994
            ->willReturnCallback(static function ($value, $default = null) {
1995
                if ('associated_property' === $value) {
1996
                    return $default;
1997
                }
1998
1999
                if ('associated_tostring' === $value) {
2000
                    return 'customToString';
2001
                }
2002
            });
2003
2004
        $element = $this->getMockBuilder(\stdClass::class)
2005
            ->setMethods(['customToString'])
2006
            ->getMock();
2007
        $element
2008
            ->method('customToString')
2009
            ->willReturn('fooBar');
2010
2011
        $this->assertSame('fooBar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2012
    }
2013
2014
    /**
2015
     * @group legacy
2016
     */
2017
    public function testRenderRelationElementMethodNotExist(): void
2018
    {
2019
        $this->fieldDescription->expects($this->exactly(2))
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2020
            ->method('getOption')
2021
2022
            ->willReturnCallback(static function ($value, $default = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $default is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2023
                if ('associated_tostring' === $value) {
2024
                    return 'nonExistedMethod';
2025
                }
2026
            });
2027
2028
        $element = new \stdClass();
2029
        $this->expectException(\RuntimeException::class);
2030
        $this->expectExceptionMessage('You must define an `associated_property` option or create a `stdClass::__toString');
2031
2032
        $this->twigExtension->renderRelationElement($element, $this->fieldDescription);
2033
    }
2034
2035
    public function testRenderRelationElementWithPropertyPath(): void
2036
    {
2037
        $this->fieldDescription->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2038
            ->method('getOption')
2039
2040
            ->willReturnCallback(static function ($value, $default = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $default is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2041
                if ('associated_property' === $value) {
2042
                    return 'foo';
2043
                }
2044
            });
2045
2046
        $element = new \stdClass();
2047
        $element->foo = 'bar';
2048
2049
        $this->assertSame('bar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2050
    }
2051
2052
    public function testRenderRelationElementWithClosure(): void
2053
    {
2054
        $this->fieldDescription->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2055
            ->method('getOption')
2056
2057
            ->willReturnCallback(static function ($value, $default = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $default is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2058
                if ('associated_property' === $value) {
2059
                    return static function ($element): string {
2060
                        return 'closure '.$element->foo;
2061
                    };
2062
                }
2063
            });
2064
2065
        $element = new \stdClass();
2066
        $element->foo = 'bar';
2067
2068
        $this->assertSame(
2069
            'closure bar',
2070
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2071
        );
2072
    }
2073
2074
    public function testGetUrlsafeIdentifier(): void
2075
    {
2076
        $entity = new \stdClass();
2077
2078
        // set admin to pool
2079
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
2080
        $this->pool->setAdminClasses([\stdClass::class => ['sonata_admin_foo_service']]);
2081
2082
        $this->admin->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2083
            ->method('getUrlSafeIdentifier')
2084
            ->with($this->equalTo($entity))
2085
            ->willReturn('1234567');
2086
2087
        $this->assertSame('1234567', $this->twigExtension->getUrlSafeIdentifier($entity));
2088
    }
2089
2090
    public function testGetUrlsafeIdentifier_GivenAdmin_Foo(): void
2091
    {
2092
        $entity = new \stdClass();
2093
2094
        // set admin to pool
2095
        $this->pool->setAdminServiceIds([
2096
            'sonata_admin_foo_service',
2097
            'sonata_admin_bar_service',
2098
        ]);
2099
        $this->pool->setAdminClasses([\stdClass::class => [
2100
            'sonata_admin_foo_service',
2101
            'sonata_admin_bar_service',
2102
        ]]);
2103
2104
        $this->admin->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2105
            ->method('getUrlSafeIdentifier')
2106
            ->with($this->equalTo($entity))
2107
            ->willReturn('1234567');
2108
2109
        $this->adminBar->expects($this->never())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2110
            ->method('getUrlSafeIdentifier');
2111
2112
        $this->assertSame('1234567', $this->twigExtension->getUrlSafeIdentifier($entity, $this->admin));
2113
    }
2114
2115
    public function testGetUrlsafeIdentifier_GivenAdmin_Bar(): void
2116
    {
2117
        $entity = new \stdClass();
2118
2119
        // set admin to pool
2120
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service', 'sonata_admin_bar_service']);
2121
        $this->pool->setAdminClasses([\stdClass::class => [
2122
            'sonata_admin_foo_service',
2123
            'sonata_admin_bar_service',
2124
        ]]);
2125
2126
        $this->admin->expects($this->never())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2127
            ->method('getUrlSafeIdentifier');
2128
2129
        $this->adminBar->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2130
            ->method('getUrlSafeIdentifier')
2131
            ->with($this->equalTo($entity))
2132
            ->willReturn('1234567');
2133
2134
        $this->assertSame('1234567', $this->twigExtension->getUrlSafeIdentifier($entity, $this->adminBar));
2135
    }
2136
2137
    public function xEditableChoicesProvider()
2138
    {
2139
        return [
2140
            'needs processing' => [
2141
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2']],
2142
                [
2143
                    ['value' => 'Status1', 'text' => 'Alias1'],
2144
                    ['value' => 'Status2', 'text' => 'Alias2'],
2145
                ],
2146
            ],
2147
            'already processed' => [
2148
                ['choices' => [
2149
                    ['value' => 'Status1', 'text' => 'Alias1'],
2150
                    ['value' => 'Status2', 'text' => 'Alias2'],
2151
                ]],
2152
                [
2153
                    ['value' => 'Status1', 'text' => 'Alias1'],
2154
                    ['value' => 'Status2', 'text' => 'Alias2'],
2155
                ],
2156
            ],
2157
            'not required' => [
2158
                [
2159
                    'required' => false,
2160
                    'choices' => ['' => '', 'Status1' => 'Alias1', 'Status2' => 'Alias2'],
2161
                ],
2162
                [
2163
                    ['value' => '', 'text' => ''],
2164
                    ['value' => 'Status1', 'text' => 'Alias1'],
2165
                    ['value' => 'Status2', 'text' => 'Alias2'],
2166
                ],
2167
            ],
2168
            'not required multiple' => [
2169
                [
2170
                    'required' => false,
2171
                    'multiple' => true,
2172
                    'choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2'],
2173
                ],
2174
                [
2175
                    ['value' => 'Status1', 'text' => 'Alias1'],
2176
                    ['value' => 'Status2', 'text' => 'Alias2'],
2177
                ],
2178
            ],
2179
        ];
2180
    }
2181
2182
    /**
2183
     * @dataProvider xEditablechoicesProvider
2184
     */
2185
    public function testGetXEditableChoicesIsIdempotent(array $options, array $expectedChoices): void
2186
    {
2187
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2188
        $fieldDescription
2189
            ->method('getOption')
2190
            ->withConsecutive(
2191
                ['choices', []],
2192
                ['catalogue'],
2193
                ['required'],
2194
                ['multiple']
2195
            )
2196
            ->will($this->onConsecutiveCalls(
2197
                $options['choices'],
2198
                'MyCatalogue',
2199
                $options['multiple'] ?? null
2200
            ));
2201
2202
        $this->assertSame($expectedChoices, $this->twigExtension->getXEditableChoices($fieldDescription));
2203
    }
2204
2205
    public function select2LocalesProvider()
2206
    {
2207
        return [
2208
            ['ar', 'ar'],
2209
            ['az', 'az'],
2210
            ['bg', 'bg'],
2211
            ['ca', 'ca'],
2212
            ['cs', 'cs'],
2213
            ['da', 'da'],
2214
            ['de', 'de'],
2215
            ['el', 'el'],
2216
            [null, 'en'],
2217
            ['es', 'es'],
2218
            ['et', 'et'],
2219
            ['eu', 'eu'],
2220
            ['fa', 'fa'],
2221
            ['fi', 'fi'],
2222
            ['fr', 'fr'],
2223
            ['gl', 'gl'],
2224
            ['he', 'he'],
2225
            ['hr', 'hr'],
2226
            ['hu', 'hu'],
2227
            ['id', 'id'],
2228
            ['is', 'is'],
2229
            ['it', 'it'],
2230
            ['ja', 'ja'],
2231
            ['ka', 'ka'],
2232
            ['ko', 'ko'],
2233
            ['lt', 'lt'],
2234
            ['lv', 'lv'],
2235
            ['mk', 'mk'],
2236
            ['ms', 'ms'],
2237
            ['nb', 'nb'],
2238
            ['nl', 'nl'],
2239
            ['pl', 'pl'],
2240
            ['pt-PT', 'pt'],
2241
            ['pt-BR', 'pt-BR'],
2242
            ['pt-PT', 'pt-PT'],
2243
            ['ro', 'ro'],
2244
            ['rs', 'rs'],
2245
            ['ru', 'ru'],
2246
            ['sk', 'sk'],
2247
            ['sv', 'sv'],
2248
            ['th', 'th'],
2249
            ['tr', 'tr'],
2250
            ['ug-CN', 'ug'],
2251
            ['ug-CN', 'ug-CN'],
2252
            ['uk', 'uk'],
2253
            ['vi', 'vi'],
2254
            ['zh-CN', 'zh'],
2255
            ['zh-CN', 'zh-CN'],
2256
            ['zh-TW', 'zh-TW'],
2257
        ];
2258
    }
2259
2260
    /**
2261
     * @dataProvider select2LocalesProvider
2262
     */
2263
    public function testCanonicalizedLocaleForSelect2(?string $expected, string $original): void
2264
    {
2265
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForSelect2($this->mockExtensionContext($original)));
2266
    }
2267
2268
    public function momentLocalesProvider(): array
2269
    {
2270
        return [
2271
            ['af', 'af'],
2272
            ['ar-dz', 'ar-dz'],
2273
            ['ar', 'ar'],
2274
            ['ar-ly', 'ar-ly'],
2275
            ['ar-ma', 'ar-ma'],
2276
            ['ar-sa', 'ar-sa'],
2277
            ['ar-tn', 'ar-tn'],
2278
            ['az', 'az'],
2279
            ['be', 'be'],
2280
            ['bg', 'bg'],
2281
            ['bn', 'bn'],
2282
            ['bo', 'bo'],
2283
            ['br', 'br'],
2284
            ['bs', 'bs'],
2285
            ['ca', 'ca'],
2286
            ['cs', 'cs'],
2287
            ['cv', 'cv'],
2288
            ['cy', 'cy'],
2289
            ['da', 'da'],
2290
            ['de-at', 'de-at'],
2291
            ['de', 'de'],
2292
            ['de', 'de-de'],
2293
            ['dv', 'dv'],
2294
            ['el', 'el'],
2295
            [null, 'en'],
2296
            [null, 'en-us'],
2297
            ['en-au', 'en-au'],
2298
            ['en-ca', 'en-ca'],
2299
            ['en-gb', 'en-gb'],
2300
            ['en-ie', 'en-ie'],
2301
            ['en-nz', 'en-nz'],
2302
            ['eo', 'eo'],
2303
            ['es-do', 'es-do'],
2304
            ['es', 'es-ar'],
2305
            ['es', 'es-mx'],
2306
            ['es', 'es'],
2307
            ['et', 'et'],
2308
            ['eu', 'eu'],
2309
            ['fa', 'fa'],
2310
            ['fi', 'fi'],
2311
            ['fo', 'fo'],
2312
            ['fr-ca', 'fr-ca'],
2313
            ['fr-ch', 'fr-ch'],
2314
            ['fr', 'fr-fr'],
2315
            ['fr', 'fr'],
2316
            ['fy', 'fy'],
2317
            ['gd', 'gd'],
2318
            ['gl', 'gl'],
2319
            ['he', 'he'],
2320
            ['hi', 'hi'],
2321
            ['hr', 'hr'],
2322
            ['hu', 'hu'],
2323
            ['hy-am', 'hy-am'],
2324
            ['id', 'id'],
2325
            ['is', 'is'],
2326
            ['it', 'it'],
2327
            ['ja', 'ja'],
2328
            ['jv', 'jv'],
2329
            ['ka', 'ka'],
2330
            ['kk', 'kk'],
2331
            ['km', 'km'],
2332
            ['ko', 'ko'],
2333
            ['ky', 'ky'],
2334
            ['lb', 'lb'],
2335
            ['lo', 'lo'],
2336
            ['lt', 'lt'],
2337
            ['lv', 'lv'],
2338
            ['me', 'me'],
2339
            ['mi', 'mi'],
2340
            ['mk', 'mk'],
2341
            ['ml', 'ml'],
2342
            ['mr', 'mr'],
2343
            ['ms', 'ms'],
2344
            ['ms-my', 'ms-my'],
2345
            ['my', 'my'],
2346
            ['nb', 'nb'],
2347
            ['ne', 'ne'],
2348
            ['nl-be', 'nl-be'],
2349
            ['nl', 'nl'],
2350
            ['nl', 'nl-nl'],
2351
            ['nn', 'nn'],
2352
            ['pa-in', 'pa-in'],
2353
            ['pl', 'pl'],
2354
            ['pt-br', 'pt-br'],
2355
            ['pt', 'pt'],
2356
            ['ro', 'ro'],
2357
            ['ru', 'ru'],
2358
            ['se', 'se'],
2359
            ['si', 'si'],
2360
            ['sk', 'sk'],
2361
            ['sl', 'sl'],
2362
            ['sq', 'sq'],
2363
            ['sr-cyrl', 'sr-cyrl'],
2364
            ['sr', 'sr'],
2365
            ['ss', 'ss'],
2366
            ['sv', 'sv'],
2367
            ['sw', 'sw'],
2368
            ['ta', 'ta'],
2369
            ['te', 'te'],
2370
            ['tet', 'tet'],
2371
            ['th', 'th'],
2372
            ['tlh', 'tlh'],
2373
            ['tl-ph', 'tl-ph'],
2374
            ['tr', 'tr'],
2375
            ['tzl', 'tzl'],
2376
            ['tzm', 'tzm'],
2377
            ['tzm-latn', 'tzm-latn'],
2378
            ['uk', 'uk'],
2379
            ['uz', 'uz'],
2380
            ['vi', 'vi'],
2381
            ['x-pseudo', 'x-pseudo'],
2382
            ['yo', 'yo'],
2383
            ['zh-cn', 'zh-cn'],
2384
            ['zh-hk', 'zh-hk'],
2385
            ['zh-tw', 'zh-tw'],
2386
        ];
2387
    }
2388
2389
    /**
2390
     * @dataProvider momentLocalesProvider
2391
     */
2392
    public function testCanonicalizedLocaleForMoment(?string $expected, string $original): void
2393
    {
2394
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForMoment($this->mockExtensionContext($original)));
2395
    }
2396
2397
    public function testIsGrantedAffirmative(): void
2398
    {
2399
        $this->assertTrue(
2400
            $this->twigExtension->isGrantedAffirmative(['foo', 'bar'])
2401
        );
2402
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('foo'));
2403
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('bar'));
2404
    }
2405
2406
    /**
2407
     * @dataProvider getRenderViewElementCompareTests
2408
     */
2409
    public function testRenderViewElementCompare(string $expected, string $type, $value, array $options, ?string $objectName = null): void
2410
    {
2411
        $this->admin
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2412
            ->method('getTemplate')
2413
            ->willReturn('@SonataAdmin/CRUD/base_show_compare.html.twig');
2414
2415
        $this->fieldDescription
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2416
            ->method('getValue')
2417
            ->willReturn($value);
2418
2419
        $this->fieldDescription
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2420
            ->method('getType')
2421
            ->willReturn($type);
2422
2423
        $this->fieldDescription
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2424
            ->method('getOptions')
2425
            ->willReturn($options);
2426
2427
        $this->fieldDescription
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2428
            ->method('getTemplate')
2429
            ->willReturnCallback(static function () use ($type, $options): ?string {
2430
                if (isset($options['template'])) {
2431
                    return $options['template'];
2432
                }
2433
2434
                switch ($type) {
2435
                    case 'boolean':
2436
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
2437
                    case 'datetime':
2438
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
2439
                    case 'date':
2440
                        return '@SonataAdmin/CRUD/show_date.html.twig';
2441
                    case 'time':
2442
                        return '@SonataAdmin/CRUD/show_time.html.twig';
2443
                    case 'currency':
2444
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
2445
                    case 'percent':
2446
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
2447
                    case 'email':
2448
                        return '@SonataAdmin/CRUD/show_email.html.twig';
2449
                    case 'choice':
2450
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
2451
                    case 'array':
2452
                        return '@SonataAdmin/CRUD/show_array.html.twig';
2453
                    case 'trans':
2454
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
2455
                    case 'url':
2456
                        return '@SonataAdmin/CRUD/show_url.html.twig';
2457
                    case 'html':
2458
                        return '@SonataAdmin/CRUD/show_html.html.twig';
2459
                    default:
2460
                        return null;
2461
                }
2462
            });
2463
2464
        $this->object->name = 'SonataAdmin';
2465
2466
        $comparedObject = clone $this->object;
2467
2468
        if (null !== $objectName) {
2469
            $comparedObject->name = $objectName;
2470
        }
2471
2472
        $this->assertSame(
2473
            $this->removeExtraWhitespace($expected),
2474
            $this->removeExtraWhitespace(
2475
                $this->twigExtension->renderViewElementCompare(
2476
                    $this->environment,
2477
                    $this->fieldDescription,
2478
                    $this->object,
2479
                    $comparedObject
2480
                )
2481
            )
2482
        );
2483
    }
2484
2485
    public function getRenderViewElementCompareTests(): iterable
2486
    {
2487
        return [
2488
            ['<th>Data</th> <td>Example</td><td>Example</td>', 'string', 'Example', ['safe' => false]],
2489
            ['<th>Data</th> <td>Example</td><td>Example</td>', 'text', 'Example', ['safe' => false]],
2490
            ['<th>Data</th> <td>Example</td><td>Example</td>', 'textarea', 'Example', ['safe' => false]],
2491
            ['<th>Data</th> <td>SonataAdmin<br/>Example</td><td>SonataAdmin<br/>Example</td>', 'virtual_field', 'Example', ['template' => 'custom_show_field.html.twig', 'safe' => false, 'SonataAdmin']],
2492
            ['<th class="diff">Data</th> <td>SonataAdmin<br/>Example</td><td>SonataAdmin<br/>Example</td>', 'virtual_field', 'Example', ['template' => 'custom_show_field.html.twig', 'safe' => false], 'sonata-project/admin-bundle'],
2493
            [
2494
                '<th>Data</th> <td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> May 27, 2020 10:11 </time></td>'
2495
                .'<td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> May 27, 2020 10:11 </time></td>',
2496
                'datetime',
2497
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('Europe/London')), [],
2498
            ],
2499
            [
2500
                '<th>Data</th> <td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> 27.05.2020 10:11:12 </time></td>'
2501
                .'<td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> 27.05.2020 10:11:12 </time></td>',
2502
                'datetime',
2503
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('Europe/London')),
2504
                ['format' => 'd.m.Y H:i:s'],
2505
            ],
2506
            [
2507
                '<th>Data</th> <td><time datetime="2020-05-27T10:11:12+00:00" title="2020-05-27T10:11:12+00:00"> May 27, 2020 18:11 </time></td>'
2508
                .'<td><time datetime="2020-05-27T10:11:12+00:00" title="2020-05-27T10:11:12+00:00"> May 27, 2020 18:11 </time></td>',
2509
                'datetime',
2510
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('UTC')),
2511
                ['timezone' => 'Asia/Hong_Kong'],
2512
            ],
2513
            [
2514
                '<th>Data</th> <td><time datetime="2020-05-27" title="2020-05-27"> May 27, 2020 </time></td>'
2515
                .'<td><time datetime="2020-05-27" title="2020-05-27"> May 27, 2020 </time></td>',
2516
                'date',
2517
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('Europe/London')),
2518
                [],
2519
            ],
2520
        ];
2521
    }
2522
2523
    /**
2524
     * This method generates url part for Twig layout.
2525
     */
2526
    private function buildTwigLikeUrl(array $url): string
2527
    {
2528
        return htmlspecialchars(http_build_query($url, '', '&', PHP_QUERY_RFC3986));
2529
    }
2530
2531
    private function getMethodAsPublic($privateMethod): \ReflectionMethod
2532
    {
2533
        $reflection = new \ReflectionMethod('Sonata\AdminBundle\Twig\Extension\SonataAdminExtension', $privateMethod);
2534
        $reflection->setAccessible(true);
2535
2536
        return $reflection;
2537
    }
2538
2539
    private function removeExtraWhitespace(string $string): string
2540
    {
2541
        return trim(preg_replace(
2542
            '/\s+/',
2543
            ' ',
2544
            $string
2545
        ));
2546
    }
2547
2548
    private function mockExtensionContext(string $locale): array
2549
    {
2550
        $request = $this->createMock(Request::class);
2551
        $request->method('getLocale')->willReturn($locale);
2552
        $appVariable = $this->createMock(AppVariable::class);
2553
        $appVariable->method('getRequest')->willReturn($request);
2554
2555
        return ['app' => $appVariable];
2556
    }
2557
}
2558