Completed
Push — 3.x ( 11eae5...d8de84 )
by Javier
02:59
created

SonataAdminExtensionTest::removeExtraWhitespace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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 as LegacyTranslatorInterface;
42
use Symfony\Contracts\Translation\TranslatorInterface;
43
use Twig\Environment;
44
use Twig\Error\LoaderError;
45
use Twig\Extensions\TextExtension;
46
47
/**
48
 * Test for SonataAdminExtension.
49
 *
50
 * @author Andrej Hudec <[email protected]>
51
 */
52
class SonataAdminExtensionTest extends TestCase
53
{
54
    /**
55
     * @var SonataAdminExtension
56
     */
57
    private $twigExtension;
58
59
    /**
60
     * @var Environment
61
     */
62
    private $environment;
63
64
    /**
65
     * @var AdminInterface
66
     */
67
    private $admin;
68
69
    /**
70
     * @var AdminInterface
71
     */
72
    private $adminBar;
73
74
    /**
75
     * @var FieldDescriptionInterface
76
     */
77
    private $fieldDescription;
78
79
    /**
80
     * @var \stdClass
81
     */
82
    private $object;
83
84
    /**
85
     * @var Pool
86
     */
87
    private $pool;
88
89
    /**
90
     * @var LoggerInterface
91
     */
92
    private $logger;
93
94
    /**
95
     * @var string[]
96
     */
97
    private $xEditableTypeMapping;
98
99
    /**
100
     * @var TranslatorInterface
101
     */
102
    private $translator;
103
104
    /**
105
     * @var ContainerInterface
106
     */
107
    private $container;
108
109
    /**
110
     * @var TemplateRegistryInterface
111
     */
112
    private $templateRegistry;
113
114
    /**
115
     * @var AuthorizationCheckerInterface
116
     */
117
    private $securityChecker;
118
119
    protected function setUp(): void
120
    {
121
        date_default_timezone_set('Europe/London');
122
123
        $container = $this->createMock(ContainerInterface::class);
124
125
        $this->pool = new Pool($container, '', '');
126
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
127
        $this->pool->setAdminClasses(['fooClass' => ['sonata_admin_foo_service']]);
128
129
        $this->logger = $this->getMockForAbstractClass(LoggerInterface::class);
130
        $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...
131
            'choice' => 'select',
132
            'boolean' => 'select',
133
            'text' => 'text',
134
            'textarea' => 'textarea',
135
            'html' => 'textarea',
136
            'email' => 'email',
137
            'string' => 'text',
138
            'smallint' => 'text',
139
            'bigint' => 'text',
140
            'integer' => 'number',
141
            'decimal' => 'number',
142
            'currency' => 'number',
143
            'percent' => 'number',
144
            'url' => 'url',
145
        ];
146
147
        // translation extension
148
        $translator = new Translator('en');
149
        $translator->addLoader('xlf', new XliffFileLoader());
150
        $translator->addResource(
151
            'xlf',
152
            __DIR__.'/../../../src/Resources/translations/SonataAdminBundle.en.xliff',
153
            'en',
154
            'SonataAdminBundle'
155
        );
156
157
        $this->translator = $translator;
158
159
        $this->templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
160
        $this->container = $this->prophesize(ContainerInterface::class);
161
        $this->container->get('sonata_admin_foo_service.template_registry')->willReturn($this->templateRegistry->reveal());
162
163
        $this->securityChecker = $this->prophesize(AuthorizationCheckerInterface::class);
164
        $this->securityChecker->isGranted(['foo', 'bar'], null)->willReturn(false);
165
        $this->securityChecker->isGranted(Argument::type('string'), null)->willReturn(true);
166
167
        $this->twigExtension = new SonataAdminExtension(
168
            $this->pool,
169
            $this->logger,
170
            $this->translator,
171
            $this->container->reveal(),
172
            $this->securityChecker->reveal()
173
        );
174
        $this->twigExtension->setXEditableTypeMapping($this->xEditableTypeMapping);
175
176
        $request = $this->createMock(Request::class);
177
        $request->method('get')->with('_sonata_admin')->willReturn('sonata_admin_foo_service');
178
179
        $loader = new StubFilesystemLoader([
180
            __DIR__.'/../../../src/Resources/views/CRUD',
181
            __DIR__.'/../../Fixtures/Resources/views/CRUD',
182
        ]);
183
        $loader->addPath(__DIR__.'/../../../src/Resources/views/', 'SonataAdmin');
184
        $loader->addPath(__DIR__.'/../../Fixtures/Resources/views/', 'App');
185
186
        $this->environment = new Environment($loader, [
187
            'strict_variables' => true,
188
            'cache' => false,
189
            'autoescape' => 'html',
190
            'optimizations' => 0,
191
        ]);
192
        $this->environment->addExtension($this->twigExtension);
193
        $this->environment->addExtension(new TranslationExtension($translator));
194
        $this->environment->addExtension(new FakeTemplateRegistryExtension());
195
196
        // routing extension
197
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../../src/Resources/config/routing']));
198
        $routeCollection = $xmlFileLoader->load('sonata_admin.xml');
199
200
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../Fixtures/Resources/config/routing']));
201
        $testRouteCollection = $xmlFileLoader->load('routing.xml');
202
203
        $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...
204
        $requestContext = new RequestContext();
205
        $urlGenerator = new UrlGenerator($routeCollection, $requestContext);
206
        $this->environment->addExtension(new RoutingExtension($urlGenerator));
207
        $this->environment->addExtension(new TextExtension());
208
        $this->environment->addExtension(new StringExtension());
209
210
        // initialize object
211
        $this->object = new \stdClass();
212
213
        // initialize admin
214
        $this->admin = $this->createMock(AbstractAdmin::class);
215
216
        $this->admin
217
            ->method('getCode')
218
            ->willReturn('sonata_admin_foo_service');
219
220
        $this->admin
221
            ->method('id')
222
            ->with($this->equalTo($this->object))
223
            ->willReturn(12345);
224
225
        $this->admin
226
            ->method('getNormalizedIdentifier')
227
            ->with($this->equalTo($this->object))
228
            ->willReturn(12345);
229
230
        $this->admin
231
            ->method('trans')
232
            ->willReturnCallback(static function ($id, $parameters = [], $domain = null) use ($translator) {
233
                return $translator->trans($id, $parameters, $domain);
234
            });
235
236
        $this->adminBar = $this->createMock(AbstractAdmin::class);
237
        $this->adminBar
238
            ->method('hasAccess')
239
            ->willReturn(true);
240
        $this->adminBar
241
            ->method('getNormalizedIdentifier')
242
            ->with($this->equalTo($this->object))
243
            ->willReturn(12345);
244
245
        $container
246
            ->method('get')
247
            ->willReturnCallback(function (string $id) {
248
                if ('sonata_admin_foo_service' === $id) {
249
                    return $this->admin;
250
                }
251
252
                if ('sonata_admin_bar_service' === $id) {
253
                    return $this->adminBar;
254
                }
255
            });
256
257
        // initialize field description
258
        $this->fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
259
260
        $this->fieldDescription
261
            ->method('getName')
262
            ->willReturn('fd_name');
263
264
        $this->fieldDescription
265
            ->method('getAdmin')
266
            ->willReturn($this->admin);
267
268
        $this->fieldDescription
269
            ->method('getLabel')
270
            ->willReturn('Data');
271
    }
272
273
    /**
274
     * NEXT_MAJOR: Remove this method.
275
     *
276
     * @group legacy
277
     */
278
    public function testConstructThrowsExceptionWithWrongTranslationArgument(): void
279
    {
280
        $this->expectException(\TypeError::class);
281
282
        new SonataAdminExtension(
283
            $this->pool,
284
            null,
285
            new \stdClass()
286
        );
287
    }
288
289
    /**
290
     * @doesNotPerformAssertions
291
     * @group legacy
292
     */
293
    public function testConstructWithLegacyTranslator(): void
294
    {
295
        new SonataAdminExtension(
296
            $this->pool,
297
            null,
298
            $this->createStub(LegacyTranslatorInterface::class)
299
        );
300
    }
301
302
    /**
303
     * @group legacy
304
     * @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).
305
     * @dataProvider getRenderListElementTests
306
     */
307
    public function testRenderListElement(string $expected, string $type, $value, array $options): void
308
    {
309
        $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...
310
            ->method('getPersistentParameters')
311
            ->willReturn(['context' => 'foo']);
312
313
        $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...
314
            ->method('hasAccess')
315
            ->willReturn(true);
316
317
        // NEXT_MAJOR: Remove this line
318
        $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...
319
            ->method('getTemplate')
320
            ->with('base_list_field')
321
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
322
323
        $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...
324
325
        $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...
326
            ->method('getValue')
327
            ->willReturn($value);
328
329
        $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...
330
            ->method('getType')
331
            ->willReturn($type);
332
333
        $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...
334
            ->method('getOptions')
335
            ->willReturn($options);
336
337
        $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...
338
            ->method('getOption')
339
            ->willReturnCallback(static function ($name, $default = null) use ($options) {
340
                return $options[$name] ?? $default;
341
            });
342
343
        $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...
344
            ->method('getTemplate')
345
            ->willReturnCallback(static function () use ($type): ?string {
346
                switch ($type) {
347
                    case 'string':
348
                        return '@SonataAdmin/CRUD/list_string.html.twig';
349
                    case 'boolean':
350
                        return '@SonataAdmin/CRUD/list_boolean.html.twig';
351
                    case 'datetime':
352
                        return '@SonataAdmin/CRUD/list_datetime.html.twig';
353
                    case 'date':
354
                        return '@SonataAdmin/CRUD/list_date.html.twig';
355
                    case 'time':
356
                        return '@SonataAdmin/CRUD/list_time.html.twig';
357
                    case 'currency':
358
                        return '@SonataAdmin/CRUD/list_currency.html.twig';
359
                    case 'percent':
360
                        return '@SonataAdmin/CRUD/list_percent.html.twig';
361
                    case 'email':
362
                        return '@SonataAdmin/CRUD/list_email.html.twig';
363
                    case 'choice':
364
                        return '@SonataAdmin/CRUD/list_choice.html.twig';
365
                    case 'array':
366
                        return '@SonataAdmin/CRUD/list_array.html.twig';
367
                    case 'trans':
368
                        return '@SonataAdmin/CRUD/list_trans.html.twig';
369
                    case 'url':
370
                        return '@SonataAdmin/CRUD/list_url.html.twig';
371
                    case 'html':
372
                        return '@SonataAdmin/CRUD/list_html.html.twig';
373
                    case 'nonexistent':
374
                        // template doesn`t exist
375
                        return '@SonataAdmin/CRUD/list_nonexistent_template.html.twig';
376
                    default:
377
                        return null;
378
                }
379
            });
380
381
        $this->assertSame(
382
            $this->removeExtraWhitespace($expected),
383
            $this->removeExtraWhitespace($this->twigExtension->renderListElement(
384
                $this->environment,
385
                $this->object,
386
                $this->fieldDescription
387
            ))
388
        );
389
    }
390
391
    /**
392
     * @dataProvider getDeprecatedRenderListElementTests
393
     * @group legacy
394
     */
395
    public function testDeprecatedRenderListElement(string $expected, ?string $value, array $options): void
396
    {
397
        $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...
398
            ->method('hasAccess')
399
            ->willReturn(true);
400
401
        // NEXT_MAJOR: Remove this line
402
        $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...
403
            ->method('getTemplate')
404
            ->with('base_list_field')
405
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
406
407
        $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...
408
409
        $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...
410
            ->method('getValue')
411
            ->willReturn($value);
412
413
        $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...
414
            ->method('getType')
415
            ->willReturn('nonexistent');
416
417
        $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...
418
            ->method('getOptions')
419
            ->willReturn($options);
420
421
        $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...
422
            ->method('getOption')
423
            ->willReturnCallback(static function ($name, $default = null) use ($options) {
424
                return $options[$name] ?? $default;
425
            });
426
427
        $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...
428
            ->method('getTemplate')
429
            ->willReturn('@SonataAdmin/CRUD/list_nonexistent_template.html.twig');
430
431
        $this->assertSame(
432
            $this->removeExtraWhitespace($expected),
433
            $this->removeExtraWhitespace($this->twigExtension->renderListElement(
434
                $this->environment,
435
                $this->object,
436
                $this->fieldDescription
437
            ))
438
        );
439
    }
440
441
    public function getDeprecatedRenderListElementTests()
442
    {
443
        return [
444
            [
445
                '<td class="sonata-ba-list-field sonata-ba-list-field-nonexistent" objectId="12345"> Example </td>',
446
                'Example',
447
                [],
448
            ],
449
            [
450
                '<td class="sonata-ba-list-field sonata-ba-list-field-nonexistent" objectId="12345"> </td>',
451
                null,
452
                [],
453
            ],
454
        ];
455
    }
456
457
    public function getRenderListElementTests()
458
    {
459
        return [
460
            [
461
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> Example </td>',
462
                'string',
463
                'Example',
464
                [],
465
            ],
466
            [
467
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> </td>',
468
                'string',
469
                null,
470
                [],
471
            ],
472
            [
473
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> Example </td>',
474
                'text',
475
                'Example',
476
                [],
477
            ],
478
            [
479
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> </td>',
480
                'text',
481
                null,
482
                [],
483
            ],
484
            [
485
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> Example </td>',
486
                'textarea',
487
                'Example',
488
                [],
489
            ],
490
            [
491
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> </td>',
492
                'textarea',
493
                null,
494
                [],
495
            ],
496
            'datetime field' => [
497
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
498
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
499
                        December 24, 2013 10:11
500
                    </time>
501
                </td>',
502
                'datetime',
503
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
504
                [],
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
                        December 24, 2013 18:11
510
                    </time>
511
                </td>',
512
                'datetime',
513
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
514
                ['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
                [],
521
            ],
522
            [
523
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
524
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
525
                        24.12.2013 10:11:12
526
                    </time>
527
                </td>',
528
                'datetime',
529
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
530
                ['format' => 'd.m.Y H:i:s'],
531
            ],
532
            [
533
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
534
                'datetime',
535
                null,
536
                ['format' => 'd.m.Y H:i:s'],
537
            ],
538
            [
539
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
540
                    <time datetime="2013-12-24T10:11:12+00:00" title="2013-12-24T10:11:12+00:00">
541
                        24.12.2013 18:11:12
542
                    </time>
543
                </td>',
544
                'datetime',
545
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
546
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
547
            ],
548
            [
549
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
550
                'datetime',
551
                null,
552
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
553
            ],
554
            [
555
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345">
556
                    <time datetime="2013-12-24" title="2013-12-24">
557
                        December 24, 2013
558
                    </time>
559
                </td>',
560
                'date',
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-date" objectId="12345"> &nbsp; </td>',
566
                'date',
567
                null,
568
                [],
569
            ],
570
            [
571
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345">
572
                    <time datetime="2013-12-24" title="2013-12-24">
573
                        24.12.2013
574
                    </time>
575
                </td>',
576
                'date',
577
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
578
                ['format' => 'd.m.Y'],
579
            ],
580
            [
581
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
582
                'date',
583
                null,
584
                ['format' => 'd.m.Y'],
585
            ],
586
            [
587
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345">
588
                    <time datetime="10:11:12+00:00" title="10:11:12+00:00">
589
                        10:11:12
590
                    </time>
591
                </td>',
592
                'time',
593
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
594
                [],
595
            ],
596
            [
597
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345">
598
                    <time datetime="10:11:12+00:00" title="10:11:12+00:00">
599
                        18:11:12
600
                    </time>
601
                </td>',
602
                'time',
603
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
604
                ['timezone' => 'Asia/Hong_Kong'],
605
            ],
606
            [
607
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> &nbsp; </td>',
608
                'time',
609
                null,
610
                [],
611
            ],
612
            [
613
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> 10.746135 </td>',
614
                'number', 10.746135,
615
                [],
616
            ],
617
            [
618
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> </td>',
619
                'number',
620
                null,
621
                [],
622
            ],
623
            [
624
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> 5678 </td>',
625
                'integer',
626
                5678,
627
                [],
628
            ],
629
            [
630
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> </td>',
631
                'integer',
632
                null,
633
                [],
634
            ],
635
            [
636
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 1074.6135 % </td>',
637
                'percent',
638
                10.746135,
639
                [],
640
            ],
641
            [
642
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 0 % </td>',
643
                'percent',
644
                null,
645
                [],
646
            ],
647
            [
648
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> EUR 10.746135 </td>',
649
                'currency',
650
                10.746135,
651
                ['currency' => 'EUR'],
652
            ],
653
            [
654
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
655
                'currency',
656
                null,
657
                ['currency' => 'EUR'],
658
            ],
659
            [
660
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> GBP 51.23456 </td>',
661
                'currency',
662
                51.23456,
663
                ['currency' => 'GBP'],
664
            ],
665
            [
666
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
667
                'currency',
668
                null,
669
                ['currency' => 'GBP'],
670
            ],
671
            [
672
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> &nbsp; </td>',
673
                'email',
674
                null,
675
                [],
676
            ],
677
            [
678
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> <a href="mailto:[email protected]">[email protected]</a> </td>',
679
                'email',
680
                '[email protected]',
681
                [],
682
            ],
683
            [
684
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
685
                    <a href="mailto:[email protected]">[email protected]</a> </td>',
686
                'email',
687
                '[email protected]',
688
                ['as_string' => false],
689
            ],
690
            [
691
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
692
                'email',
693
                '[email protected]',
694
                ['as_string' => true],
695
            ],
696
            [
697
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
698
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a>  </td>',
699
                'email',
700
                '[email protected]',
701
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
702
            ],
703
            [
704
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
705
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a>  </td>',
706
                'email',
707
                '[email protected]',
708
                ['subject' => 'Main Theme'],
709
            ],
710
            [
711
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
712
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a>  </td>',
713
                'email',
714
                '[email protected]',
715
                ['body' => 'Message Body'],
716
            ],
717
            [
718
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
719
                'email',
720
                '[email protected]',
721
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
722
            ],
723
            [
724
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
725
                'email',
726
                '[email protected]',
727
                ['as_string' => true, 'body' => 'Message Body'],
728
            ],
729
            [
730
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
731
                'email',
732
                '[email protected]',
733
                ['as_string' => true, 'subject' => 'Main Theme'],
734
            ],
735
            [
736
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345">
737
                    [1&nbsp;=>&nbsp;First, 2&nbsp;=>&nbsp;Second]
738
                </td>',
739
                'array',
740
                [1 => 'First', 2 => 'Second'],
741
                [],
742
            ],
743
            [
744
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345"> [] </td>',
745
                'array',
746
                null,
747
                [],
748
            ],
749
            [
750
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
751
                    <span class="label label-success">yes</span>
752
                </td>',
753
                'boolean',
754
                true,
755
                ['editable' => false],
756
            ],
757
            [
758
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
759
                    <span class="label label-danger">no</span>
760
                </td>',
761
                'boolean',
762
                false,
763
                ['editable' => false],
764
            ],
765
            [
766
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
767
                    <span class="label label-danger">no</span>
768
                </td>',
769
                'boolean',
770
                null,
771
                ['editable' => false],
772
            ],
773
            [
774
                <<<'EOT'
775
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
776
    <span
777
        class="x-editable"
778
        data-type="select"
779
        data-value="1"
780
        data-title="Data"
781
        data-pk="12345"
782
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
783
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
784
    >
785
        <span class="label label-success">yes</span>
786
    </span>
787
</td>
788
EOT
789
            ,
790
                'boolean',
791
                true,
792
                ['editable' => true],
793
            ],
794
            [
795
                <<<'EOT'
796
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
797
    <span
798
        class="x-editable"
799
        data-type="select"
800
        data-value="0"
801
        data-title="Data"
802
        data-pk="12345"
803
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
804
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
805
    >
806
    <span class="label label-danger">no</span> </span>
807
</td>
808
EOT
809
                ,
810
                'boolean',
811
                false,
812
                ['editable' => true],
813
            ],
814
            [
815
                <<<'EOT'
816
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
817
    <span
818
        class="x-editable"
819
        data-type="select"
820
        data-value="0"
821
        data-title="Data"
822
        data-pk="12345"
823
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
824
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]" >
825
        <span class="label label-danger">no</span> </span>
826
</td>
827
EOT
828
                ,
829
                'boolean',
830
                null,
831
                ['editable' => true],
832
            ],
833
            [
834
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
835
                'trans',
836
                'action_delete',
837
                ['catalogue' => 'SonataAdminBundle'],
838
            ],
839
            [
840
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> </td>',
841
                'trans',
842
                null,
843
                ['catalogue' => 'SonataAdminBundle'],
844
            ],
845
            [
846
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
847
                'trans',
848
                'action_delete',
849
                ['format' => '%s', 'catalogue' => 'SonataAdminBundle'],
850
            ],
851
            [
852
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
853
                action.action_delete
854
                </td>',
855
                'trans',
856
                'action_delete',
857
                ['format' => 'action.%s'],
858
            ],
859
            [
860
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
861
                action.action_delete
862
                </td>',
863
                'trans',
864
                'action_delete',
865
                ['format' => 'action.%s', 'catalogue' => 'SonataAdminBundle'],
866
            ],
867
            [
868
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
869
                'choice',
870
                'Status1',
871
                [],
872
            ],
873
            [
874
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
875
                'choice',
876
                ['Status1'],
877
                ['choices' => [], 'multiple' => true],
878
            ],
879
            [
880
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 </td>',
881
                'choice',
882
                'Status1',
883
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
884
            ],
885
            [
886
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
887
                'choice',
888
                null,
889
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
890
            ],
891
            [
892
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
893
                NoValidKeyInChoices
894
                </td>',
895
                'choice',
896
                'NoValidKeyInChoices',
897
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
898
            ],
899
            [
900
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete </td>',
901
                'choice',
902
                'Foo',
903
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
904
                    'Foo' => 'action_delete',
905
                    'Status2' => 'Alias2',
906
                    'Status3' => 'Alias3',
907
                ]],
908
            ],
909
            [
910
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1, Alias3 </td>',
911
                'choice',
912
                ['Status1', 'Status3'],
913
                ['choices' => [
914
                    'Status1' => 'Alias1',
915
                    'Status2' => 'Alias2',
916
                    'Status3' => 'Alias3',
917
                ], 'multiple' => true], ],
918
            [
919
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 | Alias3 </td>',
920
                'choice',
921
                ['Status1', 'Status3'],
922
                ['choices' => [
923
                    'Status1' => 'Alias1',
924
                    'Status2' => 'Alias2',
925
                    'Status3' => 'Alias3',
926
                ], 'multiple' => true, 'delimiter' => ' | '], ],
927
            [
928
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
929
                'choice',
930
                null,
931
                ['choices' => [
932
                    'Status1' => 'Alias1',
933
                    'Status2' => 'Alias2',
934
                    'Status3' => 'Alias3',
935
                ], 'multiple' => true],
936
            ],
937
            [
938
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
939
                NoValidKeyInChoices
940
                </td>',
941
                'choice',
942
                ['NoValidKeyInChoices'],
943
                ['choices' => [
944
                    'Status1' => 'Alias1',
945
                    'Status2' => 'Alias2',
946
                    'Status3' => 'Alias3',
947
                ], 'multiple' => true],
948
            ],
949
            [
950
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
951
                NoValidKeyInChoices, Alias2
952
                </td>',
953
                'choice',
954
                ['NoValidKeyInChoices', 'Status2'],
955
                ['choices' => [
956
                    'Status1' => 'Alias1',
957
                    'Status2' => 'Alias2',
958
                    'Status3' => 'Alias3',
959
                ], 'multiple' => true],
960
            ],
961
            [
962
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete, Alias3 </td>',
963
                'choice',
964
                ['Foo', 'Status3'],
965
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
966
                    'Foo' => 'action_delete',
967
                    'Status2' => 'Alias2',
968
                    'Status3' => 'Alias3',
969
                ], 'multiple' => true],
970
            ],
971
            [
972
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
973
                &lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;
974
            </td>',
975
                'choice',
976
                ['Status1', 'Status3'],
977
                ['choices' => [
978
                    'Status1' => '<b>Alias1</b>',
979
                    'Status2' => '<b>Alias2</b>',
980
                    'Status3' => '<b>Alias3</b>',
981
                ], 'multiple' => true], ],
982
            [
983
                <<<'EOT'
984
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
985
    <span
986
        class="x-editable"
987
        data-type="select"
988
        data-value="Status1"
989
        data-title="Data"
990
        data-pk="12345"
991
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
992
        data-source="[]"
993
    >
994
        Status1
995
    </span>
996
</td>
997
EOT
998
                ,
999
                'choice',
1000
                'Status1',
1001
                ['editable' => true],
1002
            ],
1003
            [
1004
                <<<'EOT'
1005
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1006
    <span
1007
        class="x-editable"
1008
        data-type="select"
1009
        data-value="Status1"
1010
        data-title="Data"
1011
        data-pk="12345"
1012
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1013
        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;}]" >
1014
        Alias1 </span>
1015
</td>
1016
EOT
1017
                ,
1018
                'choice',
1019
                'Status1',
1020
                [
1021
                    'editable' => true,
1022
                    'choices' => [
1023
                        'Status1' => 'Alias1',
1024
                        'Status2' => 'Alias2',
1025
                        'Status3' => 'Alias3',
1026
                    ],
1027
                ],
1028
            ],
1029
            [
1030
                <<<'EOT'
1031
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1032
    <span
1033
        class="x-editable"
1034
        data-type="select"
1035
        data-value=""
1036
        data-title="Data"
1037
        data-pk="12345"
1038
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1039
        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;}]" >
1040
1041
    </span>
1042
</td>
1043
EOT
1044
                ,
1045
                'choice',
1046
                null,
1047
                [
1048
                    'editable' => true,
1049
                    'choices' => [
1050
                        'Status1' => 'Alias1',
1051
                        'Status2' => 'Alias2',
1052
                        'Status3' => 'Alias3',
1053
                    ],
1054
                ],
1055
            ],
1056
            [
1057
                <<<'EOT'
1058
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1059
    <span
1060
        class="x-editable"
1061
        data-type="select"
1062
        data-value="NoValidKeyInChoices"
1063
        data-title="Data" data-pk="12345"
1064
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1065
        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;}]" >
1066
        NoValidKeyInChoices
1067
    </span>
1068
</td>
1069
EOT
1070
                ,
1071
                'choice',
1072
                'NoValidKeyInChoices',
1073
                [
1074
                    'editable' => true,
1075
                    'choices' => [
1076
                        'Status1' => 'Alias1',
1077
                        'Status2' => 'Alias2',
1078
                        'Status3' => 'Alias3',
1079
                    ],
1080
                ],
1081
            ],
1082
            [
1083
                <<<'EOT'
1084
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1085
    <span
1086
        class="x-editable"
1087
        data-type="select"
1088
        data-value="Foo"
1089
        data-title="Data"
1090
        data-pk="12345"
1091
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1092
        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;}]" >
1093
         Delete
1094
    </span>
1095
</td>
1096
EOT
1097
                ,
1098
                'choice',
1099
                'Foo',
1100
                [
1101
                    'editable' => true,
1102
                    'catalogue' => 'SonataAdminBundle',
1103
                    'choices' => [
1104
                        'Foo' => 'action_delete',
1105
                        'Status2' => 'Alias2',
1106
                        'Status3' => 'Alias3',
1107
                    ],
1108
                ],
1109
            ],
1110
            [
1111
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1112
                'url',
1113
                null,
1114
                [],
1115
            ],
1116
            [
1117
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1118
                'url',
1119
                null,
1120
                ['url' => 'http://example.com'],
1121
            ],
1122
            [
1123
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1124
                'url',
1125
                null,
1126
                ['route' => ['name' => 'sonata_admin_foo']],
1127
            ],
1128
            [
1129
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1130
                <a href="http://example.com">http://example.com</a>
1131
                </td>',
1132
                'url',
1133
                'http://example.com',
1134
                [],
1135
            ],
1136
            [
1137
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1138
                <a href="https://example.com">https://example.com</a>
1139
                </td>',
1140
                'url',
1141
                'https://example.com',
1142
                [],
1143
            ],
1144
            [
1145
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1146
                <a href="https://example.com" target="_blank">https://example.com</a>
1147
                </td>',
1148
                'url',
1149
                'https://example.com',
1150
                ['attributes' => ['target' => '_blank']],
1151
            ],
1152
            [
1153
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1154
                <a href="https://example.com" target="_blank" class="fooLink">https://example.com</a>
1155
                </td>',
1156
                'url',
1157
                'https://example.com',
1158
                ['attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1159
            ],
1160
            [
1161
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1162
                <a href="http://example.com">example.com</a>
1163
                </td>',
1164
                'url',
1165
                'http://example.com',
1166
                ['hide_protocol' => true],
1167
            ],
1168
            [
1169
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1170
                <a href="https://example.com">example.com</a>
1171
                </td>',
1172
                'url',
1173
                'https://example.com',
1174
                ['hide_protocol' => true],
1175
            ],
1176
            [
1177
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1178
                <a href="http://example.com">http://example.com</a>
1179
                </td>',
1180
                'url',
1181
                'http://example.com',
1182
                ['hide_protocol' => false],
1183
            ],
1184
            [
1185
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1186
                <a href="https://example.com">https://example.com</a>
1187
                </td>',
1188
                'url',
1189
                'https://example.com',
1190
                ['hide_protocol' => false],
1191
            ],
1192
            [
1193
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1194
                <a href="http://example.com">Foo</a>
1195
                </td>',
1196
                'url',
1197
                'Foo',
1198
                ['url' => 'http://example.com'],
1199
            ],
1200
            [
1201
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1202
                <a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a>
1203
                </td>',
1204
                'url',
1205
                '<b>Foo</b>',
1206
                ['url' => 'http://example.com'],
1207
            ],
1208
            [
1209
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1210
                <a href="/foo">Foo</a>
1211
                </td>',
1212
                'url',
1213
                'Foo',
1214
                ['route' => ['name' => 'sonata_admin_foo']],
1215
            ],
1216
            [
1217
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1218
                <a href="http://localhost/foo">Foo</a>
1219
                </td>',
1220
                'url',
1221
                'Foo',
1222
                ['route' => ['name' => 'sonata_admin_foo', 'absolute' => true]],
1223
            ],
1224
            [
1225
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1226
                <a href="/foo">foo/bar?a=b&amp;c=123456789</a>
1227
                </td>',
1228
                'url',
1229
                'http://foo/bar?a=b&c=123456789',
1230
                ['route' => ['name' => 'sonata_admin_foo'],
1231
                'hide_protocol' => true, ],
1232
            ],
1233
            [
1234
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1235
                <a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a>
1236
                </td>',
1237
                'url',
1238
                'http://foo/bar?a=b&c=123456789',
1239
                [
1240
                    'route' => ['name' => 'sonata_admin_foo', 'absolute' => true],
1241
                    'hide_protocol' => true,
1242
                ],
1243
            ],
1244
            [
1245
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1246
                <a href="/foo/abcd/efgh?param3=ijkl">Foo</a>
1247
                </td>',
1248
                'url',
1249
                'Foo',
1250
                [
1251
                    'route' => ['name' => 'sonata_admin_foo_param',
1252
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1253
                ],
1254
            ],
1255
            [
1256
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1257
                <a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a>
1258
                </td>',
1259
                'url',
1260
                'Foo',
1261
                [
1262
                    'route' => ['name' => 'sonata_admin_foo_param',
1263
                    'absolute' => true,
1264
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1265
                ],
1266
            ],
1267
            [
1268
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1269
                <a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1270
                </td>',
1271
                'url',
1272
                'Foo',
1273
                [
1274
                    'route' => ['name' => 'sonata_admin_foo_object',
1275
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1276
                    'identifier_parameter_name' => 'barId', ],
1277
                ],
1278
            ],
1279
            [
1280
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1281
                <a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1282
                </td>',
1283
                'url',
1284
                'Foo',
1285
                [
1286
                    'route' => ['name' => 'sonata_admin_foo_object',
1287
                    'absolute' => true,
1288
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1289
                    'identifier_parameter_name' => 'barId', ],
1290
                ],
1291
            ],
1292
            [
1293
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1294
                <p><strong>Creating a Template for the Field</strong> and form</p>
1295
                </td>',
1296
                'html',
1297
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1298
                [],
1299
            ],
1300
            [
1301
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1302
                Creating a Template for the Field and form
1303
                </td>',
1304
                'html',
1305
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1306
                ['strip' => true],
1307
            ],
1308
            [
1309
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1310
                Creating a Template for the...
1311
                </td>',
1312
                'html',
1313
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1314
                ['truncate' => true],
1315
            ],
1316
            [
1317
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345"> Creatin... </td>',
1318
                'html',
1319
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1320
                ['truncate' => ['length' => 10]],
1321
            ],
1322
            [
1323
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1324
                Creating a Template for the Field...
1325
                </td>',
1326
                'html',
1327
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1328
                ['truncate' => ['cut' => false]],
1329
            ],
1330
            [
1331
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1332
                Creating a Template for t etc.
1333
                </td>',
1334
                'html',
1335
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1336
                ['truncate' => ['ellipsis' => ' etc.']],
1337
            ],
1338
            [
1339
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1340
                Creating a Template[...]
1341
                </td>',
1342
                'html',
1343
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1344
                [
1345
                    'truncate' => [
1346
                        'length' => 20,
1347
                        'cut' => false,
1348
                        'ellipsis' => '[...]',
1349
                    ],
1350
                ],
1351
            ],
1352
1353
            [
1354
                <<<'EOT'
1355
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1356
<div
1357
    class="sonata-readmore"
1358
    data-readmore-height="40"
1359
    data-readmore-more="Read more"
1360
    data-readmore-less="Close">A very long string</div>
1361
</td>
1362
EOT
1363
                ,
1364
                'text',
1365
                'A very long string',
1366
                [
1367
                    'collapse' => true,
1368
                ],
1369
            ],
1370
            [
1371
                <<<'EOT'
1372
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1373
<div
1374
    class="sonata-readmore"
1375
    data-readmore-height="10"
1376
    data-readmore-more="More"
1377
    data-readmore-less="Less">A very long string</div>
1378
</td>
1379
EOT
1380
                ,
1381
                'text',
1382
                'A very long string',
1383
                [
1384
                    'collapse' => [
1385
                        'height' => 10,
1386
                        'more' => 'More',
1387
                        'less' => 'Less',
1388
                    ],
1389
                ],
1390
            ],
1391
            [
1392
                <<<'EOT'
1393
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1394
    <span
1395
        class="x-editable"
1396
        data-type="checklist"
1397
        data-value="[&quot;Status1&quot;,&quot;Status2&quot;]"
1398
        data-title="Data"
1399
        data-pk="12345"
1400
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1401
        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;}]" >
1402
         Delete, Alias2
1403
    </span>
1404
</td>
1405
EOT
1406
                ,
1407
                'choice',
1408
                [
1409
                    'Status1',
1410
                    'Status2',
1411
                ],
1412
                [
1413
                    'editable' => true,
1414
                    'multiple' => true,
1415
                    'catalogue' => 'SonataAdminBundle',
1416
                    'choices' => [
1417
                        'Status1' => 'action_delete',
1418
                        'Status2' => 'Alias2',
1419
                        'Status3' => 'Alias3',
1420
                    ],
1421
                ],
1422
            ],
1423
        ];
1424
    }
1425
1426
    /**
1427
     * @group legacy
1428
     */
1429
    public function testRenderListElementNonExistentTemplate(): void
1430
    {
1431
        // NEXT_MAJOR: Remove this line
1432
        $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...
1433
            ->with('base_list_field')
1434
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
1435
1436
        $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...
1437
1438
        $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...
1439
            ->method('getValue')
1440
            ->willReturn('Foo');
1441
1442
        $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...
1443
            ->method('getFieldName')
1444
            ->willReturn('Foo_name');
1445
1446
        $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...
1447
            ->method('getType')
1448
            ->willReturn('nonexistent');
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->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...
1455
            ->method('warning')
1456
            ->with(($this->stringStartsWith($this->removeExtraWhitespace(
1457
                'An error occured trying to load the template
1458
                "@SonataAdmin/CRUD/list_nonexistent_template.html.twig"
1459
                for the field "Foo_name", the default template
1460
                    "@SonataAdmin/CRUD/base_list_field.html.twig" was used
1461
                    instead.'
1462
            ))));
1463
1464
        $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription);
1465
    }
1466
1467
    /**
1468
     * @group                    legacy
1469
     */
1470
    public function testRenderListElementErrorLoadingTemplate(): void
1471
    {
1472
        $this->expectException(LoaderError::class);
1473
        $this->expectExceptionMessage('Unable to find template "@SonataAdmin/CRUD/base_list_nonexistent_field.html.twig"');
1474
1475
        // NEXT_MAJOR: Remove this line
1476
        $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...
1477
            ->with('base_list_field')
1478
            ->willReturn('@SonataAdmin/CRUD/base_list_nonexistent_field.html.twig');
1479
1480
        $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...
1481
1482
        $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...
1483
            ->method('getTemplate')
1484
            ->willReturn('@SonataAdmin/CRUD/list_nonexistent_template.html.twig');
1485
1486
        $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription);
1487
1488
        $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...
1489
    }
1490
1491
    /**
1492
     * @dataProvider getRenderViewElementTests
1493
     */
1494
    public function testRenderViewElement(string $expected, string $type, $value, array $options): void
1495
    {
1496
        $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...
1497
            ->method('getTemplate')
1498
            ->willReturn('@SonataAdmin/CRUD/base_show_field.html.twig');
1499
1500
        $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...
1501
            ->method('getValue')
1502
            ->willReturn($value);
1503
1504
        $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...
1505
            ->method('getType')
1506
            ->willReturn($type);
1507
1508
        $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...
1509
            ->method('getOptions')
1510
            ->willReturn($options);
1511
1512
        $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...
1513
            ->method('getTemplate')
1514
            ->willReturnCallback(static function () use ($type): ?string {
1515
                switch ($type) {
1516
                    case 'boolean':
1517
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
1518
                    case 'datetime':
1519
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
1520
                    case 'date':
1521
                        return '@SonataAdmin/CRUD/show_date.html.twig';
1522
                    case 'time':
1523
                        return '@SonataAdmin/CRUD/show_time.html.twig';
1524
                    case 'currency':
1525
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
1526
                    case 'percent':
1527
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
1528
                    case 'email':
1529
                        return '@SonataAdmin/CRUD/show_email.html.twig';
1530
                    case 'choice':
1531
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
1532
                    case 'array':
1533
                        return '@SonataAdmin/CRUD/show_array.html.twig';
1534
                    case 'trans':
1535
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
1536
                    case 'url':
1537
                        return '@SonataAdmin/CRUD/show_url.html.twig';
1538
                    case 'html':
1539
                        return '@SonataAdmin/CRUD/show_html.html.twig';
1540
                    default:
1541
                        return null;
1542
                }
1543
            });
1544
1545
        $this->assertSame(
1546
            $this->removeExtraWhitespace($expected),
1547
            $this->removeExtraWhitespace(
1548
                $this->twigExtension->renderViewElement(
1549
                    $this->environment,
1550
                    $this->fieldDescription,
1551
                    $this->object
1552
                )
1553
            )
1554
        );
1555
    }
1556
1557
    public function getRenderViewElementTests()
1558
    {
1559
        return [
1560
            ['<th>Data</th> <td>Example</td>', 'string', 'Example', ['safe' => false]],
1561
            ['<th>Data</th> <td>Example</td>', 'text', 'Example', ['safe' => false]],
1562
            ['<th>Data</th> <td>Example</td>', 'textarea', 'Example', ['safe' => false]],
1563
            [
1564
                '<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>',
1565
                'datetime',
1566
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), [],
1567
            ],
1568
            [
1569
                '<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>',
1570
                'datetime',
1571
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1572
                ['format' => 'd.m.Y H:i:s'],
1573
            ],
1574
            [
1575
                '<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>',
1576
                'datetime',
1577
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1578
                ['timezone' => 'Asia/Hong_Kong'],
1579
            ],
1580
            [
1581
                '<th>Data</th> <td><time datetime="2013-12-24" title="2013-12-24"> December 24, 2013 </time></td>',
1582
                'date',
1583
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1584
                [],
1585
            ],
1586
            [
1587
                '<th>Data</th> <td><time datetime="2013-12-24" title="2013-12-24"> 24.12.2013 </time></td>',
1588
                'date',
1589
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1590
                ['format' => 'd.m.Y'],
1591
            ],
1592
            [
1593
                '<th>Data</th> <td><time datetime="10:11:12+00:00" title="10:11:12+00:00"> 10:11:12 </time></td>',
1594
                'time',
1595
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1596
                [],
1597
            ],
1598
            [
1599
                '<th>Data</th> <td><time datetime="10:11:12+00:00" title="10:11:12+00:00"> 18:11:12 </time></td>',
1600
                'time',
1601
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1602
                ['timezone' => 'Asia/Hong_Kong'],
1603
            ],
1604
            ['<th>Data</th> <td>10.746135</td>', 'number', 10.746135, ['safe' => false]],
1605
            ['<th>Data</th> <td>5678</td>', 'integer', 5678, ['safe' => false]],
1606
            ['<th>Data</th> <td> 1074.6135 % </td>', 'percent', 10.746135, []],
1607
            ['<th>Data</th> <td> EUR 10.746135 </td>', 'currency', 10.746135, ['currency' => 'EUR']],
1608
            ['<th>Data</th> <td> GBP 51.23456 </td>', 'currency', 51.23456, ['currency' => 'GBP']],
1609
            [
1610
                '<th>Data</th> <td> <ul><li>1&nbsp;=>&nbsp;First</li><li>2&nbsp;=>&nbsp;Second</li></ul> </td>',
1611
                'array',
1612
                [1 => 'First', 2 => 'Second'],
1613
                ['safe' => false],
1614
            ],
1615
            [
1616
                '<th>Data</th> <td> [1&nbsp;=>&nbsp;First, 2&nbsp;=>&nbsp;Second] </td>',
1617
                'array',
1618
                [1 => 'First', 2 => 'Second'],
1619
                ['safe' => false, 'inline' => true],
1620
            ],
1621
            [
1622
                '<th>Data</th> <td><span class="label label-success">yes</span></td>',
1623
                'boolean',
1624
                true,
1625
                [],
1626
            ],
1627
            [
1628
                '<th>Data</th> <td><span class="label label-danger">yes</span></td>',
1629
                'boolean',
1630
                true,
1631
                ['inverse' => true],
1632
            ],
1633
            ['<th>Data</th> <td><span class="label label-danger">no</span></td>', 'boolean', false, []],
1634
            [
1635
                '<th>Data</th> <td><span class="label label-success">no</span></td>',
1636
                'boolean',
1637
                false,
1638
                ['inverse' => true],
1639
            ],
1640
            [
1641
                '<th>Data</th> <td> Delete </td>',
1642
                'trans',
1643
                'action_delete',
1644
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1645
            ],
1646
            [
1647
                '<th>Data</th> <td> Delete </td>',
1648
                'trans',
1649
                'delete',
1650
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'format' => 'action_%s'],
1651
            ],
1652
            ['<th>Data</th> <td>Status1</td>', 'choice', 'Status1', ['safe' => false]],
1653
            [
1654
                '<th>Data</th> <td>Alias1</td>',
1655
                'choice',
1656
                'Status1',
1657
                ['safe' => false, 'choices' => [
1658
                    'Status1' => 'Alias1',
1659
                    'Status2' => 'Alias2',
1660
                    'Status3' => 'Alias3',
1661
                ]],
1662
            ],
1663
            [
1664
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1665
                'choice',
1666
                'NoValidKeyInChoices',
1667
                ['safe' => false, 'choices' => [
1668
                    'Status1' => 'Alias1',
1669
                    'Status2' => 'Alias2',
1670
                    'Status3' => 'Alias3',
1671
                ]],
1672
            ],
1673
            [
1674
                '<th>Data</th> <td>Delete</td>',
1675
                'choice',
1676
                'Foo',
1677
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1678
                    'Foo' => 'action_delete',
1679
                    'Status2' => 'Alias2',
1680
                    'Status3' => 'Alias3',
1681
                ]],
1682
            ],
1683
            [
1684
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1685
                'choice',
1686
                ['NoValidKeyInChoices'],
1687
                ['safe' => false, 'choices' => [
1688
                    'Status1' => 'Alias1',
1689
                    'Status2' => 'Alias2',
1690
                    'Status3' => 'Alias3',
1691
                ], 'multiple' => true],
1692
            ],
1693
            [
1694
                '<th>Data</th> <td>NoValidKeyInChoices, Alias2</td>',
1695
                'choice',
1696
                ['NoValidKeyInChoices', 'Status2'],
1697
                ['safe' => false, 'choices' => [
1698
                    'Status1' => 'Alias1',
1699
                    'Status2' => 'Alias2',
1700
                    'Status3' => 'Alias3',
1701
                ], 'multiple' => true],
1702
            ],
1703
            [
1704
                '<th>Data</th> <td>Alias1, Alias3</td>',
1705
                'choice',
1706
                ['Status1', 'Status3'],
1707
                ['safe' => false, 'choices' => [
1708
                    'Status1' => 'Alias1',
1709
                    'Status2' => 'Alias2',
1710
                    'Status3' => 'Alias3',
1711
                ], 'multiple' => true],
1712
            ],
1713
            [
1714
                '<th>Data</th> <td>Alias1 | Alias3</td>',
1715
                'choice',
1716
                ['Status1', 'Status3'], ['safe' => false, 'choices' => [
1717
                    'Status1' => 'Alias1',
1718
                    'Status2' => 'Alias2',
1719
                    'Status3' => 'Alias3',
1720
                ], 'multiple' => true, 'delimiter' => ' | '],
1721
            ],
1722
            [
1723
                '<th>Data</th> <td>Delete, Alias3</td>',
1724
                'choice',
1725
                ['Foo', 'Status3'],
1726
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1727
                    'Foo' => 'action_delete',
1728
                    'Status2' => 'Alias2',
1729
                    'Status3' => 'Alias3',
1730
                ], 'multiple' => true],
1731
            ],
1732
            [
1733
                '<th>Data</th> <td><b>Alias1</b>, <b>Alias3</b></td>',
1734
                'choice',
1735
                ['Status1', 'Status3'],
1736
                ['safe' => true, 'choices' => [
1737
                    'Status1' => '<b>Alias1</b>',
1738
                    'Status2' => '<b>Alias2</b>',
1739
                    'Status3' => '<b>Alias3</b>',
1740
                ], 'multiple' => true],
1741
            ],
1742
            [
1743
                '<th>Data</th> <td>&lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;</td>',
1744
                'choice',
1745
                ['Status1', 'Status3'],
1746
                ['safe' => false, 'choices' => [
1747
                    'Status1' => '<b>Alias1</b>',
1748
                    'Status2' => '<b>Alias2</b>',
1749
                    'Status3' => '<b>Alias3</b>',
1750
                ], 'multiple' => true],
1751
            ],
1752
            [
1753
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1754
                'url',
1755
                'http://example.com',
1756
                ['safe' => false],
1757
            ],
1758
            [
1759
                '<th>Data</th> <td><a href="http://example.com" target="_blank">http://example.com</a></td>',
1760
                'url',
1761
                'http://example.com',
1762
                ['safe' => false, 'attributes' => ['target' => '_blank']],
1763
            ],
1764
            [
1765
                '<th>Data</th> <td><a href="http://example.com" target="_blank" class="fooLink">http://example.com</a></td>',
1766
                'url',
1767
                'http://example.com',
1768
                ['safe' => false, 'attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1769
            ],
1770
            [
1771
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1772
                'url',
1773
                'https://example.com',
1774
                ['safe' => false],
1775
            ],
1776
            [
1777
                '<th>Data</th> <td><a href="http://example.com">example.com</a></td>',
1778
                'url',
1779
                'http://example.com',
1780
                ['safe' => false, 'hide_protocol' => true],
1781
            ],
1782
            [
1783
                '<th>Data</th> <td><a href="https://example.com">example.com</a></td>',
1784
                'url',
1785
                'https://example.com',
1786
                ['safe' => false, 'hide_protocol' => true],
1787
            ],
1788
            [
1789
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1790
                'url',
1791
                'http://example.com',
1792
                ['safe' => false, 'hide_protocol' => false],
1793
            ],
1794
            [
1795
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1796
                'url',
1797
                'https://example.com',
1798
                ['safe' => false,
1799
                'hide_protocol' => false, ],
1800
            ],
1801
            [
1802
                '<th>Data</th> <td><a href="http://example.com">Foo</a></td>',
1803
                'url',
1804
                'Foo',
1805
                ['safe' => false, 'url' => 'http://example.com'],
1806
            ],
1807
            [
1808
                '<th>Data</th> <td><a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a></td>',
1809
                'url',
1810
                '<b>Foo</b>',
1811
                ['safe' => false, 'url' => 'http://example.com'],
1812
            ],
1813
            [
1814
                '<th>Data</th> <td><a href="http://example.com"><b>Foo</b></a></td>',
1815
                'url',
1816
                '<b>Foo</b>',
1817
                ['safe' => true, 'url' => 'http://example.com'],
1818
            ],
1819
            [
1820
                '<th>Data</th> <td><a href="/foo">Foo</a></td>',
1821
                'url',
1822
                'Foo',
1823
                ['safe' => false, 'route' => ['name' => 'sonata_admin_foo']],
1824
            ],
1825
            [
1826
                '<th>Data</th> <td><a href="http://localhost/foo">Foo</a></td>',
1827
                'url',
1828
                'Foo',
1829
                ['safe' => false, 'route' => [
1830
                    'name' => 'sonata_admin_foo',
1831
                    'absolute' => true,
1832
                ]],
1833
            ],
1834
            [
1835
                '<th>Data</th> <td><a href="/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1836
                'url',
1837
                'http://foo/bar?a=b&c=123456789',
1838
                [
1839
                    'safe' => false,
1840
                    'route' => ['name' => 'sonata_admin_foo'],
1841
                    'hide_protocol' => true,
1842
                ],
1843
            ],
1844
            [
1845
                '<th>Data</th> <td><a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1846
                'url',
1847
                'http://foo/bar?a=b&c=123456789',
1848
                ['safe' => false, 'route' => [
1849
                    'name' => 'sonata_admin_foo',
1850
                    'absolute' => true,
1851
                ], 'hide_protocol' => true],
1852
            ],
1853
            [
1854
                '<th>Data</th> <td><a href="/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1855
                'url',
1856
                'Foo',
1857
                ['safe' => false, 'route' => [
1858
                    'name' => 'sonata_admin_foo_param',
1859
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1860
                ]],
1861
            ],
1862
            [
1863
                '<th>Data</th> <td><a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1864
                'url',
1865
                'Foo',
1866
                ['safe' => false, 'route' => [
1867
                    'name' => 'sonata_admin_foo_param',
1868
                    'absolute' => true,
1869
                    'parameters' => [
1870
                        'param1' => 'abcd',
1871
                        'param2' => 'efgh',
1872
                        'param3' => 'ijkl',
1873
                    ],
1874
                ]],
1875
            ],
1876
            [
1877
                '<th>Data</th> <td><a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1878
                'url',
1879
                'Foo',
1880
                ['safe' => false, 'route' => [
1881
                    'name' => 'sonata_admin_foo_object',
1882
                    'parameters' => [
1883
                        'param1' => 'abcd',
1884
                        'param2' => 'efgh',
1885
                        'param3' => 'ijkl',
1886
                    ],
1887
                    'identifier_parameter_name' => 'barId',
1888
                ]],
1889
            ],
1890
            [
1891
                '<th>Data</th> <td><a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1892
                'url',
1893
                'Foo',
1894
                ['safe' => false, 'route' => [
1895
                    'name' => 'sonata_admin_foo_object',
1896
                    'absolute' => true,
1897
                    'parameters' => [
1898
                        'param1' => 'abcd',
1899
                        'param2' => 'efgh',
1900
                        'param3' => 'ijkl',
1901
                    ],
1902
                    'identifier_parameter_name' => 'barId',
1903
                ]],
1904
            ],
1905
            [
1906
                '<th>Data</th> <td> &nbsp;</td>',
1907
                'email',
1908
                null,
1909
                [],
1910
            ],
1911
            [
1912
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1913
                'email',
1914
                '[email protected]',
1915
                [],
1916
            ],
1917
            [
1918
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a></td>',
1919
                'email',
1920
                '[email protected]',
1921
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
1922
            ],
1923
            [
1924
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a></td>',
1925
                'email',
1926
                '[email protected]',
1927
                ['subject' => 'Main Theme'],
1928
            ],
1929
            [
1930
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a></td>',
1931
                'email',
1932
                '[email protected]',
1933
                ['body' => 'Message Body'],
1934
            ],
1935
            [
1936
                '<th>Data</th> <td> [email protected]</td>',
1937
                'email',
1938
                '[email protected]',
1939
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
1940
            ],
1941
            [
1942
                '<th>Data</th> <td> [email protected]</td>',
1943
                'email',
1944
                '[email protected]',
1945
                ['as_string' => true, 'subject' => 'Main Theme'],
1946
            ],
1947
            [
1948
                '<th>Data</th> <td> [email protected]</td>',
1949
                'email',
1950
                '[email protected]',
1951
                ['as_string' => true, 'body' => 'Message Body'],
1952
            ],
1953
            [
1954
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1955
                'email',
1956
                '[email protected]',
1957
                ['as_string' => false],
1958
            ],
1959
            [
1960
                '<th>Data</th> <td> [email protected]</td>',
1961
                'email',
1962
                '[email protected]',
1963
                ['as_string' => true],
1964
            ],
1965
            [
1966
                '<th>Data</th> <td><p><strong>Creating a Template for the Field</strong> and form</p> </td>',
1967
                'html',
1968
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1969
                [],
1970
            ],
1971
            [
1972
                '<th>Data</th> <td>Creating a Template for the Field and form </td>',
1973
                'html',
1974
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1975
                ['strip' => true],
1976
            ],
1977
            [
1978
                '<th>Data</th> <td> Creating a Template for the... </td>',
1979
                'html',
1980
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1981
                ['truncate' => true],
1982
            ],
1983
            [
1984
                '<th>Data</th> <td> Creatin... </td>',
1985
                'html',
1986
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1987
                ['truncate' => ['length' => 10]],
1988
            ],
1989
            [
1990
                '<th>Data</th> <td> Creating a Template for the Field... </td>',
1991
                'html',
1992
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1993
                ['truncate' => ['cut' => false]],
1994
            ],
1995
            [
1996
                '<th>Data</th> <td> Creating a Template for t etc. </td>',
1997
                'html',
1998
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1999
                ['truncate' => ['ellipsis' => ' etc.']],
2000
            ],
2001
            [
2002
                '<th>Data</th> <td> Creating a Template[...] </td>',
2003
                'html',
2004
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
2005
                [
2006
                    'truncate' => [
2007
                        'length' => 20,
2008
                        'cut' => false,
2009
                        'ellipsis' => '[...]',
2010
                    ],
2011
                ],
2012
            ],
2013
            [
2014
                <<<'EOT'
2015
<th>Data</th> <td><div
2016
        class="sonata-readmore"
2017
        data-readmore-height="40"
2018
        data-readmore-more="Read more"
2019
        data-readmore-less="Close">
2020
            A very long string
2021
</div></td>
2022
EOT
2023
                ,
2024
                'text',
2025
                ' A very long string ',
2026
                [
2027
                    'collapse' => true,
2028
                    'safe' => false,
2029
                ],
2030
            ],
2031
            [
2032
                <<<'EOT'
2033
<th>Data</th> <td><div
2034
        class="sonata-readmore"
2035
        data-readmore-height="10"
2036
        data-readmore-more="More"
2037
        data-readmore-less="Less">
2038
            A very long string
2039
</div></td>
2040
EOT
2041
                ,
2042
                'text',
2043
                ' A very long string ',
2044
                [
2045
                    'collapse' => [
2046
                        'height' => 10,
2047
                        'more' => 'More',
2048
                        'less' => 'Less',
2049
                    ],
2050
                    'safe' => false,
2051
                ],
2052
            ],
2053
        ];
2054
    }
2055
2056
    /**
2057
     * @group legacy
2058
     * @assertDeprecation Accessing a non existing value is deprecated since sonata-project/admin-bundle 3.67 and will throw an exception in 4.0.
2059
     *
2060
     * @dataProvider getRenderViewElementWithNoValueTests
2061
     */
2062
    public function testRenderViewElementWithNoValue(string $expected, string $type, array $options): void
2063
    {
2064
        $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...
2065
            ->method('getTemplate')
2066
            ->willReturn('@SonataAdmin/CRUD/base_show_field.html.twig');
2067
2068
        $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...
2069
            ->method('getValue')
2070
            ->willThrowException(new NoValueException());
2071
2072
        $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...
2073
            ->method('getType')
2074
            ->willReturn($type);
2075
2076
        $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...
2077
            ->method('getOptions')
2078
            ->willReturn($options);
2079
2080
        $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...
2081
            ->method('getTemplate')
2082
            ->willReturnCallback(static function () use ($type): ?string {
2083
                switch ($type) {
2084
                    case 'boolean':
2085
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
2086
                    case 'datetime':
2087
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
2088
                    case 'date':
2089
                        return '@SonataAdmin/CRUD/show_date.html.twig';
2090
                    case 'time':
2091
                        return '@SonataAdmin/CRUD/show_time.html.twig';
2092
                    case 'currency':
2093
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
2094
                    case 'percent':
2095
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
2096
                    case 'email':
2097
                        return '@SonataAdmin/CRUD/show_email.html.twig';
2098
                    case 'choice':
2099
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
2100
                    case 'array':
2101
                        return '@SonataAdmin/CRUD/show_array.html.twig';
2102
                    case 'trans':
2103
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
2104
                    case 'url':
2105
                        return '@SonataAdmin/CRUD/show_url.html.twig';
2106
                    case 'html':
2107
                        return '@SonataAdmin/CRUD/show_html.html.twig';
2108
                    default:
2109
                        return null;
2110
                }
2111
            });
2112
2113
        $this->assertSame(
2114
            $this->removeExtraWhitespace($expected),
2115
            $this->removeExtraWhitespace(
2116
                $this->twigExtension->renderViewElement(
2117
                    $this->environment,
2118
                    $this->fieldDescription,
2119
                    $this->object
2120
                )
2121
            )
2122
        );
2123
    }
2124
2125
    public function getRenderViewElementWithNoValueTests(): iterable
2126
    {
2127
        return [
2128
            // NoValueException
2129
            ['<th>Data</th> <td></td>', 'string', ['safe' => false]],
2130
            ['<th>Data</th> <td></td>', 'text', ['safe' => false]],
2131
            ['<th>Data</th> <td></td>', 'textarea', ['safe' => false]],
2132
            ['<th>Data</th> <td>&nbsp;</td>', 'datetime', []],
2133
            [
2134
                '<th>Data</th> <td>&nbsp;</td>',
2135
                'datetime',
2136
                ['format' => 'd.m.Y H:i:s'],
2137
            ],
2138
            ['<th>Data</th> <td>&nbsp;</td>', 'date', []],
2139
            ['<th>Data</th> <td>&nbsp;</td>', 'date', ['format' => 'd.m.Y']],
2140
            ['<th>Data</th> <td>&nbsp;</td>', 'time', []],
2141
            ['<th>Data</th> <td></td>', 'number', ['safe' => false]],
2142
            ['<th>Data</th> <td></td>', 'integer', ['safe' => false]],
2143
            ['<th>Data</th> <td> 0 % </td>', 'percent', []],
2144
            ['<th>Data</th> <td> </td>', 'currency', ['currency' => 'EUR']],
2145
            ['<th>Data</th> <td> </td>', 'currency', ['currency' => 'GBP']],
2146
            ['<th>Data</th> <td> <ul></ul> </td>', 'array', ['safe' => false]],
2147
            [
2148
                '<th>Data</th> <td><span class="label label-danger">no</span></td>',
2149
                'boolean',
2150
                [],
2151
            ],
2152
            [
2153
                '<th>Data</th> <td> </td>',
2154
                'trans',
2155
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
2156
            ],
2157
            [
2158
                '<th>Data</th> <td></td>',
2159
                'choice',
2160
                ['safe' => false, 'choices' => []],
2161
            ],
2162
            [
2163
                '<th>Data</th> <td></td>',
2164
                'choice',
2165
                ['safe' => false, 'choices' => [], 'multiple' => true],
2166
            ],
2167
            ['<th>Data</th> <td>&nbsp;</td>', 'url', []],
2168
            [
2169
                '<th>Data</th> <td>&nbsp;</td>',
2170
                'url',
2171
                ['url' => 'http://example.com'],
2172
            ],
2173
            [
2174
                '<th>Data</th> <td>&nbsp;</td>',
2175
                'url',
2176
                ['route' => ['name' => 'sonata_admin_foo']],
2177
            ],
2178
        ];
2179
    }
2180
2181
    /**
2182
     * NEXT_MAJOR: Remove this method.
2183
     *
2184
     * @group legacy
2185
     *
2186
     * @dataProvider getDeprecatedTextExtensionItems
2187
     *
2188
     * @expectedDeprecation The "truncate.preserve" option is deprecated since sonata-project/admin-bundle 3.65, to be removed in 4.0. Use "truncate.cut" instead. ("@SonataAdmin/CRUD/show_html.html.twig" at line %d).
2189
     *
2190
     * @expectedDeprecation The "truncate.separator" option is deprecated since sonata-project/admin-bundle 3.65, to be removed in 4.0. Use "truncate.ellipsis" instead. ("@SonataAdmin/CRUD/show_html.html.twig" at line %d).
2191
     */
2192
    public function testDeprecatedTextExtension(string $expected, string $type, $value, array $options): void
2193
    {
2194
        $loader = new StubFilesystemLoader([
2195
            __DIR__.'/../../../src/Resources/views/CRUD',
2196
        ]);
2197
        $loader->addPath(__DIR__.'/../../../src/Resources/views/', 'SonataAdmin');
2198
        $environment = new Environment($loader, [
2199
            'strict_variables' => true,
2200
            'cache' => false,
2201
            'autoescape' => 'html',
2202
            'optimizations' => 0,
2203
        ]);
2204
        $environment->addExtension($this->twigExtension);
2205
        $environment->addExtension(new TranslationExtension($this->translator));
2206
        $environment->addExtension(new StringExtension(new TextExtension()));
2207
2208
        $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...
2209
            ->method('getTemplate')
2210
            ->willReturn('@SonataAdmin/CRUD/base_show_field.html.twig');
2211
2212
        $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...
2213
            ->method('getValue')
2214
            ->willReturn($value);
2215
2216
        $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...
2217
            ->method('getType')
2218
            ->willReturn($type);
2219
2220
        $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...
2221
            ->method('getOptions')
2222
            ->willReturn($options);
2223
2224
        $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...
2225
            ->method('getTemplate')
2226
            ->willReturn('@SonataAdmin/CRUD/show_html.html.twig');
2227
2228
        $this->assertSame(
2229
            $this->removeExtraWhitespace($expected),
2230
            $this->removeExtraWhitespace(
2231
                $this->twigExtension->renderViewElement(
2232
                    $environment,
2233
                    $this->fieldDescription,
2234
                    $this->object
2235
                )
2236
            )
2237
        );
2238
    }
2239
2240
    /**
2241
     * NEXT_MAJOR: Remove this method.
2242
     */
2243
    public function getDeprecatedTextExtensionItems(): iterable
2244
    {
2245
        yield 'default_separator' => [
2246
            '<th>Data</th> <td> Creating a Template for the Field... </td>',
2247
            'html',
2248
            '<p><strong>Creating a Template for the Field</strong> and form</p>',
2249
            ['truncate' => ['preserve' => true, 'separator' => '...']],
2250
        ];
2251
2252
        yield 'custom_length' => [
2253
            '<th>Data</th> <td> Creating a Template for[...] </td>',
2254
            'html',
2255
            '<p><strong>Creating a Template for the Field</strong> and form</p>',
2256
            [
2257
                'truncate' => [
2258
                    'length' => 20,
2259
                    'preserve' => true,
2260
                    'separator' => '[...]',
2261
                ],
2262
            ],
2263
        ];
2264
    }
2265
2266
    public function testGetValueFromFieldDescription(): void
2267
    {
2268
        $object = new \stdClass();
2269
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2270
2271
        $fieldDescription
2272
            ->method('getValue')
2273
            ->willReturn('test123');
2274
2275
        $this->assertSame('test123', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2276
    }
2277
2278
    public function testGetValueFromFieldDescriptionWithRemoveLoopException(): void
2279
    {
2280
        $object = $this->createMock(\ArrayAccess::class);
2281
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2282
2283
        $this->expectException(\RuntimeException::class);
2284
        $this->expectExceptionMessage('remove the loop requirement');
2285
2286
        $this->assertSame(
2287
            'anything',
2288
            $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription, ['loop' => true])
2289
        );
2290
    }
2291
2292
    /**
2293
     * NEXT_MAJOR: Change this test to expect a NoValueException instead.
2294
     *
2295
     * @group legacy
2296
     * @expectedDeprecation Accessing a non existing value is deprecated since sonata-project/admin-bundle 3.67 and will throw an exception in 4.0.
2297
     */
2298
    public function testGetValueFromFieldDescriptionWithNoValueException(): void
2299
    {
2300
        $object = new \stdClass();
2301
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2302
2303
        $fieldDescription
2304
            ->method('getValue')
2305
            ->willReturnCallback(static function (): void {
2306
                throw new NoValueException();
2307
            });
2308
2309
        $fieldDescription
2310
            ->method('getAssociationAdmin')
2311
            ->willReturn(null);
2312
2313
        $this->assertNull($this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2314
    }
2315
2316
    public function testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance(): void
2317
    {
2318
        $object = new \stdClass();
2319
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2320
2321
        $fieldDescription
2322
            ->method('getValue')
2323
            ->willReturnCallback(static function (): void {
2324
                throw new NoValueException();
2325
            });
2326
2327
        $fieldDescription
2328
            ->method('getAssociationAdmin')
2329
            ->willReturn($this->admin);
2330
2331
        $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...
2332
            ->method('getNewInstance')
2333
            ->willReturn('foo');
2334
2335
        $this->assertSame('foo', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2336
    }
2337
2338
    /**
2339
     * @group legacy
2340
     */
2341
    public function testOutput(): void
2342
    {
2343
        $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...
2344
            ->method('getTemplate')
2345
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
2346
2347
        $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...
2348
            ->method('getFieldName')
2349
            ->willReturn('fd_name');
2350
2351
        $this->environment->disableDebug();
2352
2353
        $parameters = [
2354
            'admin' => $this->admin,
2355
            'value' => 'foo',
2356
            'field_description' => $this->fieldDescription,
2357
            'object' => $this->object,
2358
        ];
2359
2360
        $template = $this->environment->loadTemplate('@SonataAdmin/CRUD/base_list_field.html.twig');
2361
2362
        $this->assertSame(
2363
            '<td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>',
2364
            $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...
2365
                $this->fieldDescription,
2366
                $template,
2367
                $parameters,
2368
                $this->environment
2369
            ))
2370
        );
2371
2372
        $this->environment->enableDebug();
2373
        $this->assertSame(
2374
            $this->removeExtraWhitespace(
2375
                <<<'EOT'
2376
<!-- START
2377
    fieldName: fd_name
2378
    template: @SonataAdmin/CRUD/base_list_field.html.twig
2379
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
2380
-->
2381
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
2382
<!-- END - fieldName: fd_name -->
2383
EOT
2384
            ),
2385
            $this->removeExtraWhitespace(
2386
                $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...
2387
            )
2388
        );
2389
    }
2390
2391
    /**
2392
     * @group legacy
2393
     * @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).
2394
     */
2395
    public function testRenderWithDebug(): void
2396
    {
2397
        $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...
2398
            ->method('getTemplate')
2399
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
2400
2401
        $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...
2402
            ->method('getFieldName')
2403
            ->willReturn('fd_name');
2404
2405
        $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...
2406
            ->method('getValue')
2407
            ->willReturn('foo');
2408
2409
        $parameters = [
2410
            'admin' => $this->admin,
2411
            'value' => 'foo',
2412
            'field_description' => $this->fieldDescription,
2413
            'object' => $this->object,
2414
        ];
2415
2416
        $this->environment->enableDebug();
2417
2418
        $this->assertSame(
2419
            $this->removeExtraWhitespace(
2420
                <<<'EOT'
2421
<!-- START
2422
    fieldName: fd_name
2423
    template: @SonataAdmin/CRUD/base_list_field.html.twig
2424
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
2425
-->
2426
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
2427
<!-- END - fieldName: fd_name -->
2428
EOT
2429
            ),
2430
            $this->removeExtraWhitespace(
2431
                $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription, $parameters)
2432
            )
2433
        );
2434
    }
2435
2436
    public function testRenderRelationElementNoObject(): void
2437
    {
2438
        $this->assertSame('foo', $this->twigExtension->renderRelationElement('foo', $this->fieldDescription));
2439
    }
2440
2441
    public function testRenderRelationElementToString(): void
2442
    {
2443
        $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...
2444
            ->method('getOption')
2445
            ->willReturnCallback(static function ($value, $default = null) {
2446
                if ('associated_property' === $value) {
2447
                    return $default;
2448
                }
2449
            });
2450
2451
        $element = new FooToString();
2452
        $this->assertSame('salut', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2453
    }
2454
2455
    /**
2456
     * @group legacy
2457
     */
2458
    public function testDeprecatedRelationElementToString(): void
2459
    {
2460
        $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...
2461
            ->method('getOption')
2462
            ->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...
2463
                if ('associated_tostring' === $value) {
2464
                    return '__toString';
2465
                }
2466
            });
2467
2468
        $element = new FooToString();
2469
        $this->assertSame(
2470
            'salut',
2471
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2472
        );
2473
    }
2474
2475
    /**
2476
     * @group legacy
2477
     */
2478
    public function testRenderRelationElementCustomToString(): void
2479
    {
2480
        $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...
2481
            ->method('getOption')
2482
            ->willReturnCallback(static function ($value, $default = null) {
2483
                if ('associated_property' === $value) {
2484
                    return $default;
2485
                }
2486
2487
                if ('associated_tostring' === $value) {
2488
                    return 'customToString';
2489
                }
2490
            });
2491
2492
        $element = $this->getMockBuilder(\stdClass::class)
2493
            ->setMethods(['customToString'])
2494
            ->getMock();
2495
        $element
2496
            ->method('customToString')
2497
            ->willReturn('fooBar');
2498
2499
        $this->assertSame('fooBar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2500
    }
2501
2502
    /**
2503
     * @group legacy
2504
     */
2505
    public function testRenderRelationElementMethodNotExist(): void
2506
    {
2507
        $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...
2508
            ->method('getOption')
2509
2510
            ->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...
2511
                if ('associated_tostring' === $value) {
2512
                    return 'nonExistedMethod';
2513
                }
2514
            });
2515
2516
        $element = new \stdClass();
2517
        $this->expectException(\RuntimeException::class);
2518
        $this->expectExceptionMessage('You must define an `associated_property` option or create a `stdClass::__toString');
2519
2520
        $this->twigExtension->renderRelationElement($element, $this->fieldDescription);
2521
    }
2522
2523
    public function testRenderRelationElementWithPropertyPath(): void
2524
    {
2525
        $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...
2526
            ->method('getOption')
2527
2528
            ->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...
2529
                if ('associated_property' === $value) {
2530
                    return 'foo';
2531
                }
2532
            });
2533
2534
        $element = new \stdClass();
2535
        $element->foo = 'bar';
2536
2537
        $this->assertSame('bar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2538
    }
2539
2540
    public function testRenderRelationElementWithClosure(): void
2541
    {
2542
        $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...
2543
            ->method('getOption')
2544
2545
            ->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...
2546
                if ('associated_property' === $value) {
2547
                    return static function ($element): string {
2548
                        return 'closure '.$element->foo;
2549
                    };
2550
                }
2551
            });
2552
2553
        $element = new \stdClass();
2554
        $element->foo = 'bar';
2555
2556
        $this->assertSame(
2557
            'closure bar',
2558
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2559
        );
2560
    }
2561
2562
    public function testGetUrlsafeIdentifier(): void
2563
    {
2564
        $entity = new \stdClass();
2565
2566
        // set admin to pool
2567
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
2568
        $this->pool->setAdminClasses([\stdClass::class => ['sonata_admin_foo_service']]);
2569
2570
        $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...
2571
            ->method('getUrlSafeIdentifier')
2572
            ->with($this->equalTo($entity))
2573
            ->willReturn(1234567);
2574
2575
        $this->assertSame(1234567, $this->twigExtension->getUrlSafeIdentifier($entity));
2576
    }
2577
2578
    public function testGetUrlsafeIdentifier_GivenAdmin_Foo(): void
2579
    {
2580
        $entity = new \stdClass();
2581
2582
        // set admin to pool
2583
        $this->pool->setAdminServiceIds([
2584
            'sonata_admin_foo_service',
2585
            'sonata_admin_bar_service',
2586
        ]);
2587
        $this->pool->setAdminClasses([\stdClass::class => [
2588
            'sonata_admin_foo_service',
2589
            'sonata_admin_bar_service',
2590
        ]]);
2591
2592
        $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...
2593
            ->method('getUrlSafeIdentifier')
2594
            ->with($this->equalTo($entity))
2595
            ->willReturn(1234567);
2596
2597
        $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...
2598
            ->method('getUrlSafeIdentifier');
2599
2600
        $this->assertSame(1234567, $this->twigExtension->getUrlSafeIdentifier($entity, $this->admin));
2601
    }
2602
2603
    public function testGetUrlsafeIdentifier_GivenAdmin_Bar(): void
2604
    {
2605
        $entity = new \stdClass();
2606
2607
        // set admin to pool
2608
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service', 'sonata_admin_bar_service']);
2609
        $this->pool->setAdminClasses([\stdClass::class => [
2610
            'sonata_admin_foo_service',
2611
            'sonata_admin_bar_service',
2612
        ]]);
2613
2614
        $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...
2615
            ->method('getUrlSafeIdentifier');
2616
2617
        $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...
2618
            ->method('getUrlSafeIdentifier')
2619
            ->with($this->equalTo($entity))
2620
            ->willReturn(1234567);
2621
2622
        $this->assertSame(1234567, $this->twigExtension->getUrlSafeIdentifier($entity, $this->adminBar));
2623
    }
2624
2625
    public function xEditableChoicesProvider()
2626
    {
2627
        return [
2628
            'needs processing' => [
2629
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2']],
2630
                [
2631
                    ['value' => 'Status1', 'text' => 'Alias1'],
2632
                    ['value' => 'Status2', 'text' => 'Alias2'],
2633
                ],
2634
            ],
2635
            'already processed' => [
2636
                ['choices' => [
2637
                    ['value' => 'Status1', 'text' => 'Alias1'],
2638
                    ['value' => 'Status2', 'text' => 'Alias2'],
2639
                ]],
2640
                [
2641
                    ['value' => 'Status1', 'text' => 'Alias1'],
2642
                    ['value' => 'Status2', 'text' => 'Alias2'],
2643
                ],
2644
            ],
2645
            'not required' => [
2646
                [
2647
                    'required' => false,
2648
                    'choices' => ['' => '', 'Status1' => 'Alias1', 'Status2' => 'Alias2'],
2649
                ],
2650
                [
2651
                    ['value' => '', 'text' => ''],
2652
                    ['value' => 'Status1', 'text' => 'Alias1'],
2653
                    ['value' => 'Status2', 'text' => 'Alias2'],
2654
                ],
2655
            ],
2656
            'not required multiple' => [
2657
                [
2658
                    'required' => false,
2659
                    'multiple' => true,
2660
                    'choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2'],
2661
                ],
2662
                [
2663
                    ['value' => 'Status1', 'text' => 'Alias1'],
2664
                    ['value' => 'Status2', 'text' => 'Alias2'],
2665
                ],
2666
            ],
2667
        ];
2668
    }
2669
2670
    /**
2671
     * @dataProvider xEditablechoicesProvider
2672
     */
2673
    public function testGetXEditableChoicesIsIdempotent(array $options, array $expectedChoices): void
2674
    {
2675
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2676
        $fieldDescription
2677
            ->method('getOption')
2678
            ->withConsecutive(
2679
                ['choices', []],
2680
                ['catalogue'],
2681
                ['required'],
2682
                ['multiple']
2683
            )
2684
            ->will($this->onConsecutiveCalls(
2685
                $options['choices'],
2686
                'MyCatalogue',
2687
                $options['multiple'] ?? null
2688
            ));
2689
2690
        $this->assertSame($expectedChoices, $this->twigExtension->getXEditableChoices($fieldDescription));
2691
    }
2692
2693
    public function select2LocalesProvider()
2694
    {
2695
        return [
2696
            ['ar', 'ar'],
2697
            ['az', 'az'],
2698
            ['bg', 'bg'],
2699
            ['ca', 'ca'],
2700
            ['cs', 'cs'],
2701
            ['da', 'da'],
2702
            ['de', 'de'],
2703
            ['el', 'el'],
2704
            [null, 'en'],
2705
            ['es', 'es'],
2706
            ['et', 'et'],
2707
            ['eu', 'eu'],
2708
            ['fa', 'fa'],
2709
            ['fi', 'fi'],
2710
            ['fr', 'fr'],
2711
            ['gl', 'gl'],
2712
            ['he', 'he'],
2713
            ['hr', 'hr'],
2714
            ['hu', 'hu'],
2715
            ['id', 'id'],
2716
            ['is', 'is'],
2717
            ['it', 'it'],
2718
            ['ja', 'ja'],
2719
            ['ka', 'ka'],
2720
            ['ko', 'ko'],
2721
            ['lt', 'lt'],
2722
            ['lv', 'lv'],
2723
            ['mk', 'mk'],
2724
            ['ms', 'ms'],
2725
            ['nb', 'nb'],
2726
            ['nl', 'nl'],
2727
            ['pl', 'pl'],
2728
            ['pt-PT', 'pt'],
2729
            ['pt-BR', 'pt-BR'],
2730
            ['pt-PT', 'pt-PT'],
2731
            ['ro', 'ro'],
2732
            ['rs', 'rs'],
2733
            ['ru', 'ru'],
2734
            ['sk', 'sk'],
2735
            ['sv', 'sv'],
2736
            ['th', 'th'],
2737
            ['tr', 'tr'],
2738
            ['ug-CN', 'ug'],
2739
            ['ug-CN', 'ug-CN'],
2740
            ['uk', 'uk'],
2741
            ['vi', 'vi'],
2742
            ['zh-CN', 'zh'],
2743
            ['zh-CN', 'zh-CN'],
2744
            ['zh-TW', 'zh-TW'],
2745
        ];
2746
    }
2747
2748
    /**
2749
     * @dataProvider select2LocalesProvider
2750
     */
2751
    public function testCanonicalizedLocaleForSelect2(?string $expected, string $original): void
2752
    {
2753
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForSelect2($this->mockExtensionContext($original)));
2754
    }
2755
2756
    public function momentLocalesProvider(): array
2757
    {
2758
        return [
2759
            ['af', 'af'],
2760
            ['ar-dz', 'ar-dz'],
2761
            ['ar', 'ar'],
2762
            ['ar-ly', 'ar-ly'],
2763
            ['ar-ma', 'ar-ma'],
2764
            ['ar-sa', 'ar-sa'],
2765
            ['ar-tn', 'ar-tn'],
2766
            ['az', 'az'],
2767
            ['be', 'be'],
2768
            ['bg', 'bg'],
2769
            ['bn', 'bn'],
2770
            ['bo', 'bo'],
2771
            ['br', 'br'],
2772
            ['bs', 'bs'],
2773
            ['ca', 'ca'],
2774
            ['cs', 'cs'],
2775
            ['cv', 'cv'],
2776
            ['cy', 'cy'],
2777
            ['da', 'da'],
2778
            ['de-at', 'de-at'],
2779
            ['de', 'de'],
2780
            ['de', 'de-de'],
2781
            ['dv', 'dv'],
2782
            ['el', 'el'],
2783
            [null, 'en'],
2784
            [null, 'en-us'],
2785
            ['en-au', 'en-au'],
2786
            ['en-ca', 'en-ca'],
2787
            ['en-gb', 'en-gb'],
2788
            ['en-ie', 'en-ie'],
2789
            ['en-nz', 'en-nz'],
2790
            ['eo', 'eo'],
2791
            ['es-do', 'es-do'],
2792
            ['es', 'es-ar'],
2793
            ['es', 'es-mx'],
2794
            ['es', 'es'],
2795
            ['et', 'et'],
2796
            ['eu', 'eu'],
2797
            ['fa', 'fa'],
2798
            ['fi', 'fi'],
2799
            ['fo', 'fo'],
2800
            ['fr-ca', 'fr-ca'],
2801
            ['fr-ch', 'fr-ch'],
2802
            ['fr', 'fr-fr'],
2803
            ['fr', 'fr'],
2804
            ['fy', 'fy'],
2805
            ['gd', 'gd'],
2806
            ['gl', 'gl'],
2807
            ['he', 'he'],
2808
            ['hi', 'hi'],
2809
            ['hr', 'hr'],
2810
            ['hu', 'hu'],
2811
            ['hy-am', 'hy-am'],
2812
            ['id', 'id'],
2813
            ['is', 'is'],
2814
            ['it', 'it'],
2815
            ['ja', 'ja'],
2816
            ['jv', 'jv'],
2817
            ['ka', 'ka'],
2818
            ['kk', 'kk'],
2819
            ['km', 'km'],
2820
            ['ko', 'ko'],
2821
            ['ky', 'ky'],
2822
            ['lb', 'lb'],
2823
            ['lo', 'lo'],
2824
            ['lt', 'lt'],
2825
            ['lv', 'lv'],
2826
            ['me', 'me'],
2827
            ['mi', 'mi'],
2828
            ['mk', 'mk'],
2829
            ['ml', 'ml'],
2830
            ['mr', 'mr'],
2831
            ['ms', 'ms'],
2832
            ['ms-my', 'ms-my'],
2833
            ['my', 'my'],
2834
            ['nb', 'nb'],
2835
            ['ne', 'ne'],
2836
            ['nl-be', 'nl-be'],
2837
            ['nl', 'nl'],
2838
            ['nl', 'nl-nl'],
2839
            ['nn', 'nn'],
2840
            ['pa-in', 'pa-in'],
2841
            ['pl', 'pl'],
2842
            ['pt-br', 'pt-br'],
2843
            ['pt', 'pt'],
2844
            ['ro', 'ro'],
2845
            ['ru', 'ru'],
2846
            ['se', 'se'],
2847
            ['si', 'si'],
2848
            ['sk', 'sk'],
2849
            ['sl', 'sl'],
2850
            ['sq', 'sq'],
2851
            ['sr-cyrl', 'sr-cyrl'],
2852
            ['sr', 'sr'],
2853
            ['ss', 'ss'],
2854
            ['sv', 'sv'],
2855
            ['sw', 'sw'],
2856
            ['ta', 'ta'],
2857
            ['te', 'te'],
2858
            ['tet', 'tet'],
2859
            ['th', 'th'],
2860
            ['tlh', 'tlh'],
2861
            ['tl-ph', 'tl-ph'],
2862
            ['tr', 'tr'],
2863
            ['tzl', 'tzl'],
2864
            ['tzm', 'tzm'],
2865
            ['tzm-latn', 'tzm-latn'],
2866
            ['uk', 'uk'],
2867
            ['uz', 'uz'],
2868
            ['vi', 'vi'],
2869
            ['x-pseudo', 'x-pseudo'],
2870
            ['yo', 'yo'],
2871
            ['zh-cn', 'zh-cn'],
2872
            ['zh-hk', 'zh-hk'],
2873
            ['zh-tw', 'zh-tw'],
2874
        ];
2875
    }
2876
2877
    /**
2878
     * @dataProvider momentLocalesProvider
2879
     */
2880
    public function testCanonicalizedLocaleForMoment(?string $expected, string $original): void
2881
    {
2882
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForMoment($this->mockExtensionContext($original)));
2883
    }
2884
2885
    public function testIsGrantedAffirmative(): void
2886
    {
2887
        $this->assertTrue(
2888
            $this->twigExtension->isGrantedAffirmative(['foo', 'bar'])
2889
        );
2890
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('foo'));
2891
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('bar'));
2892
    }
2893
2894
    /**
2895
     * @dataProvider getRenderViewElementCompareTests
2896
     */
2897
    public function testRenderViewElementCompare(string $expected, string $type, $value, array $options, ?string $objectName = null): void
2898
    {
2899
        $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...
2900
            ->method('getTemplate')
2901
            ->willReturn('@SonataAdmin/CRUD/base_show_compare.html.twig');
2902
2903
        $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...
2904
            ->method('getValue')
2905
            ->willReturn($value);
2906
2907
        $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...
2908
            ->method('getType')
2909
            ->willReturn($type);
2910
2911
        $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...
2912
            ->method('getOptions')
2913
            ->willReturn($options);
2914
2915
        $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...
2916
            ->method('getTemplate')
2917
            ->willReturnCallback(static function () use ($type, $options): ?string {
2918
                if (isset($options['template'])) {
2919
                    return $options['template'];
2920
                }
2921
2922
                switch ($type) {
2923
                    case 'boolean':
2924
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
2925
                    case 'datetime':
2926
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
2927
                    case 'date':
2928
                        return '@SonataAdmin/CRUD/show_date.html.twig';
2929
                    case 'time':
2930
                        return '@SonataAdmin/CRUD/show_time.html.twig';
2931
                    case 'currency':
2932
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
2933
                    case 'percent':
2934
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
2935
                    case 'email':
2936
                        return '@SonataAdmin/CRUD/show_email.html.twig';
2937
                    case 'choice':
2938
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
2939
                    case 'array':
2940
                        return '@SonataAdmin/CRUD/show_array.html.twig';
2941
                    case 'trans':
2942
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
2943
                    case 'url':
2944
                        return '@SonataAdmin/CRUD/show_url.html.twig';
2945
                    case 'html':
2946
                        return '@SonataAdmin/CRUD/show_html.html.twig';
2947
                    default:
2948
                        return null;
2949
                }
2950
            });
2951
2952
        $this->object->name = 'SonataAdmin';
2953
2954
        $comparedObject = clone $this->object;
2955
2956
        if (null !== $objectName) {
2957
            $comparedObject->name = $objectName;
2958
        }
2959
2960
        $this->assertSame(
2961
            $this->removeExtraWhitespace($expected),
2962
            $this->removeExtraWhitespace(
2963
                $this->twigExtension->renderViewElementCompare(
2964
                    $this->environment,
2965
                    $this->fieldDescription,
2966
                    $this->object,
2967
                    $comparedObject
2968
                )
2969
            )
2970
        );
2971
    }
2972
2973
    public function getRenderViewElementCompareTests(): iterable
2974
    {
2975
        return [
2976
            ['<th>Data</th> <td>Example</td><td>Example</td>', 'string', 'Example', ['safe' => false]],
2977
            ['<th>Data</th> <td>Example</td><td>Example</td>', 'text', 'Example', ['safe' => false]],
2978
            ['<th>Data</th> <td>Example</td><td>Example</td>', 'textarea', 'Example', ['safe' => false]],
2979
            ['<th>Data</th> <td>SonataAdmin<br/>Example</td><td>SonataAdmin<br/>Example</td>', 'virtual_field', 'Example', ['template' => 'custom_show_field.html.twig', 'safe' => false, 'SonataAdmin']],
2980
            ['<th class="diff">Data</th> <td>SonataAdmin<br/>Example</td><td>SonataAdmin<br/>Example</td>', 'virtual_field', 'Example', ['template' => 'custom_show_field.html.twig', 'safe' => false], 'sonata-project/admin-bundle'],
2981
            [
2982
                '<th>Data</th> <td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> May 27, 2020 10:11 </time></td>'
2983
                .'<td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> May 27, 2020 10:11 </time></td>',
2984
                'datetime',
2985
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('Europe/London')), [],
2986
            ],
2987
            [
2988
                '<th>Data</th> <td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> 27.05.2020 10:11:12 </time></td>'
2989
                .'<td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> 27.05.2020 10:11:12 </time></td>',
2990
                'datetime',
2991
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('Europe/London')),
2992
                ['format' => 'd.m.Y H:i:s'],
2993
            ],
2994
            [
2995
                '<th>Data</th> <td><time datetime="2020-05-27T10:11:12+00:00" title="2020-05-27T10:11:12+00:00"> May 27, 2020 18:11 </time></td>'
2996
                .'<td><time datetime="2020-05-27T10:11:12+00:00" title="2020-05-27T10:11:12+00:00"> May 27, 2020 18:11 </time></td>',
2997
                'datetime',
2998
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('UTC')),
2999
                ['timezone' => 'Asia/Hong_Kong'],
3000
            ],
3001
            [
3002
                '<th>Data</th> <td><time datetime="2020-05-27" title="2020-05-27"> May 27, 2020 </time></td>'
3003
                .'<td><time datetime="2020-05-27" title="2020-05-27"> May 27, 2020 </time></td>',
3004
                'date',
3005
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('Europe/London')),
3006
                [],
3007
            ],
3008
        ];
3009
    }
3010
3011
    /**
3012
     * This method generates url part for Twig layout.
3013
     */
3014
    private function buildTwigLikeUrl(array $url): string
3015
    {
3016
        return htmlspecialchars(http_build_query($url, '', '&', PHP_QUERY_RFC3986));
3017
    }
3018
3019
    private function removeExtraWhitespace(string $string): string
3020
    {
3021
        return trim(preg_replace(
3022
            '/\s+/',
3023
            ' ',
3024
            $string
3025
        ));
3026
    }
3027
3028
    private function mockExtensionContext(string $locale): array
3029
    {
3030
        $request = $this->createMock(Request::class);
3031
        $request->method('getLocale')->willReturn($locale);
3032
        $appVariable = $this->createMock(AppVariable::class);
3033
        $appVariable->method('getRequest')->willReturn($request);
3034
3035
        return ['app' => $appVariable];
3036
    }
3037
}
3038