Completed
Push — 3.x ( 37ee0f...10863f )
by Vincent
02:54
created

testRenderViewElementWithNoValue()   C

Complexity

Conditions 13
Paths 1

Size

Total Lines 62

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 62
rs 6.1224
c 0
b 0
f 0
cc 13
nc 1
nop 3

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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