Completed
Pull Request — 3.x (#6198)
by
unknown
03:07
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 Symfony\Bridge\Twig\AppVariable;
29
use Symfony\Bridge\Twig\Extension\RoutingExtension;
30
use Symfony\Bridge\Twig\Extension\TranslationExtension;
31
use Symfony\Component\Config\FileLocator;
32
use Symfony\Component\DependencyInjection\ContainerInterface;
33
use Symfony\Component\HttpFoundation\Request;
34
use Symfony\Component\Routing\Generator\UrlGenerator;
35
use Symfony\Component\Routing\Loader\XmlFileLoader;
36
use Symfony\Component\Routing\RequestContext;
37
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
38
use Symfony\Component\Translation\Loader\XliffFileLoader;
39
use Symfony\Component\Translation\Translator;
40
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
41
use Symfony\Contracts\Translation\TranslatorInterface;
42
use Twig\Environment;
43
use Twig\Error\LoaderError;
44
use Twig\Extra\String\StringExtension;
45
46
/**
47
 * Test for SonataAdminExtension.
48
 *
49
 * @author Andrej Hudec <[email protected]>
50
 */
51
class SonataAdminExtensionTest extends TestCase
52
{
53
    /**
54
     * @var SonataAdminExtension
55
     */
56
    private $twigExtension;
57
58
    /**
59
     * @var Environment
60
     */
61
    private $environment;
62
63
    /**
64
     * @var AdminInterface
65
     */
66
    private $admin;
67
68
    /**
69
     * @var AdminInterface
70
     */
71
    private $adminBar;
72
73
    /**
74
     * @var FieldDescriptionInterface
75
     */
76
    private $fieldDescription;
77
78
    /**
79
     * @var \stdClass
80
     */
81
    private $object;
82
83
    /**
84
     * @var Pool
85
     */
86
    private $pool;
87
88
    /**
89
     * @var LoggerInterface
90
     */
91
    private $logger;
92
93
    /**
94
     * @var string[]
95
     */
96
    private $xEditableTypeMapping;
97
98
    /**
99
     * @var TranslatorInterface
100
     */
101
    private $translator;
102
103
    /**
104
     * @var ContainerInterface
105
     */
106
    private $container;
107
108
    /**
109
     * @var TemplateRegistryInterface
110
     */
111
    private $templateRegistry;
112
113
    /**
114
     * @var AuthorizationCheckerInterface
115
     */
116
    private $securityChecker;
117
118
    protected function setUp(): void
119
    {
120
        date_default_timezone_set('Europe/London');
121
122
        $container = $this->createMock(ContainerInterface::class);
123
124
        $this->pool = new Pool($container, '', '');
125
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
126
        $this->pool->setAdminClasses(['fooClass' => ['sonata_admin_foo_service']]);
127
128
        $this->logger = $this->getMockForAbstractClass(LoggerInterface::class);
129
        $this->xEditableTypeMapping = [
0 ignored issues
show
Documentation Bug introduced by
It seems like array('choice' => 'selec...umber', 'url' => 'url') of type array<string,string,{"ch...tring","url":"string"}> is incompatible with the declared type array<integer,string> of property $xEditableTypeMapping.

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

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

Loading history...
130
            'choice' => 'select',
131
            'boolean' => 'select',
132
            'text' => 'text',
133
            'textarea' => 'textarea',
134
            'html' => 'textarea',
135
            'email' => 'email',
136
            'string' => 'text',
137
            'smallint' => 'text',
138
            'bigint' => 'text',
139
            'integer' => 'number',
140
            'decimal' => 'number',
141
            'currency' => 'number',
142
            'percent' => 'number',
143
            'url' => 'url',
144
        ];
145
146
        // translation extension
147
        $translator = new Translator('en');
148
        $translator->addLoader('xlf', new XliffFileLoader());
149
        $translator->addResource(
150
            'xlf',
151
            sprintf('%s/../../../src/Resources/translations/SonataAdminBundle.en.xliff', __DIR__),
152
            'en',
153
            'SonataAdminBundle'
154
        );
155
156
        $this->translator = $translator;
157
158
        $this->templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
159
        $this->container = $this->prophesize(ContainerInterface::class);
160
        $this->container->get('sonata_admin_foo_service.template_registry')->willReturn($this->templateRegistry->reveal());
161
162
        $this->securityChecker = $this->prophesize(AuthorizationCheckerInterface::class);
163
        $this->securityChecker->isGranted(['foo', 'bar'], null)->willReturn(false);
164
        $this->securityChecker->isGranted(Argument::type('string'), null)->willReturn(true);
165
166
        $this->twigExtension = new SonataAdminExtension(
167
            $this->pool,
168
            $this->logger,
169
            $this->translator,
170
            $this->container->reveal(),
171
            $this->securityChecker->reveal()
172
        );
173
        $this->twigExtension->setXEditableTypeMapping($this->xEditableTypeMapping);
174
175
        $request = $this->createMock(Request::class);
176
        $request->method('get')->with('_sonata_admin')->willReturn('sonata_admin_foo_service');
177
178
        $loader = new StubFilesystemLoader([
179
            __DIR__.'/../../../src/Resources/views/CRUD',
180
            __DIR__.'/../../Fixtures/Resources/views/CRUD',
181
        ]);
182
        $loader->addPath(__DIR__.'/../../../src/Resources/views/', 'SonataAdmin');
183
        $loader->addPath(__DIR__.'/../../Fixtures/Resources/views/', 'App');
184
185
        $this->environment = new Environment($loader, [
186
            'strict_variables' => true,
187
            'cache' => false,
188
            'autoescape' => 'html',
189
            'optimizations' => 0,
190
        ]);
191
        $this->environment->addExtension($this->twigExtension);
192
        $this->environment->addExtension(new TranslationExtension($translator));
193
        $this->environment->addExtension(new FakeTemplateRegistryExtension());
194
195
        // routing extension
196
        $xmlFileLoader = new XmlFileLoader(new FileLocator([sprintf('%s/../../../src/Resources/config/routing', __DIR__)]));
197
        $routeCollection = $xmlFileLoader->load('sonata_admin.xml');
198
199
        $xmlFileLoader = new XmlFileLoader(new FileLocator([sprintf('%s/../../Fixtures/Resources/config/routing', __DIR__)]));
200
        $testRouteCollection = $xmlFileLoader->load('routing.xml');
201
202
        $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...
203
        $requestContext = new RequestContext();
204
        $urlGenerator = new UrlGenerator($routeCollection, $requestContext);
205
        $this->environment->addExtension(new RoutingExtension($urlGenerator));
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.67 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
            sprintf('%s/../../../src/Resources/views/CRUD', __DIR__),
2194
        ]);
2195
        $loader->addPath(sprintf('%s/../../../src/Resources/views/', __DIR__), '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());
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[...] </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
    /**
2277
     * NEXT_MAJOR: Change this test to expect a NoValueException instead.
2278
     *
2279
     * @group legacy
2280
     * @expectedDeprecation Accessing a non existing value is deprecated since sonata-project/admin-bundle 3.67 and will throw an exception in 4.0.
2281
     */
2282
    public function testGetValueFromFieldDescriptionWithNoValueException(): void
2283
    {
2284
        $object = new \stdClass();
2285
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2286
2287
        $fieldDescription
2288
            ->method('getValue')
2289
            ->willReturnCallback(static function (): void {
2290
                throw new NoValueException();
2291
            });
2292
2293
        $fieldDescription
2294
            ->method('getAssociationAdmin')
2295
            ->willReturn(null);
2296
2297
        $this->assertNull($this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2298
    }
2299
2300
    public function testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance(): void
2301
    {
2302
        $object = new \stdClass();
2303
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2304
2305
        $fieldDescription
2306
            ->method('getValue')
2307
            ->willReturnCallback(static function (): void {
2308
                throw new NoValueException();
2309
            });
2310
2311
        $fieldDescription
2312
            ->method('getAssociationAdmin')
2313
            ->willReturn($this->admin);
2314
2315
        $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...
2316
            ->method('getNewInstance')
2317
            ->willReturn('foo');
2318
2319
        $this->assertSame('foo', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2320
    }
2321
2322
    /**
2323
     * @group legacy
2324
     */
2325
    public function testOutput(): void
2326
    {
2327
        $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...
2328
            ->method('getTemplate')
2329
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
2330
2331
        $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...
2332
            ->method('getFieldName')
2333
            ->willReturn('fd_name');
2334
2335
        $this->environment->disableDebug();
2336
2337
        $parameters = [
2338
            'admin' => $this->admin,
2339
            'value' => 'foo',
2340
            'field_description' => $this->fieldDescription,
2341
            'object' => $this->object,
2342
        ];
2343
2344
        $template = $this->environment->loadTemplate('@SonataAdmin/CRUD/base_list_field.html.twig');
2345
2346
        $this->assertSame(
2347
            '<td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>',
2348
            $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...
2349
                $this->fieldDescription,
2350
                $template,
2351
                $parameters,
2352
                $this->environment
2353
            ))
2354
        );
2355
2356
        $this->environment->enableDebug();
2357
        $this->assertSame(
2358
            $this->removeExtraWhitespace(
2359
                <<<'EOT'
2360
<!-- START
2361
    fieldName: fd_name
2362
    template: @SonataAdmin/CRUD/base_list_field.html.twig
2363
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
2364
-->
2365
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
2366
<!-- END - fieldName: fd_name -->
2367
EOT
2368
            ),
2369
            $this->removeExtraWhitespace(
2370
                $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...
2371
            )
2372
        );
2373
    }
2374
2375
    /**
2376
     * @group legacy
2377
     * @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).
2378
     */
2379
    public function testRenderWithDebug(): void
2380
    {
2381
        $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...
2382
            ->method('getTemplate')
2383
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
2384
2385
        $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...
2386
            ->method('getFieldName')
2387
            ->willReturn('fd_name');
2388
2389
        $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...
2390
            ->method('getValue')
2391
            ->willReturn('foo');
2392
2393
        $parameters = [
2394
            'admin' => $this->admin,
2395
            'value' => 'foo',
2396
            'field_description' => $this->fieldDescription,
2397
            'object' => $this->object,
2398
        ];
2399
2400
        $this->environment->enableDebug();
2401
2402
        $this->assertSame(
2403
            $this->removeExtraWhitespace(
2404
                <<<'EOT'
2405
<!-- START
2406
    fieldName: fd_name
2407
    template: @SonataAdmin/CRUD/base_list_field.html.twig
2408
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
2409
-->
2410
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
2411
<!-- END - fieldName: fd_name -->
2412
EOT
2413
            ),
2414
            $this->removeExtraWhitespace(
2415
                $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription, $parameters)
2416
            )
2417
        );
2418
    }
2419
2420
    public function testRenderRelationElementNoObject(): void
2421
    {
2422
        $this->assertSame('foo', $this->twigExtension->renderRelationElement('foo', $this->fieldDescription));
2423
    }
2424
2425
    public function testRenderRelationElementToString(): void
2426
    {
2427
        $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...
2428
            ->method('getOption')
2429
            ->willReturnCallback(static function ($value, $default = null) {
2430
                if ('associated_property' === $value) {
2431
                    return $default;
2432
                }
2433
            });
2434
2435
        $element = new FooToString();
2436
        $this->assertSame('salut', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2437
    }
2438
2439
    /**
2440
     * @group legacy
2441
     */
2442
    public function testDeprecatedRelationElementToString(): void
2443
    {
2444
        $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...
2445
            ->method('getOption')
2446
            ->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...
2447
                if ('associated_tostring' === $value) {
2448
                    return '__toString';
2449
                }
2450
            });
2451
2452
        $element = new FooToString();
2453
        $this->assertSame(
2454
            'salut',
2455
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2456
        );
2457
    }
2458
2459
    /**
2460
     * @group legacy
2461
     */
2462
    public function testRenderRelationElementCustomToString(): void
2463
    {
2464
        $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...
2465
            ->method('getOption')
2466
            ->willReturnCallback(static function ($value, $default = null) {
2467
                if ('associated_property' === $value) {
2468
                    return $default;
2469
                }
2470
2471
                if ('associated_tostring' === $value) {
2472
                    return 'customToString';
2473
                }
2474
            });
2475
2476
        $element = $this->getMockBuilder(\stdClass::class)
2477
            ->setMethods(['customToString'])
2478
            ->getMock();
2479
        $element
2480
            ->method('customToString')
2481
            ->willReturn('fooBar');
2482
2483
        $this->assertSame('fooBar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2484
    }
2485
2486
    /**
2487
     * @group legacy
2488
     */
2489
    public function testRenderRelationElementMethodNotExist(): void
2490
    {
2491
        $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...
2492
            ->method('getOption')
2493
2494
            ->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...
2495
                if ('associated_tostring' === $value) {
2496
                    return 'nonExistedMethod';
2497
                }
2498
            });
2499
2500
        $element = new \stdClass();
2501
        $this->expectException(\RuntimeException::class);
2502
        $this->expectExceptionMessage('You must define an `associated_property` option or create a `stdClass::__toString');
2503
2504
        $this->twigExtension->renderRelationElement($element, $this->fieldDescription);
2505
    }
2506
2507
    public function testRenderRelationElementWithPropertyPath(): void
2508
    {
2509
        $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...
2510
            ->method('getOption')
2511
2512
            ->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...
2513
                if ('associated_property' === $value) {
2514
                    return 'foo';
2515
                }
2516
            });
2517
2518
        $element = new \stdClass();
2519
        $element->foo = 'bar';
2520
2521
        $this->assertSame('bar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2522
    }
2523
2524
    public function testRenderRelationElementWithClosure(): void
2525
    {
2526
        $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...
2527
            ->method('getOption')
2528
2529
            ->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...
2530
                if ('associated_property' === $value) {
2531
                    return static function ($element): string {
2532
                        return sprintf('closure %s', $element->foo);
2533
                    };
2534
                }
2535
            });
2536
2537
        $element = new \stdClass();
2538
        $element->foo = 'bar';
2539
2540
        $this->assertSame(
2541
            'closure bar',
2542
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2543
        );
2544
    }
2545
2546
    public function testGetUrlsafeIdentifier(): void
2547
    {
2548
        $model = new \stdClass();
2549
2550
        // set admin to pool
2551
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
2552
        $this->pool->setAdminClasses([\stdClass::class => ['sonata_admin_foo_service']]);
2553
2554
        $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...
2555
            ->method('getUrlSafeIdentifier')
2556
            ->with($this->equalTo($model))
2557
            ->willReturn(1234567);
2558
2559
        $this->assertSame(1234567, $this->twigExtension->getUrlSafeIdentifier($model));
2560
    }
2561
2562
    public function testGetUrlsafeIdentifier_GivenAdmin_Foo(): void
2563
    {
2564
        $model = new \stdClass();
2565
2566
        // set admin to pool
2567
        $this->pool->setAdminServiceIds([
2568
            'sonata_admin_foo_service',
2569
            'sonata_admin_bar_service',
2570
        ]);
2571
        $this->pool->setAdminClasses([\stdClass::class => [
2572
            'sonata_admin_foo_service',
2573
            'sonata_admin_bar_service',
2574
        ]]);
2575
2576
        $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...
2577
            ->method('getUrlSafeIdentifier')
2578
            ->with($this->equalTo($model))
2579
            ->willReturn(1234567);
2580
2581
        $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...
2582
            ->method('getUrlSafeIdentifier');
2583
2584
        $this->assertSame(1234567, $this->twigExtension->getUrlSafeIdentifier($model, $this->admin));
2585
    }
2586
2587
    public function testGetUrlsafeIdentifier_GivenAdmin_Bar(): void
2588
    {
2589
        $model = new \stdClass();
2590
2591
        // set admin to pool
2592
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service', 'sonata_admin_bar_service']);
2593
        $this->pool->setAdminClasses([\stdClass::class => [
2594
            'sonata_admin_foo_service',
2595
            'sonata_admin_bar_service',
2596
        ]]);
2597
2598
        $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...
2599
            ->method('getUrlSafeIdentifier');
2600
2601
        $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...
2602
            ->method('getUrlSafeIdentifier')
2603
            ->with($this->equalTo($model))
2604
            ->willReturn(1234567);
2605
2606
        $this->assertSame(1234567, $this->twigExtension->getUrlSafeIdentifier($model, $this->adminBar));
2607
    }
2608
2609
    public function xEditableChoicesProvider()
2610
    {
2611
        return [
2612
            'needs processing' => [
2613
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2']],
2614
                [
2615
                    ['value' => 'Status1', 'text' => 'Alias1'],
2616
                    ['value' => 'Status2', 'text' => 'Alias2'],
2617
                ],
2618
            ],
2619
            'already processed' => [
2620
                ['choices' => [
2621
                    ['value' => 'Status1', 'text' => 'Alias1'],
2622
                    ['value' => 'Status2', 'text' => 'Alias2'],
2623
                ]],
2624
                [
2625
                    ['value' => 'Status1', 'text' => 'Alias1'],
2626
                    ['value' => 'Status2', 'text' => 'Alias2'],
2627
                ],
2628
            ],
2629
            'not required' => [
2630
                [
2631
                    'required' => false,
2632
                    'choices' => ['' => '', 'Status1' => 'Alias1', 'Status2' => 'Alias2'],
2633
                ],
2634
                [
2635
                    ['value' => '', 'text' => ''],
2636
                    ['value' => 'Status1', 'text' => 'Alias1'],
2637
                    ['value' => 'Status2', 'text' => 'Alias2'],
2638
                ],
2639
            ],
2640
            'not required multiple' => [
2641
                [
2642
                    'required' => false,
2643
                    'multiple' => true,
2644
                    'choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2'],
2645
                ],
2646
                [
2647
                    ['value' => 'Status1', 'text' => 'Alias1'],
2648
                    ['value' => 'Status2', 'text' => 'Alias2'],
2649
                ],
2650
            ],
2651
        ];
2652
    }
2653
2654
    /**
2655
     * @dataProvider xEditablechoicesProvider
2656
     */
2657
    public function testGetXEditableChoicesIsIdempotent(array $options, array $expectedChoices): void
2658
    {
2659
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2660
        $fieldDescription
2661
            ->method('getOption')
2662
            ->withConsecutive(
2663
                ['choices', []],
2664
                ['catalogue'],
2665
                ['required'],
2666
                ['multiple']
2667
            )
2668
            ->will($this->onConsecutiveCalls(
2669
                $options['choices'],
2670
                'MyCatalogue',
2671
                $options['multiple'] ?? null
2672
            ));
2673
2674
        $this->assertSame($expectedChoices, $this->twigExtension->getXEditableChoices($fieldDescription));
2675
    }
2676
2677
    public function select2LocalesProvider()
2678
    {
2679
        return [
2680
            ['ar', 'ar'],
2681
            ['az', 'az'],
2682
            ['bg', 'bg'],
2683
            ['ca', 'ca'],
2684
            ['cs', 'cs'],
2685
            ['da', 'da'],
2686
            ['de', 'de'],
2687
            ['el', 'el'],
2688
            [null, 'en'],
2689
            ['es', 'es'],
2690
            ['et', 'et'],
2691
            ['eu', 'eu'],
2692
            ['fa', 'fa'],
2693
            ['fi', 'fi'],
2694
            ['fr', 'fr'],
2695
            ['gl', 'gl'],
2696
            ['he', 'he'],
2697
            ['hr', 'hr'],
2698
            ['hu', 'hu'],
2699
            ['id', 'id'],
2700
            ['is', 'is'],
2701
            ['it', 'it'],
2702
            ['ja', 'ja'],
2703
            ['ka', 'ka'],
2704
            ['ko', 'ko'],
2705
            ['lt', 'lt'],
2706
            ['lv', 'lv'],
2707
            ['mk', 'mk'],
2708
            ['ms', 'ms'],
2709
            ['nb', 'nb'],
2710
            ['nl', 'nl'],
2711
            ['pl', 'pl'],
2712
            ['pt-PT', 'pt'],
2713
            ['pt-BR', 'pt-BR'],
2714
            ['pt-PT', 'pt-PT'],
2715
            ['ro', 'ro'],
2716
            ['rs', 'rs'],
2717
            ['ru', 'ru'],
2718
            ['sk', 'sk'],
2719
            ['sv', 'sv'],
2720
            ['th', 'th'],
2721
            ['tr', 'tr'],
2722
            ['ug-CN', 'ug'],
2723
            ['ug-CN', 'ug-CN'],
2724
            ['uk', 'uk'],
2725
            ['vi', 'vi'],
2726
            ['zh-CN', 'zh'],
2727
            ['zh-CN', 'zh-CN'],
2728
            ['zh-TW', 'zh-TW'],
2729
        ];
2730
    }
2731
2732
    /**
2733
     * @dataProvider select2LocalesProvider
2734
     */
2735
    public function testCanonicalizedLocaleForSelect2(?string $expected, string $original): void
2736
    {
2737
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForSelect2($this->mockExtensionContext($original)));
2738
    }
2739
2740
    public function momentLocalesProvider(): array
2741
    {
2742
        return [
2743
            ['af', 'af'],
2744
            ['ar-dz', 'ar-dz'],
2745
            ['ar', 'ar'],
2746
            ['ar-ly', 'ar-ly'],
2747
            ['ar-ma', 'ar-ma'],
2748
            ['ar-sa', 'ar-sa'],
2749
            ['ar-tn', 'ar-tn'],
2750
            ['az', 'az'],
2751
            ['be', 'be'],
2752
            ['bg', 'bg'],
2753
            ['bn', 'bn'],
2754
            ['bo', 'bo'],
2755
            ['br', 'br'],
2756
            ['bs', 'bs'],
2757
            ['ca', 'ca'],
2758
            ['cs', 'cs'],
2759
            ['cv', 'cv'],
2760
            ['cy', 'cy'],
2761
            ['da', 'da'],
2762
            ['de-at', 'de-at'],
2763
            ['de', 'de'],
2764
            ['de', 'de-de'],
2765
            ['dv', 'dv'],
2766
            ['el', 'el'],
2767
            [null, 'en'],
2768
            [null, 'en-us'],
2769
            ['en-au', 'en-au'],
2770
            ['en-ca', 'en-ca'],
2771
            ['en-gb', 'en-gb'],
2772
            ['en-ie', 'en-ie'],
2773
            ['en-nz', 'en-nz'],
2774
            ['eo', 'eo'],
2775
            ['es-do', 'es-do'],
2776
            ['es', 'es-ar'],
2777
            ['es', 'es-mx'],
2778
            ['es', 'es'],
2779
            ['et', 'et'],
2780
            ['eu', 'eu'],
2781
            ['fa', 'fa'],
2782
            ['fi', 'fi'],
2783
            ['fo', 'fo'],
2784
            ['fr-ca', 'fr-ca'],
2785
            ['fr-ch', 'fr-ch'],
2786
            ['fr', 'fr-fr'],
2787
            ['fr', 'fr'],
2788
            ['fy', 'fy'],
2789
            ['gd', 'gd'],
2790
            ['gl', 'gl'],
2791
            ['he', 'he'],
2792
            ['hi', 'hi'],
2793
            ['hr', 'hr'],
2794
            ['hu', 'hu'],
2795
            ['hy-am', 'hy-am'],
2796
            ['id', 'id'],
2797
            ['is', 'is'],
2798
            ['it', 'it'],
2799
            ['ja', 'ja'],
2800
            ['jv', 'jv'],
2801
            ['ka', 'ka'],
2802
            ['kk', 'kk'],
2803
            ['km', 'km'],
2804
            ['ko', 'ko'],
2805
            ['ky', 'ky'],
2806
            ['lb', 'lb'],
2807
            ['lo', 'lo'],
2808
            ['lt', 'lt'],
2809
            ['lv', 'lv'],
2810
            ['me', 'me'],
2811
            ['mi', 'mi'],
2812
            ['mk', 'mk'],
2813
            ['ml', 'ml'],
2814
            ['mr', 'mr'],
2815
            ['ms', 'ms'],
2816
            ['ms-my', 'ms-my'],
2817
            ['my', 'my'],
2818
            ['nb', 'nb'],
2819
            ['ne', 'ne'],
2820
            ['nl-be', 'nl-be'],
2821
            ['nl', 'nl'],
2822
            ['nl', 'nl-nl'],
2823
            ['nn', 'nn'],
2824
            ['pa-in', 'pa-in'],
2825
            ['pl', 'pl'],
2826
            ['pt-br', 'pt-br'],
2827
            ['pt', 'pt'],
2828
            ['ro', 'ro'],
2829
            ['ru', 'ru'],
2830
            ['se', 'se'],
2831
            ['si', 'si'],
2832
            ['sk', 'sk'],
2833
            ['sl', 'sl'],
2834
            ['sq', 'sq'],
2835
            ['sr-cyrl', 'sr-cyrl'],
2836
            ['sr', 'sr'],
2837
            ['ss', 'ss'],
2838
            ['sv', 'sv'],
2839
            ['sw', 'sw'],
2840
            ['ta', 'ta'],
2841
            ['te', 'te'],
2842
            ['tet', 'tet'],
2843
            ['th', 'th'],
2844
            ['tlh', 'tlh'],
2845
            ['tl-ph', 'tl-ph'],
2846
            ['tr', 'tr'],
2847
            ['tzl', 'tzl'],
2848
            ['tzm', 'tzm'],
2849
            ['tzm-latn', 'tzm-latn'],
2850
            ['uk', 'uk'],
2851
            ['uz', 'uz'],
2852
            ['vi', 'vi'],
2853
            ['x-pseudo', 'x-pseudo'],
2854
            ['yo', 'yo'],
2855
            ['zh-cn', 'zh-cn'],
2856
            ['zh-hk', 'zh-hk'],
2857
            ['zh-tw', 'zh-tw'],
2858
        ];
2859
    }
2860
2861
    /**
2862
     * @dataProvider momentLocalesProvider
2863
     */
2864
    public function testCanonicalizedLocaleForMoment(?string $expected, string $original): void
2865
    {
2866
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForMoment($this->mockExtensionContext($original)));
2867
    }
2868
2869
    public function testIsGrantedAffirmative(): void
2870
    {
2871
        $this->assertTrue(
2872
            $this->twigExtension->isGrantedAffirmative(['foo', 'bar'])
2873
        );
2874
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('foo'));
2875
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('bar'));
2876
    }
2877
2878
    /**
2879
     * @dataProvider getRenderViewElementCompareTests
2880
     */
2881
    public function testRenderViewElementCompare(string $expected, string $type, $value, array $options, ?string $objectName = null): void
2882
    {
2883
        $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...
2884
            ->method('getTemplate')
2885
            ->willReturn('@SonataAdmin/CRUD/base_show_compare.html.twig');
2886
2887
        $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...
2888
            ->method('getValue')
2889
            ->willReturn($value);
2890
2891
        $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...
2892
            ->method('getType')
2893
            ->willReturn($type);
2894
2895
        $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...
2896
            ->method('getOptions')
2897
            ->willReturn($options);
2898
2899
        $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...
2900
            ->method('getTemplate')
2901
            ->willReturnCallback(static function () use ($type, $options): ?string {
2902
                if (isset($options['template'])) {
2903
                    return $options['template'];
2904
                }
2905
2906
                switch ($type) {
2907
                    case 'boolean':
2908
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
2909
                    case 'datetime':
2910
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
2911
                    case 'date':
2912
                        return '@SonataAdmin/CRUD/show_date.html.twig';
2913
                    case 'time':
2914
                        return '@SonataAdmin/CRUD/show_time.html.twig';
2915
                    case 'currency':
2916
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
2917
                    case 'percent':
2918
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
2919
                    case 'email':
2920
                        return '@SonataAdmin/CRUD/show_email.html.twig';
2921
                    case 'choice':
2922
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
2923
                    case 'array':
2924
                        return '@SonataAdmin/CRUD/show_array.html.twig';
2925
                    case 'trans':
2926
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
2927
                    case 'url':
2928
                        return '@SonataAdmin/CRUD/show_url.html.twig';
2929
                    case 'html':
2930
                        return '@SonataAdmin/CRUD/show_html.html.twig';
2931
                    default:
2932
                        return null;
2933
                }
2934
            });
2935
2936
        $this->object->name = 'SonataAdmin';
2937
2938
        $comparedObject = clone $this->object;
2939
2940
        if (null !== $objectName) {
2941
            $comparedObject->name = $objectName;
2942
        }
2943
2944
        $this->assertSame(
2945
            $this->removeExtraWhitespace($expected),
2946
            $this->removeExtraWhitespace(
2947
                $this->twigExtension->renderViewElementCompare(
2948
                    $this->environment,
2949
                    $this->fieldDescription,
2950
                    $this->object,
2951
                    $comparedObject
2952
                )
2953
            )
2954
        );
2955
    }
2956
2957
    public function getRenderViewElementCompareTests(): iterable
2958
    {
2959
        return [
2960
            ['<th>Data</th> <td>Example</td><td>Example</td>', 'string', 'Example', ['safe' => false]],
2961
            ['<th>Data</th> <td>Example</td><td>Example</td>', 'text', 'Example', ['safe' => false]],
2962
            ['<th>Data</th> <td>Example</td><td>Example</td>', 'textarea', 'Example', ['safe' => false]],
2963
            ['<th>Data</th> <td>SonataAdmin<br/>Example</td><td>SonataAdmin<br/>Example</td>', 'virtual_field', 'Example', ['template' => 'custom_show_field.html.twig', 'safe' => false, 'SonataAdmin']],
2964
            ['<th class="diff">Data</th> <td>SonataAdmin<br/>Example</td><td>SonataAdmin<br/>Example</td>', 'virtual_field', 'Example', ['template' => 'custom_show_field.html.twig', 'safe' => false], 'sonata-project/admin-bundle'],
2965
            [
2966
                '<th>Data</th> <td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> May 27, 2020 10:11 </time></td>'
2967
                .'<td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> May 27, 2020 10:11 </time></td>',
2968
                'datetime',
2969
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('Europe/London')), [],
2970
            ],
2971
            [
2972
                '<th>Data</th> <td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> 27.05.2020 10:11:12 </time></td>'
2973
                .'<td><time datetime="2020-05-27T09:11:12+00:00" title="2020-05-27T09:11:12+00:00"> 27.05.2020 10:11:12 </time></td>',
2974
                'datetime',
2975
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('Europe/London')),
2976
                ['format' => 'd.m.Y H:i:s'],
2977
            ],
2978
            [
2979
                '<th>Data</th> <td><time datetime="2020-05-27T10:11:12+00:00" title="2020-05-27T10:11:12+00:00"> May 27, 2020 18:11 </time></td>'
2980
                .'<td><time datetime="2020-05-27T10:11:12+00:00" title="2020-05-27T10:11:12+00:00"> May 27, 2020 18:11 </time></td>',
2981
                'datetime',
2982
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('UTC')),
2983
                ['timezone' => 'Asia/Hong_Kong'],
2984
            ],
2985
            [
2986
                '<th>Data</th> <td><time datetime="2020-05-27" title="2020-05-27"> May 27, 2020 </time></td>'
2987
                .'<td><time datetime="2020-05-27" title="2020-05-27"> May 27, 2020 </time></td>',
2988
                'date',
2989
                new \DateTime('2020-05-27 10:11:12', new \DateTimeZone('Europe/London')),
2990
                [],
2991
            ],
2992
        ];
2993
    }
2994
2995
    /**
2996
     * This method generates url part for Twig layout.
2997
     */
2998
    private function buildTwigLikeUrl(array $url): string
2999
    {
3000
        return htmlspecialchars(http_build_query($url, '', '&', PHP_QUERY_RFC3986));
3001
    }
3002
3003
    private function removeExtraWhitespace(string $string): string
3004
    {
3005
        return trim(preg_replace(
3006
            '/\s+/',
3007
            ' ',
3008
            $string
3009
        ));
3010
    }
3011
3012
    private function mockExtensionContext(string $locale): array
3013
    {
3014
        $request = $this->createMock(Request::class);
3015
        $request->method('getLocale')->willReturn($locale);
3016
        $appVariable = $this->createMock(AppVariable::class);
3017
        $appVariable->method('getRequest')->willReturn($request);
3018
3019
        return ['app' => $appVariable];
3020
    }
3021
}
3022