Completed
Push — 3.x ( b0e4d8...846f8c )
by Grégoire
03:01
created

getDeprecatedTextExtensionItems()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.568
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\AdminBundle\Tests\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\Tests\Fixtures\StubFilesystemLoader;
27
use Sonata\AdminBundle\Twig\Extension\SonataAdminExtension;
28
use Sonata\AdminBundle\Twig\Extension\StringExtension;
29
use Symfony\Bridge\Twig\AppVariable;
30
use Symfony\Bridge\Twig\Extension\RoutingExtension;
31
use Symfony\Bridge\Twig\Extension\TranslationExtension;
32
use Symfony\Component\Config\FileLocator;
33
use Symfony\Component\DependencyInjection\ContainerInterface;
34
use Symfony\Component\HttpFoundation\Request;
35
use Symfony\Component\Routing\Generator\UrlGenerator;
36
use Symfony\Component\Routing\Loader\XmlFileLoader;
37
use Symfony\Component\Routing\RequestContext;
38
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
39
use Symfony\Component\Translation\Loader\XliffFileLoader;
40
use Symfony\Component\Translation\Translator;
41
use Symfony\Component\Translation\TranslatorInterface;
42
use Twig\Environment;
43
use Twig\Error\LoaderError;
44
use Twig\Extensions\TextExtension;
45
46
/**
47
 * Test for SonataAdminExtension.
48
 *
49
 * @author Andrej Hudec <[email protected]>
50
 */
51
class SonataAdminExtensionTest extends TestCase
52
{
53
    /**
54
     * @var SonataAdminExtension
55
     */
56
    private $twigExtension;
57
58
    /**
59
     * @var Environment
60
     */
61
    private $environment;
62
63
    /**
64
     * @var AdminInterface
65
     */
66
    private $admin;
67
68
    /**
69
     * @var AdminInterface
70
     */
71
    private $adminBar;
72
73
    /**
74
     * @var FieldDescriptionInterface
75
     */
76
    private $fieldDescription;
77
78
    /**
79
     * @var \stdClass
80
     */
81
    private $object;
82
83
    /**
84
     * @var Pool
85
     */
86
    private $pool;
87
88
    /**
89
     * @var LoggerInterface
90
     */
91
    private $logger;
92
93
    /**
94
     * @var string[]
95
     */
96
    private $xEditableTypeMapping;
97
98
    /**
99
     * @var TranslatorInterface
100
     */
101
    private $translator;
102
103
    /**
104
     * @var ContainerInterface
105
     */
106
    private $container;
107
108
    /**
109
     * @var TemplateRegistryInterface
110
     */
111
    private $templateRegistry;
112
113
    /**
114
     * @var AuthorizationCheckerInterface
115
     */
116
    private $securityChecker;
117
118
    public function setUp(): void
119
    {
120
        date_default_timezone_set('Europe/London');
121
122
        $container = $this->createMock(ContainerInterface::class);
123
124
        $this->pool = new Pool($container, '', '');
125
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
126
        $this->pool->setAdminClasses(['fooClass' => ['sonata_admin_foo_service']]);
127
128
        $this->logger = $this->getMockForAbstractClass(LoggerInterface::class);
129
        $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...
130
            'choice' => 'select',
131
            'boolean' => 'select',
132
            'text' => 'text',
133
            'textarea' => 'textarea',
134
            'html' => 'textarea',
135
            'email' => 'email',
136
            'string' => 'text',
137
            'smallint' => 'text',
138
            'bigint' => 'text',
139
            'integer' => 'number',
140
            'decimal' => 'number',
141
            'currency' => 'number',
142
            'percent' => 'number',
143
            'url' => 'url',
144
        ];
145
146
        // translation extension
147
        $translator = new Translator('en');
148
        $translator->addLoader('xlf', new XliffFileLoader());
149
        $translator->addResource(
150
            'xlf',
151
            __DIR__.'/../../../src/Resources/translations/SonataAdminBundle.en.xliff',
152
            'en',
153
            'SonataAdminBundle'
154
        );
155
156
        $this->translator = $translator;
157
158
        $this->templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
159
        $this->container = $this->prophesize(ContainerInterface::class);
160
        $this->container->get('sonata_admin_foo_service.template_registry')->willReturn($this->templateRegistry->reveal());
161
162
        $this->securityChecker = $this->prophesize(AuthorizationCheckerInterface::class);
163
        $this->securityChecker->isGranted(['foo', 'bar'], null)->willReturn(false);
164
        $this->securityChecker->isGranted(Argument::type('string'), null)->willReturn(true);
165
166
        $this->twigExtension = new SonataAdminExtension(
167
            $this->pool,
168
            $this->logger,
169
            $this->translator,
170
            $this->container->reveal(),
171
            $this->securityChecker->reveal()
172
        );
173
        $this->twigExtension->setXEditableTypeMapping($this->xEditableTypeMapping);
174
175
        $request = $this->createMock(Request::class);
176
        $request->method('get')->with('_sonata_admin')->willReturn('sonata_admin_foo_service');
177
178
        $loader = new StubFilesystemLoader([
179
            __DIR__.'/../../../src/Resources/views/CRUD',
180
        ]);
181
        $loader->addPath(__DIR__.'/../../../src/Resources/views/', 'SonataAdmin');
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 TextExtension());
205
        $this->environment->addExtension(new StringExtension());
206
207
        // initialize object
208
        $this->object = new \stdClass();
209
210
        // initialize admin
211
        $this->admin = $this->createMock(AbstractAdmin::class);
212
213
        $this->admin
214
            ->method('getCode')
215
            ->willReturn('sonata_admin_foo_service');
216
217
        $this->admin
218
            ->method('id')
219
            ->with($this->equalTo($this->object))
220
            ->willReturn(12345);
221
222
        $this->admin
223
            ->method('getNormalizedIdentifier')
224
            ->with($this->equalTo($this->object))
225
            ->willReturn(12345);
226
227
        $this->admin
228
            ->method('trans')
229
            ->willReturnCallback(static function ($id, $parameters = [], $domain = null) use ($translator) {
230
                return $translator->trans($id, $parameters, $domain);
231
            });
232
233
        $this->adminBar = $this->createMock(AbstractAdmin::class);
234
        $this->adminBar
235
            ->method('hasAccess')
236
            ->willReturn(true);
237
        $this->adminBar
238
            ->method('getNormalizedIdentifier')
239
            ->with($this->equalTo($this->object))
240
            ->willReturn(12345);
241
242
        $container
243
            ->method('get')
244
            ->willReturnCallback(function (string $id) {
245
                if ('sonata_admin_foo_service' === $id) {
246
                    return $this->admin;
247
                }
248
249
                if ('sonata_admin_bar_service' === $id) {
250
                    return $this->adminBar;
251
                }
252
            });
253
254
        // initialize field description
255
        $this->fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
256
257
        $this->fieldDescription
258
            ->method('getName')
259
            ->willReturn('fd_name');
260
261
        $this->fieldDescription
262
            ->method('getAdmin')
263
            ->willReturn($this->admin);
264
265
        $this->fieldDescription
266
            ->method('getLabel')
267
            ->willReturn('Data');
268
    }
269
270
    /**
271
     * @group legacy
272
     * @expectedDeprecation The Sonata\AdminBundle\Admin\AbstractAdmin::getTemplate method is deprecated (since sonata-project/admin-bundle 3.34, will be dropped in 4.0. Use TemplateRegistry services instead).
273
     * @dataProvider getRenderListElementTests
274
     */
275
    public function testRenderListElement(string $expected, string $type, $value, array $options): void
276
    {
277
        $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...
278
            ->method('getPersistentParameters')
279
            ->willReturn(['context' => 'foo']);
280
281
        $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...
282
            ->method('hasAccess')
283
            ->willReturn(true);
284
285
        // NEXT_MAJOR: Remove this line
286
        $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...
287
            ->method('getTemplate')
288
            ->with('base_list_field')
289
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
290
291
        $this->templateRegistry->getTemplate('base_list_field')->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
0 ignored issues
show
Bug introduced by
The method willReturn cannot be called on $this->templateRegistry-...late('base_list_field') (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
292
293
        $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...
294
            ->method('getValue')
295
            ->willReturn($value);
296
297
        $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...
298
            ->method('getType')
299
            ->willReturn($type);
300
301
        $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...
302
            ->method('getOptions')
303
            ->willReturn($options);
304
305
        $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...
306
            ->method('getOption')
307
            ->willReturnCallback(static function ($name, $default = null) use ($options) {
308
                return $options[$name] ?? $default;
309
            });
310
311
        $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...
312
            ->method('getTemplate')
313
            ->willReturnCallback(static function () use ($type) {
314
                switch ($type) {
315
                    case 'string':
316
                        return '@SonataAdmin/CRUD/list_string.html.twig';
317
                    case 'boolean':
318
                        return '@SonataAdmin/CRUD/list_boolean.html.twig';
319
                    case 'datetime':
320
                        return '@SonataAdmin/CRUD/list_datetime.html.twig';
321
                    case 'date':
322
                        return '@SonataAdmin/CRUD/list_date.html.twig';
323
                    case 'time':
324
                        return '@SonataAdmin/CRUD/list_time.html.twig';
325
                    case 'currency':
326
                        return '@SonataAdmin/CRUD/list_currency.html.twig';
327
                    case 'percent':
328
                        return '@SonataAdmin/CRUD/list_percent.html.twig';
329
                    case 'email':
330
                        return '@SonataAdmin/CRUD/list_email.html.twig';
331
                    case 'choice':
332
                        return '@SonataAdmin/CRUD/list_choice.html.twig';
333
                    case 'array':
334
                        return '@SonataAdmin/CRUD/list_array.html.twig';
335
                    case 'trans':
336
                        return '@SonataAdmin/CRUD/list_trans.html.twig';
337
                    case 'url':
338
                        return '@SonataAdmin/CRUD/list_url.html.twig';
339
                    case 'html':
340
                        return '@SonataAdmin/CRUD/list_html.html.twig';
341
                    case 'nonexistent':
342
                        // template doesn`t exist
343
                        return '@SonataAdmin/CRUD/list_nonexistent_template.html.twig';
344
                    default:
345
                        return false;
346
                }
347
            });
348
349
        $this->assertSame(
350
            $this->removeExtraWhitespace($expected),
351
            $this->removeExtraWhitespace($this->twigExtension->renderListElement(
352
                $this->environment,
353
                $this->object,
354
                $this->fieldDescription
355
            ))
356
        );
357
    }
358
359
    /**
360
     * @dataProvider getDeprecatedRenderListElementTests
361
     * @group legacy
362
     */
363
    public function testDeprecatedRenderListElement(string $expected, ?string $value, array $options): void
364
    {
365
        $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...
366
            ->method('hasAccess')
367
            ->willReturn(true);
368
369
        // NEXT_MAJOR: Remove this line
370
        $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...
371
            ->method('getTemplate')
372
            ->with('base_list_field')
373
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
374
375
        $this->templateRegistry->getTemplate('base_list_field')->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
0 ignored issues
show
Bug introduced by
The method willReturn cannot be called on $this->templateRegistry-...late('base_list_field') (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
376
377
        $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...
378
            ->method('getValue')
379
            ->willReturn($value);
380
381
        $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...
382
            ->method('getType')
383
            ->willReturn('nonexistent');
384
385
        $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...
386
            ->method('getOptions')
387
            ->willReturn($options);
388
389
        $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...
390
            ->method('getOption')
391
            ->willReturnCallback(static function ($name, $default = null) use ($options) {
392
                return $options[$name] ?? $default;
393
            });
394
395
        $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...
396
            ->method('getTemplate')
397
            ->willReturn('@SonataAdmin/CRUD/list_nonexistent_template.html.twig');
398
399
        $this->assertSame(
400
            $this->removeExtraWhitespace($expected),
401
            $this->removeExtraWhitespace($this->twigExtension->renderListElement(
402
                $this->environment,
403
                $this->object,
404
                $this->fieldDescription
405
            ))
406
        );
407
    }
408
409
    public function getDeprecatedRenderListElementTests()
410
    {
411
        return [
412
            [
413
                '<td class="sonata-ba-list-field sonata-ba-list-field-nonexistent" objectId="12345"> Example </td>',
414
                'Example',
415
                [],
416
            ],
417
            [
418
                '<td class="sonata-ba-list-field sonata-ba-list-field-nonexistent" objectId="12345"> </td>',
419
                null,
420
                [],
421
            ],
422
        ];
423
    }
424
425
    public function getRenderListElementTests()
426
    {
427
        return [
428
            [
429
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> Example </td>',
430
                'string',
431
                'Example',
432
                [],
433
            ],
434
            [
435
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> </td>',
436
                'string',
437
                null,
438
                [],
439
            ],
440
            [
441
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> Example </td>',
442
                'text',
443
                'Example',
444
                [],
445
            ],
446
            [
447
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> </td>',
448
                'text',
449
                null,
450
                [],
451
            ],
452
            [
453
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> Example </td>',
454
                'textarea',
455
                'Example',
456
                [],
457
            ],
458
            [
459
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> </td>',
460
                'textarea',
461
                null,
462
                [],
463
            ],
464
            'datetime field' => [
465
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
466
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
467
                        December 24, 2013 10:11
468
                    </time>
469
                </td>',
470
                'datetime',
471
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
472
                [],
473
            ],
474
            [
475
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
476
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
477
                        December 24, 2013 18:11
478
                    </time>
479
                </td>',
480
                'datetime',
481
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
482
                ['timezone' => 'Asia/Hong_Kong'],
483
            ],
484
            [
485
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
486
                'datetime',
487
                null,
488
                [],
489
            ],
490
            [
491
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
492
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
493
                        24.12.2013 10:11:12
494
                    </time>
495
                </td>',
496
                'datetime',
497
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
498
                ['format' => 'd.m.Y H:i:s'],
499
            ],
500
            [
501
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
502
                'datetime',
503
                null,
504
                ['format' => 'd.m.Y H:i:s'],
505
            ],
506
            [
507
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
508
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
509
                        24.12.2013 18:11:12
510
                    </time>
511
                </td>',
512
                'datetime',
513
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
514
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
515
            ],
516
            [
517
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
518
                'datetime',
519
                null,
520
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
521
            ],
522
            [
523
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345">
524
                    <time datetime="2013-12-24" title="2013-12-24">
525
                        December 24, 2013
526
                    </time>
527
                </td>',
528
                'date',
529
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
530
                [],
531
            ],
532
            [
533
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
534
                'date',
535
                null,
536
                [],
537
            ],
538
            [
539
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345">
540
                    <time datetime="2013-12-24" title="2013-12-24">
541
                        24.12.2013
542
                    </time>
543
                </td>',
544
                'date',
545
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
546
                ['format' => 'd.m.Y'],
547
            ],
548
            [
549
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
550
                'date',
551
                null,
552
                ['format' => 'd.m.Y'],
553
            ],
554
            [
555
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345">
556
                    <time datetime="10:11:12+00:00" title="10:11:12+00:00">
557
                        10:11:12
558
                    </time>
559
                </td>',
560
                'time',
561
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
562
                [],
563
            ],
564
            [
565
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345">
566
                    <time datetime="10:11:12+00:00" title="10:11:12+00:00">
567
                        18:11:12
568
                    </time>
569
                </td>',
570
                'time',
571
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
572
                ['timezone' => 'Asia/Hong_Kong'],
573
            ],
574
            [
575
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> &nbsp; </td>',
576
                'time',
577
                null,
578
                [],
579
            ],
580
            [
581
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> 10.746135 </td>',
582
                'number', 10.746135,
583
                [],
584
            ],
585
            [
586
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> </td>',
587
                'number',
588
                null,
589
                [],
590
            ],
591
            [
592
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> 5678 </td>',
593
                'integer',
594
                5678,
595
                [],
596
            ],
597
            [
598
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> </td>',
599
                'integer',
600
                null,
601
                [],
602
            ],
603
            [
604
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 1074.6135 % </td>',
605
                'percent',
606
                10.746135,
607
                [],
608
            ],
609
            [
610
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 0 % </td>',
611
                'percent',
612
                null,
613
                [],
614
            ],
615
            [
616
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> EUR 10.746135 </td>',
617
                'currency',
618
                10.746135,
619
                ['currency' => 'EUR'],
620
            ],
621
            [
622
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
623
                'currency',
624
                null,
625
                ['currency' => 'EUR'],
626
            ],
627
            [
628
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> GBP 51.23456 </td>',
629
                'currency',
630
                51.23456,
631
                ['currency' => 'GBP'],
632
            ],
633
            [
634
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
635
                'currency',
636
                null,
637
                ['currency' => 'GBP'],
638
            ],
639
            [
640
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> &nbsp; </td>',
641
                'email',
642
                null,
643
                [],
644
            ],
645
            [
646
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> <a href="mailto:[email protected]">[email protected]</a> </td>',
647
                'email',
648
                '[email protected]',
649
                [],
650
            ],
651
            [
652
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
653
                    <a href="mailto:[email protected]">[email protected]</a> </td>',
654
                'email',
655
                '[email protected]',
656
                ['as_string' => false],
657
            ],
658
            [
659
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
660
                'email',
661
                '[email protected]',
662
                ['as_string' => true],
663
            ],
664
            [
665
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
666
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a>  </td>',
667
                'email',
668
                '[email protected]',
669
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
670
            ],
671
            [
672
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
673
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a>  </td>',
674
                'email',
675
                '[email protected]',
676
                ['subject' => 'Main Theme'],
677
            ],
678
            [
679
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
680
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a>  </td>',
681
                'email',
682
                '[email protected]',
683
                ['body' => 'Message Body'],
684
            ],
685
            [
686
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
687
                'email',
688
                '[email protected]',
689
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
690
            ],
691
            [
692
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
693
                'email',
694
                '[email protected]',
695
                ['as_string' => true, 'body' => 'Message Body'],
696
            ],
697
            [
698
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
699
                'email',
700
                '[email protected]',
701
                ['as_string' => true, 'subject' => 'Main Theme'],
702
            ],
703
            [
704
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345">
705
                    [1 => First] [2 => Second]
706
                </td>',
707
                'array',
708
                [1 => 'First', 2 => 'Second'],
709
                [],
710
            ],
711
            [
712
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345"> </td>',
713
                'array',
714
                null,
715
                [],
716
            ],
717
            [
718
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
719
                    <span class="label label-success">yes</span>
720
                </td>',
721
                'boolean',
722
                true,
723
                ['editable' => false],
724
            ],
725
            [
726
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
727
                    <span class="label label-danger">no</span>
728
                </td>',
729
                'boolean',
730
                false,
731
                ['editable' => false],
732
            ],
733
            [
734
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
735
                    <span class="label label-danger">no</span>
736
                </td>',
737
                'boolean',
738
                null,
739
                ['editable' => false],
740
            ],
741
            [
742
                <<<'EOT'
743
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
744
    <span
745
        class="x-editable"
746
        data-type="select"
747
        data-value="1"
748
        data-title="Data"
749
        data-pk="12345"
750
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
751
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
752
    >
753
        <span class="label label-success">yes</span>
754
    </span>
755
</td>
756
EOT
757
            ,
758
                'boolean',
759
                true,
760
                ['editable' => true],
761
            ],
762
            [
763
                <<<'EOT'
764
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
765
    <span
766
        class="x-editable"
767
        data-type="select"
768
        data-value="0"
769
        data-title="Data"
770
        data-pk="12345"
771
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
772
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
773
    >
774
    <span class="label label-danger">no</span> </span>
775
</td>
776
EOT
777
                ,
778
                'boolean',
779
                false,
780
                ['editable' => true],
781
            ],
782
            [
783
                <<<'EOT'
784
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
785
    <span
786
        class="x-editable"
787
        data-type="select"
788
        data-value="0"
789
        data-title="Data"
790
        data-pk="12345"
791
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
792
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]" >
793
        <span class="label label-danger">no</span> </span>
794
</td>
795
EOT
796
                ,
797
                'boolean',
798
                null,
799
                ['editable' => true],
800
            ],
801
            [
802
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
803
                'trans',
804
                'action_delete',
805
                ['catalogue' => 'SonataAdminBundle'],
806
            ],
807
            [
808
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> </td>',
809
                'trans',
810
                null,
811
                ['catalogue' => 'SonataAdminBundle'],
812
            ],
813
            [
814
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
815
                'trans',
816
                'action_delete',
817
                ['format' => '%s', 'catalogue' => 'SonataAdminBundle'],
818
            ],
819
            [
820
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
821
                action.action_delete
822
                </td>',
823
                'trans',
824
                'action_delete',
825
                ['format' => 'action.%s'],
826
            ],
827
            [
828
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
829
                action.action_delete
830
                </td>',
831
                'trans',
832
                'action_delete',
833
                ['format' => 'action.%s', 'catalogue' => 'SonataAdminBundle'],
834
            ],
835
            [
836
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
837
                'choice',
838
                'Status1',
839
                [],
840
            ],
841
            [
842
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
843
                'choice',
844
                ['Status1'],
845
                ['choices' => [], 'multiple' => true],
846
            ],
847
            [
848
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 </td>',
849
                'choice',
850
                'Status1',
851
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
852
            ],
853
            [
854
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
855
                'choice',
856
                null,
857
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
858
            ],
859
            [
860
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
861
                NoValidKeyInChoices
862
                </td>',
863
                'choice',
864
                'NoValidKeyInChoices',
865
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
866
            ],
867
            [
868
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete </td>',
869
                'choice',
870
                'Foo',
871
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
872
                    'Foo' => 'action_delete',
873
                    'Status2' => 'Alias2',
874
                    'Status3' => 'Alias3',
875
                ]],
876
            ],
877
            [
878
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1, Alias3 </td>',
879
                'choice',
880
                ['Status1', 'Status3'],
881
                ['choices' => [
882
                    'Status1' => 'Alias1',
883
                    'Status2' => 'Alias2',
884
                    'Status3' => 'Alias3',
885
                ], 'multiple' => true], ],
886
            [
887
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 | Alias3 </td>',
888
                'choice',
889
                ['Status1', 'Status3'],
890
                ['choices' => [
891
                    'Status1' => 'Alias1',
892
                    'Status2' => 'Alias2',
893
                    'Status3' => 'Alias3',
894
                ], 'multiple' => true, 'delimiter' => ' | '], ],
895
            [
896
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
897
                'choice',
898
                null,
899
                ['choices' => [
900
                    'Status1' => 'Alias1',
901
                    'Status2' => 'Alias2',
902
                    'Status3' => 'Alias3',
903
                ], 'multiple' => true],
904
            ],
905
            [
906
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
907
                NoValidKeyInChoices
908
                </td>',
909
                'choice',
910
                ['NoValidKeyInChoices'],
911
                ['choices' => [
912
                    'Status1' => 'Alias1',
913
                    'Status2' => 'Alias2',
914
                    'Status3' => 'Alias3',
915
                ], 'multiple' => true],
916
            ],
917
            [
918
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
919
                NoValidKeyInChoices, Alias2
920
                </td>',
921
                'choice',
922
                ['NoValidKeyInChoices', 'Status2'],
923
                ['choices' => [
924
                    'Status1' => 'Alias1',
925
                    'Status2' => 'Alias2',
926
                    'Status3' => 'Alias3',
927
                ], 'multiple' => true],
928
            ],
929
            [
930
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete, Alias3 </td>',
931
                'choice',
932
                ['Foo', 'Status3'],
933
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
934
                    'Foo' => 'action_delete',
935
                    'Status2' => 'Alias2',
936
                    'Status3' => 'Alias3',
937
                ], 'multiple' => true],
938
            ],
939
            [
940
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
941
                &lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;
942
            </td>',
943
                'choice',
944
                ['Status1', 'Status3'],
945
                ['choices' => [
946
                    'Status1' => '<b>Alias1</b>',
947
                    'Status2' => '<b>Alias2</b>',
948
                    'Status3' => '<b>Alias3</b>',
949
                ], 'multiple' => true], ],
950
            [
951
                <<<'EOT'
952
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
953
    <span
954
        class="x-editable"
955
        data-type="select"
956
        data-value="Status1"
957
        data-title="Data"
958
        data-pk="12345"
959
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
960
        data-source="[]"
961
    >
962
        Status1
963
    </span>
964
</td>
965
EOT
966
                ,
967
                'choice',
968
                'Status1',
969
                ['editable' => true],
970
            ],
971
            [
972
                <<<'EOT'
973
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
974
    <span
975
        class="x-editable"
976
        data-type="select"
977
        data-value="Status1"
978
        data-title="Data"
979
        data-pk="12345"
980
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
981
        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;}]" >
982
        Alias1 </span>
983
</td>
984
EOT
985
                ,
986
                'choice',
987
                'Status1',
988
                [
989
                    'editable' => true,
990
                    'choices' => [
991
                        'Status1' => 'Alias1',
992
                        'Status2' => 'Alias2',
993
                        'Status3' => 'Alias3',
994
                    ],
995
                ],
996
            ],
997
            [
998
                <<<'EOT'
999
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1000
    <span
1001
        class="x-editable"
1002
        data-type="select"
1003
        data-value=""
1004
        data-title="Data"
1005
        data-pk="12345"
1006
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1007
        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;}]" >
1008
1009
    </span>
1010
</td>
1011
EOT
1012
                ,
1013
                'choice',
1014
                null,
1015
                [
1016
                    'editable' => true,
1017
                    'choices' => [
1018
                        'Status1' => 'Alias1',
1019
                        'Status2' => 'Alias2',
1020
                        'Status3' => 'Alias3',
1021
                    ],
1022
                ],
1023
            ],
1024
            [
1025
                <<<'EOT'
1026
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1027
    <span
1028
        class="x-editable"
1029
        data-type="select"
1030
        data-value="NoValidKeyInChoices"
1031
        data-title="Data" data-pk="12345"
1032
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1033
        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;}]" >
1034
        NoValidKeyInChoices
1035
    </span>
1036
</td>
1037
EOT
1038
                ,
1039
                'choice',
1040
                'NoValidKeyInChoices',
1041
                [
1042
                    'editable' => true,
1043
                    'choices' => [
1044
                        'Status1' => 'Alias1',
1045
                        'Status2' => 'Alias2',
1046
                        'Status3' => 'Alias3',
1047
                    ],
1048
                ],
1049
            ],
1050
            [
1051
                <<<'EOT'
1052
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1053
    <span
1054
        class="x-editable"
1055
        data-type="select"
1056
        data-value="Foo"
1057
        data-title="Data"
1058
        data-pk="12345"
1059
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1060
        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;}]" >
1061
         Delete
1062
    </span>
1063
</td>
1064
EOT
1065
                ,
1066
                'choice',
1067
                'Foo',
1068
                [
1069
                    'editable' => true,
1070
                    'catalogue' => 'SonataAdminBundle',
1071
                    'choices' => [
1072
                        'Foo' => 'action_delete',
1073
                        'Status2' => 'Alias2',
1074
                        'Status3' => 'Alias3',
1075
                    ],
1076
                ],
1077
            ],
1078
            [
1079
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1080
                'url',
1081
                null,
1082
                [],
1083
            ],
1084
            [
1085
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1086
                'url',
1087
                null,
1088
                ['url' => 'http://example.com'],
1089
            ],
1090
            [
1091
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1092
                'url',
1093
                null,
1094
                ['route' => ['name' => 'sonata_admin_foo']],
1095
            ],
1096
            [
1097
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1098
                <a href="http://example.com">http://example.com</a>
1099
                </td>',
1100
                'url',
1101
                'http://example.com',
1102
                [],
1103
            ],
1104
            [
1105
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1106
                <a href="https://example.com">https://example.com</a>
1107
                </td>',
1108
                'url',
1109
                'https://example.com',
1110
                [],
1111
            ],
1112
            [
1113
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1114
                <a href="https://example.com" target="_blank">https://example.com</a>
1115
                </td>',
1116
                'url',
1117
                'https://example.com',
1118
                ['attributes' => ['target' => '_blank']],
1119
            ],
1120
            [
1121
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1122
                <a href="https://example.com" target="_blank" class="fooLink">https://example.com</a>
1123
                </td>',
1124
                'url',
1125
                'https://example.com',
1126
                ['attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1127
            ],
1128
            [
1129
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1130
                <a href="http://example.com">example.com</a>
1131
                </td>',
1132
                'url',
1133
                'http://example.com',
1134
                ['hide_protocol' => true],
1135
            ],
1136
            [
1137
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1138
                <a href="https://example.com">example.com</a>
1139
                </td>',
1140
                'url',
1141
                'https://example.com',
1142
                ['hide_protocol' => true],
1143
            ],
1144
            [
1145
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1146
                <a href="http://example.com">http://example.com</a>
1147
                </td>',
1148
                'url',
1149
                'http://example.com',
1150
                ['hide_protocol' => false],
1151
            ],
1152
            [
1153
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1154
                <a href="https://example.com">https://example.com</a>
1155
                </td>',
1156
                'url',
1157
                'https://example.com',
1158
                ['hide_protocol' => false],
1159
            ],
1160
            [
1161
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1162
                <a href="http://example.com">Foo</a>
1163
                </td>',
1164
                'url',
1165
                'Foo',
1166
                ['url' => 'http://example.com'],
1167
            ],
1168
            [
1169
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1170
                <a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a>
1171
                </td>',
1172
                'url',
1173
                '<b>Foo</b>',
1174
                ['url' => 'http://example.com'],
1175
            ],
1176
            [
1177
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1178
                <a href="/foo">Foo</a>
1179
                </td>',
1180
                'url',
1181
                'Foo',
1182
                ['route' => ['name' => 'sonata_admin_foo']],
1183
            ],
1184
            [
1185
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1186
                <a href="http://localhost/foo">Foo</a>
1187
                </td>',
1188
                'url',
1189
                'Foo',
1190
                ['route' => ['name' => 'sonata_admin_foo', 'absolute' => true]],
1191
            ],
1192
            [
1193
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1194
                <a href="/foo">foo/bar?a=b&amp;c=123456789</a>
1195
                </td>',
1196
                'url',
1197
                'http://foo/bar?a=b&c=123456789',
1198
                ['route' => ['name' => 'sonata_admin_foo'],
1199
                'hide_protocol' => true, ],
1200
            ],
1201
            [
1202
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1203
                <a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a>
1204
                </td>',
1205
                'url',
1206
                'http://foo/bar?a=b&c=123456789',
1207
                [
1208
                    'route' => ['name' => 'sonata_admin_foo', 'absolute' => true],
1209
                    'hide_protocol' => true,
1210
                ],
1211
            ],
1212
            [
1213
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1214
                <a href="/foo/abcd/efgh?param3=ijkl">Foo</a>
1215
                </td>',
1216
                'url',
1217
                'Foo',
1218
                [
1219
                    'route' => ['name' => 'sonata_admin_foo_param',
1220
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1221
                ],
1222
            ],
1223
            [
1224
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1225
                <a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a>
1226
                </td>',
1227
                'url',
1228
                'Foo',
1229
                [
1230
                    'route' => ['name' => 'sonata_admin_foo_param',
1231
                    'absolute' => true,
1232
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1233
                ],
1234
            ],
1235
            [
1236
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1237
                <a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1238
                </td>',
1239
                'url',
1240
                'Foo',
1241
                [
1242
                    'route' => ['name' => 'sonata_admin_foo_object',
1243
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1244
                    'identifier_parameter_name' => 'barId', ],
1245
                ],
1246
            ],
1247
            [
1248
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1249
                <a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1250
                </td>',
1251
                'url',
1252
                'Foo',
1253
                [
1254
                    'route' => ['name' => 'sonata_admin_foo_object',
1255
                    'absolute' => true,
1256
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1257
                    'identifier_parameter_name' => 'barId', ],
1258
                ],
1259
            ],
1260
            [
1261
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1262
                <p><strong>Creating a Template for the Field</strong> and form</p>
1263
                </td>',
1264
                'html',
1265
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1266
                [],
1267
            ],
1268
            [
1269
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1270
                Creating a Template for the Field and form
1271
                </td>',
1272
                'html',
1273
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1274
                ['strip' => true],
1275
            ],
1276
            [
1277
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1278
                Creating a Template for the...
1279
                </td>',
1280
                'html',
1281
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1282
                ['truncate' => true],
1283
            ],
1284
            [
1285
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345"> Creatin... </td>',
1286
                'html',
1287
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1288
                ['truncate' => ['length' => 10]],
1289
            ],
1290
            [
1291
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1292
                Creating a Template for the Field...
1293
                </td>',
1294
                'html',
1295
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1296
                ['truncate' => ['cut' => false]],
1297
            ],
1298
            [
1299
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1300
                Creating a Template for t etc.
1301
                </td>',
1302
                'html',
1303
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1304
                ['truncate' => ['ellipsis' => ' etc.']],
1305
            ],
1306
            [
1307
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1308
                Creating a Template[...]
1309
                </td>',
1310
                'html',
1311
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1312
                [
1313
                    'truncate' => [
1314
                        'length' => 20,
1315
                        'cut' => false,
1316
                        'ellipsis' => '[...]',
1317
                    ],
1318
                ],
1319
            ],
1320
1321
            [
1322
                <<<'EOT'
1323
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1324
<div
1325
    class="sonata-readmore"
1326
    data-readmore-height="40"
1327
    data-readmore-more="Read more"
1328
    data-readmore-less="Close">A very long string</div>
1329
</td>
1330
EOT
1331
                ,
1332
                'text',
1333
                'A very long string',
1334
                [
1335
                    'collapse' => true,
1336
                ],
1337
            ],
1338
            [
1339
                <<<'EOT'
1340
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1341
<div
1342
    class="sonata-readmore"
1343
    data-readmore-height="10"
1344
    data-readmore-more="More"
1345
    data-readmore-less="Less">A very long string</div>
1346
</td>
1347
EOT
1348
                ,
1349
                'text',
1350
                'A very long string',
1351
                [
1352
                    'collapse' => [
1353
                        'height' => 10,
1354
                        'more' => 'More',
1355
                        'less' => 'Less',
1356
                    ],
1357
                ],
1358
            ],
1359
            [
1360
                <<<'EOT'
1361
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1362
    <span
1363
        class="x-editable"
1364
        data-type="checklist"
1365
        data-value="[&quot;Status1&quot;,&quot;Status2&quot;]"
1366
        data-title="Data"
1367
        data-pk="12345"
1368
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1369
        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;}]" >
1370
         Delete, Alias2
1371
    </span>
1372
</td>
1373
EOT
1374
                ,
1375
                'choice',
1376
                [
1377
                    'Status1',
1378
                    'Status2',
1379
                ],
1380
                [
1381
                    'editable' => true,
1382
                    'multiple' => true,
1383
                    'catalogue' => 'SonataAdminBundle',
1384
                    'choices' => [
1385
                        'Status1' => 'action_delete',
1386
                        'Status2' => 'Alias2',
1387
                        'Status3' => 'Alias3',
1388
                    ],
1389
                ],
1390
            ],
1391
        ];
1392
    }
1393
1394
    /**
1395
     * @group legacy
1396
     */
1397
    public function testRenderListElementNonExistentTemplate(): void
1398
    {
1399
        // NEXT_MAJOR: Remove this line
1400
        $this->admin->method('getTemplate')
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...
1401
            ->with('base_list_field')
1402
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
1403
1404
        $this->templateRegistry->getTemplate('base_list_field')->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
0 ignored issues
show
Bug introduced by
The method willReturn cannot be called on $this->templateRegistry-...late('base_list_field') (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1405
1406
        $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...
1407
            ->method('getValue')
1408
            ->willReturn('Foo');
1409
1410
        $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...
1411
            ->method('getFieldName')
1412
            ->willReturn('Foo_name');
1413
1414
        $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...
1415
            ->method('getType')
1416
            ->willReturn('nonexistent');
1417
1418
        $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...
1419
            ->method('getTemplate')
1420
            ->willReturn('@SonataAdmin/CRUD/list_nonexistent_template.html.twig');
1421
1422
        $this->logger->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Psr\Log\LoggerInterface>.

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...
1423
            ->method('warning')
1424
            ->with(($this->stringStartsWith($this->removeExtraWhitespace(
1425
                'An error occured trying to load the template
1426
                "@SonataAdmin/CRUD/list_nonexistent_template.html.twig"
1427
                for the field "Foo_name", the default template
1428
                    "@SonataAdmin/CRUD/base_list_field.html.twig" was used
1429
                    instead.'
1430
            ))));
1431
1432
        $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription);
1433
    }
1434
1435
    /**
1436
     * @group                    legacy
1437
     */
1438
    public function testRenderListElementErrorLoadingTemplate(): void
1439
    {
1440
        $this->expectException(LoaderError::class);
1441
        $this->expectExceptionMessage('Unable to find template "@SonataAdmin/CRUD/base_list_nonexistent_field.html.twig"');
1442
1443
        // NEXT_MAJOR: Remove this line
1444
        $this->admin->method('getTemplate')
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...
1445
            ->with('base_list_field')
1446
            ->willReturn('@SonataAdmin/CRUD/base_list_nonexistent_field.html.twig');
1447
1448
        $this->templateRegistry->getTemplate('base_list_field')->willReturn('@SonataAdmin/CRUD/base_list_nonexistent_field.html.twig');
0 ignored issues
show
Bug introduced by
The method willReturn cannot be called on $this->templateRegistry-...late('base_list_field') (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1449
1450
        $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...
1451
            ->method('getTemplate')
1452
            ->willReturn('@SonataAdmin/CRUD/list_nonexistent_template.html.twig');
1453
1454
        $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription);
1455
1456
        $this->templateRegistry->getTemplate('base_list_field')->shouldHaveBeenCalled();
0 ignored issues
show
Bug introduced by
The method shouldHaveBeenCalled cannot be called on $this->templateRegistry-...late('base_list_field') (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1457
    }
1458
1459
    /**
1460
     * @dataProvider getRenderViewElementTests
1461
     */
1462
    public function testRenderViewElement(string $expected, string $type, $value, array $options): void
1463
    {
1464
        $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...
1465
            ->method('getTemplate')
1466
            ->willReturn('@SonataAdmin/CRUD/base_show_field.html.twig');
1467
1468
        $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...
1469
            ->method('getValue')
1470
            ->willReturnCallback(static function () use ($value) {
1471
                if ($value instanceof NoValueException) {
1472
                    throw  $value;
1473
                }
1474
1475
                return $value;
1476
            });
1477
1478
        $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...
1479
            ->method('getType')
1480
            ->willReturn($type);
1481
1482
        $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...
1483
            ->method('getOptions')
1484
            ->willReturn($options);
1485
1486
        $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...
1487
            ->method('getTemplate')
1488
            ->willReturnCallback(static function () use ($type) {
1489
                switch ($type) {
1490
                    case 'boolean':
1491
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
1492
                    case 'datetime':
1493
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
1494
                    case 'date':
1495
                        return '@SonataAdmin/CRUD/show_date.html.twig';
1496
                    case 'time':
1497
                        return '@SonataAdmin/CRUD/show_time.html.twig';
1498
                    case 'currency':
1499
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
1500
                    case 'percent':
1501
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
1502
                    case 'email':
1503
                        return '@SonataAdmin/CRUD/show_email.html.twig';
1504
                    case 'choice':
1505
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
1506
                    case 'array':
1507
                        return '@SonataAdmin/CRUD/show_array.html.twig';
1508
                    case 'trans':
1509
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
1510
                    case 'url':
1511
                        return '@SonataAdmin/CRUD/show_url.html.twig';
1512
                    case 'html':
1513
                        return '@SonataAdmin/CRUD/show_html.html.twig';
1514
                    default:
1515
                        return false;
1516
                }
1517
            });
1518
1519
        $this->assertSame(
1520
            $this->removeExtraWhitespace($expected),
1521
            $this->removeExtraWhitespace(
1522
                $this->twigExtension->renderViewElement(
1523
                    $this->environment,
1524
                    $this->fieldDescription,
1525
                    $this->object
1526
                )
1527
            )
1528
        );
1529
    }
1530
1531
    public function getRenderViewElementTests()
1532
    {
1533
        return [
1534
            ['<th>Data</th> <td>Example</td>', 'string', 'Example', ['safe' => false]],
1535
            ['<th>Data</th> <td>Example</td>', 'text', 'Example', ['safe' => false]],
1536
            ['<th>Data</th> <td>Example</td>', 'textarea', 'Example', ['safe' => false]],
1537
            [
1538
                '<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>',
1539
                'datetime',
1540
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), [],
1541
            ],
1542
            [
1543
                '<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>',
1544
                'datetime',
1545
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1546
                ['format' => 'd.m.Y H:i:s'],
1547
            ],
1548
            [
1549
                '<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>',
1550
                'datetime',
1551
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1552
                ['timezone' => 'Asia/Hong_Kong'],
1553
            ],
1554
            [
1555
                '<th>Data</th> <td><time datetime="2013-12-24" title="2013-12-24"> December 24, 2013 </time></td>',
1556
                'date',
1557
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1558
                [],
1559
            ],
1560
            [
1561
                '<th>Data</th> <td><time datetime="2013-12-24" title="2013-12-24"> 24.12.2013 </time></td>',
1562
                'date',
1563
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1564
                ['format' => 'd.m.Y'],
1565
            ],
1566
            [
1567
                '<th>Data</th> <td><time datetime="10:11:12+00:00" title="10:11:12+00:00"> 10:11:12 </time></td>',
1568
                'time',
1569
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1570
                [],
1571
            ],
1572
            [
1573
                '<th>Data</th> <td><time datetime="10:11:12+00:00" title="10:11:12+00:00"> 18:11:12 </time></td>',
1574
                'time',
1575
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1576
                ['timezone' => 'Asia/Hong_Kong'],
1577
            ],
1578
            ['<th>Data</th> <td>10.746135</td>', 'number', 10.746135, ['safe' => false]],
1579
            ['<th>Data</th> <td>5678</td>', 'integer', 5678, ['safe' => false]],
1580
            ['<th>Data</th> <td> 1074.6135 % </td>', 'percent', 10.746135, []],
1581
            ['<th>Data</th> <td> EUR 10.746135 </td>', 'currency', 10.746135, ['currency' => 'EUR']],
1582
            ['<th>Data</th> <td> GBP 51.23456 </td>', 'currency', 51.23456, ['currency' => 'GBP']],
1583
            [
1584
                '<th>Data</th> <td> [1 => First] <br> [2 => Second] </td>',
1585
                'array',
1586
                [1 => 'First', 2 => 'Second'],
1587
                ['safe' => false],
1588
            ],
1589
            [
1590
                '<th>Data</th> <td> [1 => First] [2 => Second] </td>',
1591
                'array',
1592
                [1 => 'First', 2 => 'Second'],
1593
                ['safe' => false, 'inline' => true],
1594
            ],
1595
            [
1596
                '<th>Data</th> <td><span class="label label-success">yes</span></td>',
1597
                'boolean',
1598
                true,
1599
                [],
1600
            ],
1601
            [
1602
                '<th>Data</th> <td><span class="label label-danger">yes</span></td>',
1603
                'boolean',
1604
                true,
1605
                ['inverse' => true],
1606
            ],
1607
            ['<th>Data</th> <td><span class="label label-danger">no</span></td>', 'boolean', false, []],
1608
            [
1609
                '<th>Data</th> <td><span class="label label-success">no</span></td>',
1610
                'boolean',
1611
                false,
1612
                ['inverse' => true],
1613
            ],
1614
            [
1615
                '<th>Data</th> <td> Delete </td>',
1616
                'trans',
1617
                'action_delete',
1618
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1619
            ],
1620
            [
1621
                '<th>Data</th> <td> Delete </td>',
1622
                'trans',
1623
                'delete',
1624
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'format' => 'action_%s'],
1625
            ],
1626
            ['<th>Data</th> <td>Status1</td>', 'choice', 'Status1', ['safe' => false]],
1627
            [
1628
                '<th>Data</th> <td>Alias1</td>',
1629
                'choice',
1630
                'Status1',
1631
                ['safe' => false, 'choices' => [
1632
                    'Status1' => 'Alias1',
1633
                    'Status2' => 'Alias2',
1634
                    'Status3' => 'Alias3',
1635
                ]],
1636
            ],
1637
            [
1638
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1639
                'choice',
1640
                'NoValidKeyInChoices',
1641
                ['safe' => false, 'choices' => [
1642
                    'Status1' => 'Alias1',
1643
                    'Status2' => 'Alias2',
1644
                    'Status3' => 'Alias3',
1645
                ]],
1646
            ],
1647
            [
1648
                '<th>Data</th> <td>Delete</td>',
1649
                'choice',
1650
                'Foo',
1651
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1652
                    'Foo' => 'action_delete',
1653
                    'Status2' => 'Alias2',
1654
                    'Status3' => 'Alias3',
1655
                ]],
1656
            ],
1657
            [
1658
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1659
                'choice',
1660
                ['NoValidKeyInChoices'],
1661
                ['safe' => false, 'choices' => [
1662
                    'Status1' => 'Alias1',
1663
                    'Status2' => 'Alias2',
1664
                    'Status3' => 'Alias3',
1665
                ], 'multiple' => true],
1666
            ],
1667
            [
1668
                '<th>Data</th> <td>NoValidKeyInChoices, Alias2</td>',
1669
                'choice',
1670
                ['NoValidKeyInChoices', 'Status2'],
1671
                ['safe' => false, 'choices' => [
1672
                    'Status1' => 'Alias1',
1673
                    'Status2' => 'Alias2',
1674
                    'Status3' => 'Alias3',
1675
                ], 'multiple' => true],
1676
            ],
1677
            [
1678
                '<th>Data</th> <td>Alias1, Alias3</td>',
1679
                'choice',
1680
                ['Status1', 'Status3'],
1681
                ['safe' => false, 'choices' => [
1682
                    'Status1' => 'Alias1',
1683
                    'Status2' => 'Alias2',
1684
                    'Status3' => 'Alias3',
1685
                ], 'multiple' => true],
1686
            ],
1687
            [
1688
                '<th>Data</th> <td>Alias1 | Alias3</td>',
1689
                'choice',
1690
                ['Status1', 'Status3'], ['safe' => false, 'choices' => [
1691
                    'Status1' => 'Alias1',
1692
                    'Status2' => 'Alias2',
1693
                    'Status3' => 'Alias3',
1694
                ], 'multiple' => true, 'delimiter' => ' | '],
1695
            ],
1696
            [
1697
                '<th>Data</th> <td>Delete, Alias3</td>',
1698
                'choice',
1699
                ['Foo', 'Status3'],
1700
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1701
                    'Foo' => 'action_delete',
1702
                    'Status2' => 'Alias2',
1703
                    'Status3' => 'Alias3',
1704
                ], 'multiple' => true],
1705
            ],
1706
            [
1707
                '<th>Data</th> <td><b>Alias1</b>, <b>Alias3</b></td>',
1708
                'choice',
1709
                ['Status1', 'Status3'],
1710
                ['safe' => true, 'choices' => [
1711
                    'Status1' => '<b>Alias1</b>',
1712
                    'Status2' => '<b>Alias2</b>',
1713
                    'Status3' => '<b>Alias3</b>',
1714
                ], 'multiple' => true],
1715
            ],
1716
            [
1717
                '<th>Data</th> <td>&lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;</td>',
1718
                'choice',
1719
                ['Status1', 'Status3'],
1720
                ['safe' => false, 'choices' => [
1721
                    'Status1' => '<b>Alias1</b>',
1722
                    'Status2' => '<b>Alias2</b>',
1723
                    'Status3' => '<b>Alias3</b>',
1724
                ], 'multiple' => true],
1725
            ],
1726
            [
1727
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1728
                'url',
1729
                'http://example.com',
1730
                ['safe' => false],
1731
            ],
1732
            [
1733
                '<th>Data</th> <td><a href="http://example.com" target="_blank">http://example.com</a></td>',
1734
                'url',
1735
                'http://example.com',
1736
                ['safe' => false, 'attributes' => ['target' => '_blank']],
1737
            ],
1738
            [
1739
                '<th>Data</th> <td><a href="http://example.com" target="_blank" class="fooLink">http://example.com</a></td>',
1740
                'url',
1741
                'http://example.com',
1742
                ['safe' => false, 'attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1743
            ],
1744
            [
1745
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1746
                'url',
1747
                'https://example.com',
1748
                ['safe' => false],
1749
            ],
1750
            [
1751
                '<th>Data</th> <td><a href="http://example.com">example.com</a></td>',
1752
                'url',
1753
                'http://example.com',
1754
                ['safe' => false, 'hide_protocol' => true],
1755
            ],
1756
            [
1757
                '<th>Data</th> <td><a href="https://example.com">example.com</a></td>',
1758
                'url',
1759
                'https://example.com',
1760
                ['safe' => false, 'hide_protocol' => true],
1761
            ],
1762
            [
1763
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1764
                'url',
1765
                'http://example.com',
1766
                ['safe' => false, 'hide_protocol' => false],
1767
            ],
1768
            [
1769
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1770
                'url',
1771
                'https://example.com',
1772
                ['safe' => false,
1773
                'hide_protocol' => false, ],
1774
            ],
1775
            [
1776
                '<th>Data</th> <td><a href="http://example.com">Foo</a></td>',
1777
                'url',
1778
                'Foo',
1779
                ['safe' => false, 'url' => 'http://example.com'],
1780
            ],
1781
            [
1782
                '<th>Data</th> <td><a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a></td>',
1783
                'url',
1784
                '<b>Foo</b>',
1785
                ['safe' => false, 'url' => 'http://example.com'],
1786
            ],
1787
            [
1788
                '<th>Data</th> <td><a href="http://example.com"><b>Foo</b></a></td>',
1789
                'url',
1790
                '<b>Foo</b>',
1791
                ['safe' => true, 'url' => 'http://example.com'],
1792
            ],
1793
            [
1794
                '<th>Data</th> <td><a href="/foo">Foo</a></td>',
1795
                'url',
1796
                'Foo',
1797
                ['safe' => false, 'route' => ['name' => 'sonata_admin_foo']],
1798
            ],
1799
            [
1800
                '<th>Data</th> <td><a href="http://localhost/foo">Foo</a></td>',
1801
                'url',
1802
                'Foo',
1803
                ['safe' => false, 'route' => [
1804
                    'name' => 'sonata_admin_foo',
1805
                    'absolute' => true,
1806
                ]],
1807
            ],
1808
            [
1809
                '<th>Data</th> <td><a href="/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1810
                'url',
1811
                'http://foo/bar?a=b&c=123456789',
1812
                [
1813
                    'safe' => false,
1814
                    'route' => ['name' => 'sonata_admin_foo'],
1815
                    'hide_protocol' => true,
1816
                ],
1817
            ],
1818
            [
1819
                '<th>Data</th> <td><a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1820
                'url',
1821
                'http://foo/bar?a=b&c=123456789',
1822
                ['safe' => false, 'route' => [
1823
                    'name' => 'sonata_admin_foo',
1824
                    'absolute' => true,
1825
                ], 'hide_protocol' => true],
1826
            ],
1827
            [
1828
                '<th>Data</th> <td><a href="/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1829
                'url',
1830
                'Foo',
1831
                ['safe' => false, 'route' => [
1832
                    'name' => 'sonata_admin_foo_param',
1833
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1834
                ]],
1835
            ],
1836
            [
1837
                '<th>Data</th> <td><a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1838
                'url',
1839
                'Foo',
1840
                ['safe' => false, 'route' => [
1841
                    'name' => 'sonata_admin_foo_param',
1842
                    'absolute' => true,
1843
                    'parameters' => [
1844
                        'param1' => 'abcd',
1845
                        'param2' => 'efgh',
1846
                        'param3' => 'ijkl',
1847
                    ],
1848
                ]],
1849
            ],
1850
            [
1851
                '<th>Data</th> <td><a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1852
                'url',
1853
                'Foo',
1854
                ['safe' => false, 'route' => [
1855
                    'name' => 'sonata_admin_foo_object',
1856
                    'parameters' => [
1857
                        'param1' => 'abcd',
1858
                        'param2' => 'efgh',
1859
                        'param3' => 'ijkl',
1860
                    ],
1861
                    'identifier_parameter_name' => 'barId',
1862
                ]],
1863
            ],
1864
            [
1865
                '<th>Data</th> <td><a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1866
                'url',
1867
                'Foo',
1868
                ['safe' => false, 'route' => [
1869
                    'name' => 'sonata_admin_foo_object',
1870
                    'absolute' => true,
1871
                    'parameters' => [
1872
                        'param1' => 'abcd',
1873
                        'param2' => 'efgh',
1874
                        'param3' => 'ijkl',
1875
                    ],
1876
                    'identifier_parameter_name' => 'barId',
1877
                ]],
1878
            ],
1879
            [
1880
                '<th>Data</th> <td> &nbsp;</td>',
1881
                'email',
1882
                null,
1883
                [],
1884
            ],
1885
            [
1886
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1887
                'email',
1888
                '[email protected]',
1889
                [],
1890
            ],
1891
            [
1892
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a></td>',
1893
                'email',
1894
                '[email protected]',
1895
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
1896
            ],
1897
            [
1898
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a></td>',
1899
                'email',
1900
                '[email protected]',
1901
                ['subject' => 'Main Theme'],
1902
            ],
1903
            [
1904
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a></td>',
1905
                'email',
1906
                '[email protected]',
1907
                ['body' => 'Message Body'],
1908
            ],
1909
            [
1910
                '<th>Data</th> <td> [email protected]</td>',
1911
                'email',
1912
                '[email protected]',
1913
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
1914
            ],
1915
            [
1916
                '<th>Data</th> <td> [email protected]</td>',
1917
                'email',
1918
                '[email protected]',
1919
                ['as_string' => true, 'subject' => 'Main Theme'],
1920
            ],
1921
            [
1922
                '<th>Data</th> <td> [email protected]</td>',
1923
                'email',
1924
                '[email protected]',
1925
                ['as_string' => true, 'body' => 'Message Body'],
1926
            ],
1927
            [
1928
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1929
                'email',
1930
                '[email protected]',
1931
                ['as_string' => false],
1932
            ],
1933
            [
1934
                '<th>Data</th> <td> [email protected]</td>',
1935
                'email',
1936
                '[email protected]',
1937
                ['as_string' => true],
1938
            ],
1939
            [
1940
                '<th>Data</th> <td><p><strong>Creating a Template for the Field</strong> and form</p> </td>',
1941
                'html',
1942
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1943
                [],
1944
            ],
1945
            [
1946
                '<th>Data</th> <td>Creating a Template for the Field and form </td>',
1947
                'html',
1948
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1949
                ['strip' => true],
1950
            ],
1951
            [
1952
                '<th>Data</th> <td> Creating a Template for the... </td>',
1953
                'html',
1954
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1955
                ['truncate' => true],
1956
            ],
1957
            [
1958
                '<th>Data</th> <td> Creatin... </td>',
1959
                'html',
1960
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1961
                ['truncate' => ['length' => 10]],
1962
            ],
1963
            [
1964
                '<th>Data</th> <td> Creating a Template for the Field... </td>',
1965
                'html',
1966
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1967
                ['truncate' => ['cut' => false]],
1968
            ],
1969
            [
1970
                '<th>Data</th> <td> Creating a Template for t etc. </td>',
1971
                'html',
1972
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1973
                ['truncate' => ['ellipsis' => ' etc.']],
1974
            ],
1975
            [
1976
                '<th>Data</th> <td> Creating a Template[...] </td>',
1977
                'html',
1978
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1979
                [
1980
                    'truncate' => [
1981
                        'length' => 20,
1982
                        'cut' => false,
1983
                        'ellipsis' => '[...]',
1984
                    ],
1985
                ],
1986
            ],
1987
1988
            // NoValueException
1989
            ['<th>Data</th> <td></td>', 'string', new NoValueException(), ['safe' => false]],
1990
            ['<th>Data</th> <td></td>', 'text', new NoValueException(), ['safe' => false]],
1991
            ['<th>Data</th> <td></td>', 'textarea', new NoValueException(), ['safe' => false]],
1992
            ['<th>Data</th> <td>&nbsp;</td>', 'datetime', new NoValueException(), []],
1993
            [
1994
                '<th>Data</th> <td>&nbsp;</td>',
1995
                'datetime',
1996
                new NoValueException(),
1997
                ['format' => 'd.m.Y H:i:s'],
1998
            ],
1999
            ['<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), []],
2000
            ['<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), ['format' => 'd.m.Y']],
2001
            ['<th>Data</th> <td>&nbsp;</td>', 'time', new NoValueException(), []],
2002
            ['<th>Data</th> <td></td>', 'number', new NoValueException(), ['safe' => false]],
2003
            ['<th>Data</th> <td></td>', 'integer', new NoValueException(), ['safe' => false]],
2004
            ['<th>Data</th> <td> 0 % </td>', 'percent', new NoValueException(), []],
2005
            ['<th>Data</th> <td> </td>', 'currency', new NoValueException(), ['currency' => 'EUR']],
2006
            ['<th>Data</th> <td> </td>', 'currency', new NoValueException(), ['currency' => 'GBP']],
2007
            ['<th>Data</th> <td> </td>', 'array', new NoValueException(), ['safe' => false]],
2008
            [
2009
                '<th>Data</th> <td><span class="label label-danger">no</span></td>',
2010
                'boolean',
2011
                new NoValueException(),
2012
                [],
2013
            ],
2014
            [
2015
                '<th>Data</th> <td> </td>',
2016
                'trans',
2017
                new NoValueException(),
2018
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
2019
            ],
2020
            [
2021
                '<th>Data</th> <td></td>',
2022
                'choice',
2023
                new NoValueException(),
2024
                ['safe' => false, 'choices' => []],
2025
            ],
2026
            [
2027
                '<th>Data</th> <td></td>',
2028
                'choice',
2029
                new NoValueException(),
2030
                ['safe' => false, 'choices' => [], 'multiple' => true],
2031
            ],
2032
            ['<th>Data</th> <td>&nbsp;</td>', 'url', new NoValueException(), []],
2033
            [
2034
                '<th>Data</th> <td>&nbsp;</td>',
2035
                'url',
2036
                new NoValueException(),
2037
                ['url' => 'http://example.com'],
2038
            ],
2039
            [
2040
                '<th>Data</th> <td>&nbsp;</td>',
2041
                'url',
2042
                new NoValueException(),
2043
                ['route' => ['name' => 'sonata_admin_foo']],
2044
            ],
2045
2046
            [
2047
                <<<'EOT'
2048
<th>Data</th> <td><div
2049
        class="sonata-readmore"
2050
        data-readmore-height="40"
2051
        data-readmore-more="Read more"
2052
        data-readmore-less="Close">
2053
            A very long string
2054
</div></td>
2055
EOT
2056
                ,
2057
                'text',
2058
                ' A very long string ',
2059
                [
2060
                    'collapse' => true,
2061
                    'safe' => false,
2062
                ],
2063
            ],
2064
            [
2065
                <<<'EOT'
2066
<th>Data</th> <td><div
2067
        class="sonata-readmore"
2068
        data-readmore-height="10"
2069
        data-readmore-more="More"
2070
        data-readmore-less="Less">
2071
            A very long string
2072
</div></td>
2073
EOT
2074
                ,
2075
                'text',
2076
                ' A very long string ',
2077
                [
2078
                    'collapse' => [
2079
                        'height' => 10,
2080
                        'more' => 'More',
2081
                        'less' => 'Less',
2082
                    ],
2083
                    'safe' => false,
2084
                ],
2085
            ],
2086
        ];
2087
    }
2088
2089
    /**
2090
     * NEXT_MAJOR: Remove this method.
2091
     *
2092
     * @group legacy
2093
     *
2094
     * @dataProvider getDeprecatedTextExtensionItems
2095
     *
2096
     * @expectedDeprecation The "truncate.preserve" option is deprecated since sonata-project/admin-bundle 3.x, to be removed in 4.0. Use "truncate.cut" instead. ("@SonataAdmin/CRUD/show_html.html.twig" at line %d).
2097
     *
2098
     * @expectedDeprecation The "truncate.separator" option is deprecated since sonata-project/admin-bundle 3.x, to be removed in 4.0. Use "truncate.ellipsis" instead. ("@SonataAdmin/CRUD/show_html.html.twig" at line %d).
2099
     */
2100
    public function testDeprecatedTextExtension(string $expected, string $type, $value, array $options): void
2101
    {
2102
        $loader = new StubFilesystemLoader([
2103
            __DIR__.'/../../../src/Resources/views/CRUD',
2104
        ]);
2105
        $loader->addPath(__DIR__.'/../../../src/Resources/views/', 'SonataAdmin');
2106
        $environment = new Environment($loader, [
2107
            'strict_variables' => true,
2108
            'cache' => false,
2109
            'autoescape' => 'html',
2110
            'optimizations' => 0,
2111
        ]);
2112
        $environment->addExtension($this->twigExtension);
2113
        $environment->addExtension(new TranslationExtension($this->translator));
0 ignored issues
show
Documentation introduced by
$this->translator is of type object<Symfony\Component...on\TranslatorInterface>, but the function expects a object<Symfony\Contracts...anslatorInterface>|null.

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...
2114
        $environment->addExtension(new StringExtension(new TextExtension()));
2115
2116
        $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...
2117
            ->method('getTemplate')
2118
            ->willReturn('@SonataAdmin/CRUD/base_show_field.html.twig');
2119
2120
        $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...
2121
            ->method('getValue')
2122
            ->willReturn($value);
2123
2124
        $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...
2125
            ->method('getType')
2126
            ->willReturn($type);
2127
2128
        $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...
2129
            ->method('getOptions')
2130
            ->willReturn($options);
2131
2132
        $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...
2133
            ->method('getTemplate')
2134
            ->willReturn('@SonataAdmin/CRUD/show_html.html.twig');
2135
2136
        $this->assertSame(
2137
            $this->removeExtraWhitespace($expected),
2138
            $this->removeExtraWhitespace(
2139
                $this->twigExtension->renderViewElement(
2140
                    $environment,
2141
                    $this->fieldDescription,
2142
                    $this->object
2143
                )
2144
            )
2145
        );
2146
    }
2147
2148
    /**
2149
     * NEXT_MAJOR: Remove this method.
2150
     */
2151
    public function getDeprecatedTextExtensionItems(): iterable
2152
    {
2153
        yield 'default_separator' => [
2154
            '<th>Data</th> <td> Creating a Template for the Field... </td>',
2155
            'html',
2156
            '<p><strong>Creating a Template for the Field</strong> and form</p>',
2157
            ['truncate' => ['preserve' => true, 'separator' => '...']],
2158
        ];
2159
2160
        yield 'custom_length' => [
2161
            '<th>Data</th> <td> Creating a Template for[...] </td>',
2162
            'html',
2163
            '<p><strong>Creating a Template for the Field</strong> and form</p>',
2164
            [
2165
                'truncate' => [
2166
                    'length' => 20,
2167
                    'preserve' => true,
2168
                    'separator' => '[...]',
2169
                ],
2170
            ],
2171
        ];
2172
    }
2173
2174
    public function testGetValueFromFieldDescription(): void
2175
    {
2176
        $object = new \stdClass();
2177
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2178
2179
        $fieldDescription
2180
            ->method('getValue')
2181
            ->willReturn('test123');
2182
2183
        $this->assertSame('test123', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2184
    }
2185
2186
    public function testGetValueFromFieldDescriptionWithRemoveLoopException(): void
2187
    {
2188
        $object = $this->createMock(\ArrayAccess::class);
2189
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2190
2191
        $this->expectException(\RuntimeException::class);
2192
        $this->expectExceptionMessage('remove the loop requirement');
2193
2194
        $this->assertSame(
2195
            'anything',
2196
            $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription, ['loop' => true])
2197
        );
2198
    }
2199
2200
    public function testGetValueFromFieldDescriptionWithNoValueException(): void
2201
    {
2202
        $object = new \stdClass();
2203
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2204
2205
        $fieldDescription
2206
            ->method('getValue')
2207
            ->willReturnCallback(static function (): void {
2208
                throw new NoValueException();
2209
            });
2210
2211
        $fieldDescription
2212
            ->method('getAssociationAdmin')
2213
            ->willReturn(null);
2214
2215
        $this->assertNull($this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2216
    }
2217
2218
    public function testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance(): void
2219
    {
2220
        $object = new \stdClass();
2221
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2222
2223
        $fieldDescription
2224
            ->method('getValue')
2225
            ->willReturnCallback(static function (): void {
2226
                throw new NoValueException();
2227
            });
2228
2229
        $fieldDescription
2230
            ->method('getAssociationAdmin')
2231
            ->willReturn($this->admin);
2232
2233
        $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...
2234
            ->method('getNewInstance')
2235
            ->willReturn('foo');
2236
2237
        $this->assertSame('foo', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2238
    }
2239
2240
    /**
2241
     * @group legacy
2242
     */
2243
    public function testOutput(): void
2244
    {
2245
        $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...
2246
            ->method('getTemplate')
2247
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
2248
2249
        $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...
2250
            ->method('getFieldName')
2251
            ->willReturn('fd_name');
2252
2253
        $this->environment->disableDebug();
2254
2255
        $parameters = [
2256
            'admin' => $this->admin,
2257
            'value' => 'foo',
2258
            'field_description' => $this->fieldDescription,
2259
            'object' => $this->object,
2260
        ];
2261
2262
        $template = $this->environment->loadTemplate('@SonataAdmin/CRUD/base_list_field.html.twig');
2263
2264
        $this->assertSame(
2265
            '<td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>',
2266
            $this->removeExtraWhitespace($this->twigExtension->output(
0 ignored issues
show
Deprecated Code introduced by
The method Sonata\AdminBundle\Twig\...dminExtension::output() has been deprecated with message: since sonata-project/admin-bundle 3.33, to be removed in 4.0. Use render instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2267
                $this->fieldDescription,
2268
                $template,
2269
                $parameters,
2270
                $this->environment
2271
            ))
2272
        );
2273
2274
        $this->environment->enableDebug();
2275
        $this->assertSame(
2276
            $this->removeExtraWhitespace(
2277
                <<<'EOT'
2278
<!-- START
2279
    fieldName: fd_name
2280
    template: @SonataAdmin/CRUD/base_list_field.html.twig
2281
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
2282
-->
2283
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
2284
<!-- END - fieldName: fd_name -->
2285
EOT
2286
            ),
2287
            $this->removeExtraWhitespace(
2288
                $this->twigExtension->output($this->fieldDescription, $template, $parameters, $this->environment)
0 ignored issues
show
Deprecated Code introduced by
The method Sonata\AdminBundle\Twig\...dminExtension::output() has been deprecated with message: since sonata-project/admin-bundle 3.33, to be removed in 4.0. Use render instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2289
            )
2290
        );
2291
    }
2292
2293
    /**
2294
     * @group legacy
2295
     * @expectedDeprecation The Sonata\AdminBundle\Admin\AbstractAdmin::getTemplate method is deprecated (since sonata-project/admin-bundle 3.34, will be dropped in 4.0. Use TemplateRegistry services instead).
2296
     */
2297
    public function testRenderWithDebug(): void
2298
    {
2299
        $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...
2300
            ->method('getTemplate')
2301
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
2302
2303
        $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...
2304
            ->method('getFieldName')
2305
            ->willReturn('fd_name');
2306
2307
        $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...
2308
            ->method('getValue')
2309
            ->willReturn('foo');
2310
2311
        $parameters = [
2312
            'admin' => $this->admin,
2313
            'value' => 'foo',
2314
            'field_description' => $this->fieldDescription,
2315
            'object' => $this->object,
2316
        ];
2317
2318
        $this->environment->enableDebug();
2319
2320
        $this->assertSame(
2321
            $this->removeExtraWhitespace(
2322
                <<<'EOT'
2323
<!-- START
2324
    fieldName: fd_name
2325
    template: @SonataAdmin/CRUD/base_list_field.html.twig
2326
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
2327
-->
2328
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
2329
<!-- END - fieldName: fd_name -->
2330
EOT
2331
            ),
2332
            $this->removeExtraWhitespace(
2333
                $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription, $parameters)
2334
            )
2335
        );
2336
    }
2337
2338
    public function testRenderRelationElementNoObject(): void
2339
    {
2340
        $this->assertSame('foo', $this->twigExtension->renderRelationElement('foo', $this->fieldDescription));
2341
    }
2342
2343
    public function testRenderRelationElementToString(): void
2344
    {
2345
        $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...
2346
            ->method('getOption')
2347
            ->willReturnCallback(static function ($value, $default = null) {
2348
                if ('associated_property' === $value) {
2349
                    return $default;
2350
                }
2351
            });
2352
2353
        $element = new FooToString();
2354
        $this->assertSame('salut', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2355
    }
2356
2357
    /**
2358
     * @group legacy
2359
     */
2360
    public function testDeprecatedRelationElementToString(): void
2361
    {
2362
        $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...
2363
            ->method('getOption')
2364
            ->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...
2365
                if ('associated_tostring' === $value) {
2366
                    return '__toString';
2367
                }
2368
            });
2369
2370
        $element = new FooToString();
2371
        $this->assertSame(
2372
            'salut',
2373
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2374
        );
2375
    }
2376
2377
    /**
2378
     * @group legacy
2379
     */
2380
    public function testRenderRelationElementCustomToString(): void
2381
    {
2382
        $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...
2383
            ->method('getOption')
2384
            ->willReturnCallback(static function ($value, $default = null) {
2385
                if ('associated_property' === $value) {
2386
                    return $default;
2387
                }
2388
2389
                if ('associated_tostring' === $value) {
2390
                    return 'customToString';
2391
                }
2392
            });
2393
2394
        $element = $this->getMockBuilder('stdClass')
2395
            ->setMethods(['customToString'])
2396
            ->getMock();
2397
        $element
2398
            ->method('customToString')
2399
            ->willReturn('fooBar');
2400
2401
        $this->assertSame('fooBar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2402
    }
2403
2404
    /**
2405
     * @group legacy
2406
     */
2407
    public function testRenderRelationElementMethodNotExist(): void
2408
    {
2409
        $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...
2410
            ->method('getOption')
2411
2412
            ->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...
2413
                if ('associated_tostring' === $value) {
2414
                    return 'nonExistedMethod';
2415
                }
2416
            });
2417
2418
        $element = new \stdClass();
2419
        $this->expectException(\RuntimeException::class);
2420
        $this->expectExceptionMessage('You must define an `associated_property` option or create a `stdClass::__toString');
2421
2422
        $this->twigExtension->renderRelationElement($element, $this->fieldDescription);
2423
    }
2424
2425
    public function testRenderRelationElementWithPropertyPath(): void
2426
    {
2427
        $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...
2428
            ->method('getOption')
2429
2430
            ->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...
2431
                if ('associated_property' === $value) {
2432
                    return 'foo';
2433
                }
2434
            });
2435
2436
        $element = new \stdClass();
2437
        $element->foo = 'bar';
2438
2439
        $this->assertSame('bar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2440
    }
2441
2442
    public function testRenderRelationElementWithClosure(): void
2443
    {
2444
        $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...
2445
            ->method('getOption')
2446
2447
            ->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...
2448
                if ('associated_property' === $value) {
2449
                    return static function ($element): string {
2450
                        return 'closure '.$element->foo;
2451
                    };
2452
                }
2453
            });
2454
2455
        $element = new \stdClass();
2456
        $element->foo = 'bar';
2457
2458
        $this->assertSame(
2459
            'closure bar',
2460
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2461
        );
2462
    }
2463
2464
    public function testGetUrlsafeIdentifier(): void
2465
    {
2466
        $entity = new \stdClass();
2467
2468
        // set admin to pool
2469
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
2470
        $this->pool->setAdminClasses(['stdClass' => ['sonata_admin_foo_service']]);
2471
2472
        $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...
2473
            ->method('getUrlsafeIdentifier')
2474
            ->with($this->equalTo($entity))
2475
            ->willReturn(1234567);
2476
2477
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity));
2478
    }
2479
2480
    public function testGetUrlsafeIdentifier_GivenAdmin_Foo(): void
2481
    {
2482
        $entity = new \stdClass();
2483
2484
        // set admin to pool
2485
        $this->pool->setAdminServiceIds([
2486
            'sonata_admin_foo_service',
2487
            'sonata_admin_bar_service',
2488
        ]);
2489
        $this->pool->setAdminClasses(['stdClass' => [
2490
            'sonata_admin_foo_service',
2491
            'sonata_admin_bar_service',
2492
        ]]);
2493
2494
        $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...
2495
            ->method('getUrlsafeIdentifier')
2496
            ->with($this->equalTo($entity))
2497
            ->willReturn(1234567);
2498
2499
        $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...
2500
            ->method('getUrlsafeIdentifier');
2501
2502
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->admin));
2503
    }
2504
2505
    public function testGetUrlsafeIdentifier_GivenAdmin_Bar(): void
2506
    {
2507
        $entity = new \stdClass();
2508
2509
        // set admin to pool
2510
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service', 'sonata_admin_bar_service']);
2511
        $this->pool->setAdminClasses(['stdClass' => [
2512
            'sonata_admin_foo_service',
2513
            'sonata_admin_bar_service',
2514
        ]]);
2515
2516
        $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...
2517
            ->method('getUrlsafeIdentifier');
2518
2519
        $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...
2520
            ->method('getUrlsafeIdentifier')
2521
            ->with($this->equalTo($entity))
2522
            ->willReturn(1234567);
2523
2524
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->adminBar));
2525
    }
2526
2527
    public function xEditableChoicesProvider()
2528
    {
2529
        return [
2530
            'needs processing' => [
2531
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2']],
2532
                [
2533
                    ['value' => 'Status1', 'text' => 'Alias1'],
2534
                    ['value' => 'Status2', 'text' => 'Alias2'],
2535
                ],
2536
            ],
2537
            'already processed' => [
2538
                ['choices' => [
2539
                    ['value' => 'Status1', 'text' => 'Alias1'],
2540
                    ['value' => 'Status2', 'text' => 'Alias2'],
2541
                ]],
2542
                [
2543
                    ['value' => 'Status1', 'text' => 'Alias1'],
2544
                    ['value' => 'Status2', 'text' => 'Alias2'],
2545
                ],
2546
            ],
2547
            'not required' => [
2548
                [
2549
                    'required' => false,
2550
                    'choices' => ['' => '', 'Status1' => 'Alias1', 'Status2' => 'Alias2'],
2551
                ],
2552
                [
2553
                    ['value' => '', 'text' => ''],
2554
                    ['value' => 'Status1', 'text' => 'Alias1'],
2555
                    ['value' => 'Status2', 'text' => 'Alias2'],
2556
                ],
2557
            ],
2558
            'not required multiple' => [
2559
                [
2560
                    'required' => false,
2561
                    'multiple' => true,
2562
                    'choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2'],
2563
                ],
2564
                [
2565
                    ['value' => 'Status1', 'text' => 'Alias1'],
2566
                    ['value' => 'Status2', 'text' => 'Alias2'],
2567
                ],
2568
            ],
2569
        ];
2570
    }
2571
2572
    /**
2573
     * @dataProvider xEditablechoicesProvider
2574
     */
2575
    public function testGetXEditableChoicesIsIdempotent(array $options, array $expectedChoices): void
2576
    {
2577
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2578
        $fieldDescription
2579
            ->method('getOption')
2580
            ->withConsecutive(
2581
                ['choices', []],
2582
                ['catalogue'],
2583
                ['required'],
2584
                ['multiple']
2585
            )
2586
            ->will($this->onConsecutiveCalls(
2587
                $options['choices'],
2588
                'MyCatalogue',
2589
                $options['multiple'] ?? null
2590
            ));
2591
2592
        $this->assertSame($expectedChoices, $this->twigExtension->getXEditableChoices($fieldDescription));
2593
    }
2594
2595
    public function select2LocalesProvider()
2596
    {
2597
        return [
2598
            ['ar', 'ar'],
2599
            ['az', 'az'],
2600
            ['bg', 'bg'],
2601
            ['ca', 'ca'],
2602
            ['cs', 'cs'],
2603
            ['da', 'da'],
2604
            ['de', 'de'],
2605
            ['el', 'el'],
2606
            [null, 'en'],
2607
            ['es', 'es'],
2608
            ['et', 'et'],
2609
            ['eu', 'eu'],
2610
            ['fa', 'fa'],
2611
            ['fi', 'fi'],
2612
            ['fr', 'fr'],
2613
            ['gl', 'gl'],
2614
            ['he', 'he'],
2615
            ['hr', 'hr'],
2616
            ['hu', 'hu'],
2617
            ['id', 'id'],
2618
            ['is', 'is'],
2619
            ['it', 'it'],
2620
            ['ja', 'ja'],
2621
            ['ka', 'ka'],
2622
            ['ko', 'ko'],
2623
            ['lt', 'lt'],
2624
            ['lv', 'lv'],
2625
            ['mk', 'mk'],
2626
            ['ms', 'ms'],
2627
            ['nb', 'nb'],
2628
            ['nl', 'nl'],
2629
            ['pl', 'pl'],
2630
            ['pt-PT', 'pt'],
2631
            ['pt-BR', 'pt-BR'],
2632
            ['pt-PT', 'pt-PT'],
2633
            ['ro', 'ro'],
2634
            ['rs', 'rs'],
2635
            ['ru', 'ru'],
2636
            ['sk', 'sk'],
2637
            ['sv', 'sv'],
2638
            ['th', 'th'],
2639
            ['tr', 'tr'],
2640
            ['ug-CN', 'ug'],
2641
            ['ug-CN', 'ug-CN'],
2642
            ['uk', 'uk'],
2643
            ['vi', 'vi'],
2644
            ['zh-CN', 'zh'],
2645
            ['zh-CN', 'zh-CN'],
2646
            ['zh-TW', 'zh-TW'],
2647
        ];
2648
    }
2649
2650
    /**
2651
     * @dataProvider select2LocalesProvider
2652
     */
2653
    public function testCanonicalizedLocaleForSelect2(?string $expected, string $original): void
2654
    {
2655
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForSelect2($this->mockExtensionContext($original)));
2656
    }
2657
2658
    public function momentLocalesProvider(): array
2659
    {
2660
        return [
2661
            ['af', 'af'],
2662
            ['ar-dz', 'ar-dz'],
2663
            ['ar', 'ar'],
2664
            ['ar-ly', 'ar-ly'],
2665
            ['ar-ma', 'ar-ma'],
2666
            ['ar-sa', 'ar-sa'],
2667
            ['ar-tn', 'ar-tn'],
2668
            ['az', 'az'],
2669
            ['be', 'be'],
2670
            ['bg', 'bg'],
2671
            ['bn', 'bn'],
2672
            ['bo', 'bo'],
2673
            ['br', 'br'],
2674
            ['bs', 'bs'],
2675
            ['ca', 'ca'],
2676
            ['cs', 'cs'],
2677
            ['cv', 'cv'],
2678
            ['cy', 'cy'],
2679
            ['da', 'da'],
2680
            ['de-at', 'de-at'],
2681
            ['de', 'de'],
2682
            ['de', 'de-de'],
2683
            ['dv', 'dv'],
2684
            ['el', 'el'],
2685
            [null, 'en'],
2686
            [null, 'en-us'],
2687
            ['en-au', 'en-au'],
2688
            ['en-ca', 'en-ca'],
2689
            ['en-gb', 'en-gb'],
2690
            ['en-ie', 'en-ie'],
2691
            ['en-nz', 'en-nz'],
2692
            ['eo', 'eo'],
2693
            ['es-do', 'es-do'],
2694
            ['es', 'es-ar'],
2695
            ['es', 'es-mx'],
2696
            ['es', 'es'],
2697
            ['et', 'et'],
2698
            ['eu', 'eu'],
2699
            ['fa', 'fa'],
2700
            ['fi', 'fi'],
2701
            ['fo', 'fo'],
2702
            ['fr-ca', 'fr-ca'],
2703
            ['fr-ch', 'fr-ch'],
2704
            ['fr', 'fr-fr'],
2705
            ['fr', 'fr'],
2706
            ['fy', 'fy'],
2707
            ['gd', 'gd'],
2708
            ['gl', 'gl'],
2709
            ['he', 'he'],
2710
            ['hi', 'hi'],
2711
            ['hr', 'hr'],
2712
            ['hu', 'hu'],
2713
            ['hy-am', 'hy-am'],
2714
            ['id', 'id'],
2715
            ['is', 'is'],
2716
            ['it', 'it'],
2717
            ['ja', 'ja'],
2718
            ['jv', 'jv'],
2719
            ['ka', 'ka'],
2720
            ['kk', 'kk'],
2721
            ['km', 'km'],
2722
            ['ko', 'ko'],
2723
            ['ky', 'ky'],
2724
            ['lb', 'lb'],
2725
            ['lo', 'lo'],
2726
            ['lt', 'lt'],
2727
            ['lv', 'lv'],
2728
            ['me', 'me'],
2729
            ['mi', 'mi'],
2730
            ['mk', 'mk'],
2731
            ['ml', 'ml'],
2732
            ['mr', 'mr'],
2733
            ['ms', 'ms'],
2734
            ['ms-my', 'ms-my'],
2735
            ['my', 'my'],
2736
            ['nb', 'nb'],
2737
            ['ne', 'ne'],
2738
            ['nl-be', 'nl-be'],
2739
            ['nl', 'nl'],
2740
            ['nl', 'nl-nl'],
2741
            ['nn', 'nn'],
2742
            ['pa-in', 'pa-in'],
2743
            ['pl', 'pl'],
2744
            ['pt-br', 'pt-br'],
2745
            ['pt', 'pt'],
2746
            ['ro', 'ro'],
2747
            ['ru', 'ru'],
2748
            ['se', 'se'],
2749
            ['si', 'si'],
2750
            ['sk', 'sk'],
2751
            ['sl', 'sl'],
2752
            ['sq', 'sq'],
2753
            ['sr-cyrl', 'sr-cyrl'],
2754
            ['sr', 'sr'],
2755
            ['ss', 'ss'],
2756
            ['sv', 'sv'],
2757
            ['sw', 'sw'],
2758
            ['ta', 'ta'],
2759
            ['te', 'te'],
2760
            ['tet', 'tet'],
2761
            ['th', 'th'],
2762
            ['tlh', 'tlh'],
2763
            ['tl-ph', 'tl-ph'],
2764
            ['tr', 'tr'],
2765
            ['tzl', 'tzl'],
2766
            ['tzm', 'tzm'],
2767
            ['tzm-latn', 'tzm-latn'],
2768
            ['uk', 'uk'],
2769
            ['uz', 'uz'],
2770
            ['vi', 'vi'],
2771
            ['x-pseudo', 'x-pseudo'],
2772
            ['yo', 'yo'],
2773
            ['zh-cn', 'zh-cn'],
2774
            ['zh-hk', 'zh-hk'],
2775
            ['zh-tw', 'zh-tw'],
2776
        ];
2777
    }
2778
2779
    /**
2780
     * @dataProvider momentLocalesProvider
2781
     */
2782
    public function testCanonicalizedLocaleForMoment(?string $expected, string $original): void
2783
    {
2784
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForMoment($this->mockExtensionContext($original)));
2785
    }
2786
2787
    public function testIsGrantedAffirmative(): void
2788
    {
2789
        $this->assertTrue(
2790
            $this->twigExtension->isGrantedAffirmative(['foo', 'bar'])
2791
        );
2792
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('foo'));
2793
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('bar'));
2794
    }
2795
2796
    /**
2797
     * This method generates url part for Twig layout.
2798
     */
2799
    private function buildTwigLikeUrl(array $url): string
2800
    {
2801
        return htmlspecialchars(http_build_query($url, '', '&', PHP_QUERY_RFC3986));
2802
    }
2803
2804
    private function removeExtraWhitespace(string $string): string
2805
    {
2806
        return trim(preg_replace(
2807
            '/\s+/',
2808
            ' ',
2809
            $string
2810
        ));
2811
    }
2812
2813
    private function mockExtensionContext(string $locale): array
2814
    {
2815
        $request = $this->createMock(Request::class);
2816
        $request->method('getLocale')->willReturn($locale);
2817
        $appVariable = $this->createMock(AppVariable::class);
2818
        $appVariable->method('getRequest')->willReturn($request);
2819
2820
        return ['app' => $appVariable];
2821
    }
2822
}
2823