Completed
Pull Request — master (#5076)
by Grégoire
03:49
created

SonataAdminExtensionTest::testRenderListElement()   D

Complexity

Conditions 15
Paths 1

Size

Total Lines 83
Code Lines 65

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 83
rs 4.9121
c 0
b 0
f 0
cc 15
eloc 65
nc 1
nop 4

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 Psr\Log\LoggerInterface;
18
use Sonata\AdminBundle\Admin\AbstractAdmin;
19
use Sonata\AdminBundle\Admin\AdminInterface;
20
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
21
use Sonata\AdminBundle\Admin\Pool;
22
use Sonata\AdminBundle\Exception\NoValueException;
23
use Sonata\AdminBundle\Templating\TemplateRegistryInterface;
24
use Sonata\AdminBundle\Tests\Fixtures\Entity\FooToString;
25
use Sonata\AdminBundle\Twig\Extension\SonataAdminExtension;
26
use Symfony\Bridge\Twig\AppVariable;
27
use Symfony\Bridge\Twig\Extension\RoutingExtension;
28
use Symfony\Bridge\Twig\Extension\TranslationExtension;
29
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
30
use Symfony\Component\Config\FileLocator;
31
use Symfony\Component\DependencyInjection\ContainerInterface;
32
use Symfony\Component\HttpFoundation\Request;
33
use Symfony\Component\Routing\Generator\UrlGenerator;
34
use Symfony\Component\Routing\Loader\XmlFileLoader;
35
use Symfony\Component\Routing\RequestContext;
36
use Symfony\Component\Translation\DependencyInjection\TranslationDumperPass;
37
use Symfony\Component\Translation\Loader\XliffFileLoader;
38
use Symfony\Component\Translation\MessageSelector;
39
use Symfony\Component\Translation\Translator;
40
use Symfony\Component\Translation\TranslatorInterface;
41
42
/**
43
 * Test for SonataAdminExtension.
44
 *
45
 * @author Andrej Hudec <[email protected]>
46
 */
47
class SonataAdminExtensionTest extends TestCase
48
{
49
    /**
50
     * @var SonataAdminExtension
51
     */
52
    private $twigExtension;
53
54
    /**
55
     * @var \Twig_Environment
56
     */
57
    private $environment;
58
59
    /**
60
     * @var AdminInterface
61
     */
62
    private $admin;
63
64
    /**
65
     * @var AdminInterface
66
     */
67
    private $adminBar;
68
69
    /**
70
     * @var FieldDescriptionInterface
71
     */
72
    private $fieldDescription;
73
74
    /**
75
     * @var \stdClass
76
     */
77
    private $object;
78
79
    /**
80
     * @var Pool
81
     */
82
    private $pool;
83
84
    /**
85
     * @var LoggerInterface
86
     */
87
    private $logger;
88
89
    /**
90
     * @var string[]
91
     */
92
    private $xEditableTypeMapping;
93
94
    /**
95
     * @var TranslatorInterface
96
     */
97
    private $translator;
98
99
    /**
100
     * @var ContainerInterface
101
     */
102
    private $container;
103
104
    /**
105
     * @var TemplateRegistryInterface
106
     */
107
    private $templateRegistry;
108
109
    public function setUp(): void
110
    {
111
        date_default_timezone_set('Europe/London');
112
113
        $container = $this->getMockForAbstractClass(ContainerInterface::class);
114
115
        $this->pool = new Pool($container, '', '');
116
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
117
        $this->pool->setAdminClasses(['fooClass' => ['sonata_admin_foo_service']]);
118
119
        $this->logger = $this->getMockForAbstractClass(LoggerInterface::class);
120
        $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...
121
            'choice' => 'select',
122
            'boolean' => 'select',
123
            'text' => 'text',
124
            'textarea' => 'textarea',
125
            'html' => 'textarea',
126
            'email' => 'email',
127
            'string' => 'text',
128
            'smallint' => 'text',
129
            'bigint' => 'text',
130
            'integer' => 'number',
131
            'decimal' => 'number',
132
            'currency' => 'number',
133
            'percent' => 'number',
134
            'url' => 'url',
135
        ];
136
137
        // translation extension
138
        $translator = new Translator(
139
            'en',
140
            // NEXT_MAJOR: simplify this when dropping symfony < 3.4
141
            class_exists(TranslationDumperPass::class) ? null : new MessageSelector()
0 ignored issues
show
Documentation introduced by
class_exists(\Symfony\Co...ation\MessageSelector() is of type object<Symfony\Component...lation\MessageSelector>, but the function expects a null|object<Symfony\Comp...sageFormatterInterface>.

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...
142
        );
143
        $translator->addLoader('xlf', new XliffFileLoader());
144
        $translator->addResource(
145
            'xlf',
146
            __DIR__.'/../../../src/Resources/translations/SonataAdminBundle.en.xliff',
147
            'en',
148
            'SonataAdminBundle'
149
        );
150
151
        $this->translator = $translator;
152
153
        $this->templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
154
        $this->container = $this->prophesize(ContainerInterface::class);
155
        $this->container->get('sonata_admin_foo_service.template_registry')->willReturn($this->templateRegistry->reveal());
156
157
        $this->twigExtension = new SonataAdminExtension($this->pool, $this->logger, $this->translator, $this->container->reveal());
158
        $this->twigExtension->setXEditableTypeMapping($this->xEditableTypeMapping);
159
160
        $request = $this->createMock(Request::class);
161
        $request->expects($this->any())->method('get')->with('_sonata_admin')->willReturn('sonata_admin_foo_service');
162
163
        $loader = new StubFilesystemLoader([
164
            __DIR__.'/../../../src/Resources/views/CRUD',
165
        ]);
166
        $loader->addPath(__DIR__.'/../../../src/Resources/views/', 'SonataAdmin');
167
168
        $this->environment = new \Twig_Environment($loader, [
169
            'strict_variables' => true,
170
            'cache' => false,
171
            'autoescape' => 'html',
172
            'optimizations' => 0,
173
        ]);
174
        $this->environment->addExtension($this->twigExtension);
175
        $this->environment->addExtension(new TranslationExtension($translator));
176
        $this->environment->addExtension(new FakeTemplateRegistryExtension());
177
178
        // routing extension
179
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../../src/Resources/config/routing']));
180
        $routeCollection = $xmlFileLoader->load('sonata_admin.xml');
181
182
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../Fixtures/Resources/config/routing']));
183
        $testRouteCollection = $xmlFileLoader->load('routing.xml');
184
185
        $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...
186
        $requestContext = new RequestContext();
187
        $urlGenerator = new UrlGenerator($routeCollection, $requestContext);
188
        $this->environment->addExtension(new RoutingExtension($urlGenerator));
189
        $this->environment->addExtension(new \Twig_Extensions_Extension_Text());
190
191
        // initialize object
192
        $this->object = new \stdClass();
193
194
        // initialize admin
195
        $this->admin = $this->createMock(AbstractAdmin::class);
196
197
        $this->admin->expects($this->any())
198
            ->method('getCode')
199
            ->will($this->returnValue('sonata_admin_foo_service'));
200
201
        $this->admin->expects($this->any())
202
            ->method('id')
203
            ->with($this->equalTo($this->object))
204
            ->will($this->returnValue(12345));
205
206
        $this->admin->expects($this->any())
207
            ->method('getNormalizedIdentifier')
208
            ->with($this->equalTo($this->object))
209
            ->will($this->returnValue(12345));
210
211
        $this->admin->expects($this->any())
212
            ->method('trans')
213
            ->will($this->returnCallback(function ($id, $parameters = [], $domain = null) use ($translator) {
214
                return $translator->trans($id, $parameters, $domain);
215
            }));
216
217
        $this->adminBar = $this->createMock(AbstractAdmin::class);
218
        $this->adminBar->expects($this->any())
219
            ->method('hasAccess')
220
            ->will($this->returnValue(true));
221
        $this->adminBar->expects($this->any())
222
            ->method('getNormalizedIdentifier')
223
            ->with($this->equalTo($this->object))
224
            ->will($this->returnValue(12345));
225
226
        $container->expects($this->any())
227
            ->method('get')
228
            ->will($this->returnCallback(function ($id) {
229
                if ('sonata_admin_foo_service' == $id) {
230
                    return $this->admin;
231
                } elseif ('sonata_admin_bar_service' == $id) {
232
                    return $this->adminBar;
233
                }
234
            }));
235
236
        // initialize field description
237
        $this->fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
238
239
        $this->fieldDescription->expects($this->any())
240
            ->method('getName')
241
            ->will($this->returnValue('fd_name'));
242
243
        $this->fieldDescription->expects($this->any())
244
            ->method('getAdmin')
245
            ->will($this->returnValue($this->admin));
246
247
        $this->fieldDescription->expects($this->any())
248
            ->method('getLabel')
249
            ->will($this->returnValue('Data'));
250
    }
251
252
    /**
253
     * @group legacy
254
     * @expectedDepreaction The Sonata\AdminBundle\Admin\AbstractAdmin::getTemplate method is deprecated (since 3.34, will be dropped in 4.0. Use TemplateRegistry services instead).
255
     * @dataProvider getRenderListElementTests
256
     */
257
    public function testRenderListElement($expected, $type, $value, array $options): void
258
    {
259
        $this->admin->expects($this->any())
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...
260
            ->method('getPersistentParameters')
261
            ->will($this->returnValue(['context' => 'foo']));
262
263
        $this->admin->expects($this->any())
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...
264
            ->method('hasAccess')
265
            ->will($this->returnValue(true));
266
267
        // NEXT_MAJOR: Remove this line
268
        $this->admin->expects($this->any())
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...
269
            ->method('getTemplate')
270
            ->with('base_list_field')
271
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
272
273
        $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...
274
275
        $this->fieldDescription->expects($this->any())
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...
276
            ->method('getValue')
277
            ->will($this->returnValue($value));
278
279
        $this->fieldDescription->expects($this->any())
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...
280
            ->method('getType')
281
            ->will($this->returnValue($type));
282
283
        $this->fieldDescription->expects($this->any())
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...
284
            ->method('getOptions')
285
            ->will($this->returnValue($options));
286
287
        $this->fieldDescription->expects($this->any())
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...
288
            ->method('getOption')
289
            ->will($this->returnCallback(function ($name, $default = null) use ($options) {
290
                return $options[$name] ?? $default;
291
            }));
292
293
        $this->fieldDescription->expects($this->any())
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...
294
            ->method('getTemplate')
295
            ->will($this->returnCallback(function () use ($type) {
296
                switch ($type) {
297
                    case 'string':
298
                        return '@SonataAdmin/CRUD/list_string.html.twig';
299
                    case 'boolean':
300
                        return '@SonataAdmin/CRUD/list_boolean.html.twig';
301
                    case 'datetime':
302
                        return '@SonataAdmin/CRUD/list_datetime.html.twig';
303
                    case 'date':
304
                        return '@SonataAdmin/CRUD/list_date.html.twig';
305
                    case 'time':
306
                        return '@SonataAdmin/CRUD/list_time.html.twig';
307
                    case 'currency':
308
                        return '@SonataAdmin/CRUD/list_currency.html.twig';
309
                    case 'percent':
310
                        return '@SonataAdmin/CRUD/list_percent.html.twig';
311
                    case 'email':
312
                        return '@SonataAdmin/CRUD/list_email.html.twig';
313
                    case 'choice':
314
                        return '@SonataAdmin/CRUD/list_choice.html.twig';
315
                    case 'array':
316
                        return '@SonataAdmin/CRUD/list_array.html.twig';
317
                    case 'trans':
318
                        return '@SonataAdmin/CRUD/list_trans.html.twig';
319
                    case 'url':
320
                        return '@SonataAdmin/CRUD/list_url.html.twig';
321
                    case 'html':
322
                        return '@SonataAdmin/CRUD/list_html.html.twig';
323
                    case 'nonexistent':
324
                        // template doesn't exist
325
                        return '@SonataAdmin/CRUD/list_nonexistent_template.html.twig';
326
                    default:
327
                        return false;
328
                }
329
            }));
330
331
        $this->assertSame(
332
            $this->removeExtraWhitespace($expected),
333
            $this->removeExtraWhitespace($this->twigExtension->renderListElement(
334
                $this->environment,
0 ignored issues
show
Compatibility introduced by
$this->environment of type object<Twig_Environment> is not a sub-type of object<Twig\Environment>. It seems like you assume a child class of the class Twig_Environment to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

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

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

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

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1986
            )
1987
        );
1988
    }
1989
1990
    public function testRenderRelationElementNoObject(): void
1991
    {
1992
        $this->assertSame('foo', $this->twigExtension->renderRelationElement('foo', $this->fieldDescription));
1993
    }
1994
1995
    public function testRenderRelationElementToString(): void
1996
    {
1997
        $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...
1998
            ->method('getOption')
1999
            ->will($this->returnCallback(function ($value, $default = null) {
2000
                if ('associated_property' == $value) {
2001
                    return $default;
2002
                }
2003
            }));
2004
2005
        $element = new FooToString();
2006
        $this->assertSame('salut', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2007
    }
2008
2009
    /**
2010
     * @group legacy
2011
     */
2012
    public function testDeprecatedRelationElementToString(): void
2013
    {
2014
        $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...
2015
            ->method('getOption')
2016
            ->will($this->returnCallback(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...
2017
                if ('associated_tostring' == $value) {
2018
                    return '__toString';
2019
                }
2020
            }));
2021
2022
        $element = new FooToString();
2023
        $this->assertSame(
2024
            'salut',
2025
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2026
        );
2027
    }
2028
2029
    /**
2030
     * @group legacy
2031
     */
2032
    public function testRenderRelationElementCustomToString(): void
2033
    {
2034
        $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...
2035
            ->method('getOption')
2036
            ->will($this->returnCallback(function ($value, $default = null) {
2037
                if ('associated_property' == $value) {
2038
                    return $default;
2039
                }
2040
2041
                if ('associated_tostring' == $value) {
2042
                    return 'customToString';
2043
                }
2044
            }));
2045
2046
        $element = $this->getMockBuilder('stdClass')
2047
            ->setMethods(['customToString'])
2048
            ->getMock();
2049
        $element->expects($this->any())
2050
            ->method('customToString')
2051
            ->will($this->returnValue('fooBar'));
2052
2053
        $this->assertSame('fooBar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2054
    }
2055
2056
    /**
2057
     * @group legacy
2058
     */
2059
    public function testRenderRelationElementMethodNotExist(): void
2060
    {
2061
        $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...
2062
            ->method('getOption')
2063
2064
            ->will($this->returnCallback(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...
2065
                if ('associated_tostring' == $value) {
2066
                    return 'nonExistedMethod';
2067
                }
2068
            }));
2069
2070
        $element = new \stdClass();
2071
        $this->expectException(\RuntimeException::class, 'You must define an `associated_property` option or create a `stdClass::__toString');
2072
2073
        $this->twigExtension->renderRelationElement($element, $this->fieldDescription);
2074
    }
2075
2076
    public function testRenderRelationElementWithPropertyPath(): void
2077
    {
2078
        $this->fieldDescription->expects($this->exactly(1))
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...
2079
            ->method('getOption')
2080
2081
            ->will($this->returnCallback(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...
2082
                if ('associated_property' == $value) {
2083
                    return 'foo';
2084
                }
2085
            }));
2086
2087
        $element = new \stdClass();
2088
        $element->foo = 'bar';
2089
2090
        $this->assertSame('bar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2091
    }
2092
2093
    public function testRenderRelationElementWithClosure(): void
2094
    {
2095
        $this->fieldDescription->expects($this->exactly(1))
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...
2096
            ->method('getOption')
2097
2098
            ->will($this->returnCallback(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...
2099
                if ('associated_property' == $value) {
2100
                    return function ($element) {
2101
                        return 'closure '.$element->foo;
2102
                    };
2103
                }
2104
            }));
2105
2106
        $element = new \stdClass();
2107
        $element->foo = 'bar';
2108
2109
        $this->assertSame(
2110
            'closure bar',
2111
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2112
        );
2113
    }
2114
2115
    public function testGetUrlsafeIdentifier(): void
2116
    {
2117
        $entity = new \stdClass();
2118
2119
        // set admin to pool
2120
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
2121
        $this->pool->setAdminClasses(['stdClass' => ['sonata_admin_foo_service']]);
2122
2123
        $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...
2124
            ->method('getUrlsafeIdentifier')
2125
            ->with($this->equalTo($entity))
2126
            ->will($this->returnValue(1234567));
2127
2128
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity));
2129
    }
2130
2131
    public function testGetUrlsafeIdentifier_GivenAdmin_Foo(): void
0 ignored issues
show
Coding Style introduced by
Method name "SonataAdminExtensionTest::testGetUrlsafeIdentifier_GivenAdmin_Foo" is not in camel caps format
Loading history...
2132
    {
2133
        $entity = new \stdClass();
2134
2135
        // set admin to pool
2136
        $this->pool->setAdminServiceIds([
2137
            'sonata_admin_foo_service',
2138
            'sonata_admin_bar_service',
2139
        ]);
2140
        $this->pool->setAdminClasses(['stdClass' => [
2141
            'sonata_admin_foo_service',
2142
            'sonata_admin_bar_service',
2143
        ]]);
2144
2145
        $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...
2146
            ->method('getUrlsafeIdentifier')
2147
            ->with($this->equalTo($entity))
2148
            ->will($this->returnValue(1234567));
2149
2150
        $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...
2151
            ->method('getUrlsafeIdentifier');
2152
2153
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->admin));
2154
    }
2155
2156
    public function testGetUrlsafeIdentifier_GivenAdmin_Bar(): void
0 ignored issues
show
Coding Style introduced by
Method name "SonataAdminExtensionTest::testGetUrlsafeIdentifier_GivenAdmin_Bar" is not in camel caps format
Loading history...
2157
    {
2158
        $entity = new \stdClass();
2159
2160
        // set admin to pool
2161
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service', 'sonata_admin_bar_service']);
2162
        $this->pool->setAdminClasses(['stdClass' => [
2163
            'sonata_admin_foo_service',
2164
            'sonata_admin_bar_service',
2165
        ]]);
2166
2167
        $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...
2168
            ->method('getUrlsafeIdentifier');
2169
2170
        $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...
2171
            ->method('getUrlsafeIdentifier')
2172
            ->with($this->equalTo($entity))
2173
            ->will($this->returnValue(1234567));
2174
2175
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->adminBar));
2176
    }
2177
2178
    public function xEditableChoicesProvider()
2179
    {
2180
        return [
2181
            'needs processing' => [
2182
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2']],
2183
                [
2184
                    ['value' => 'Status1', 'text' => 'Alias1'],
2185
                    ['value' => 'Status2', 'text' => 'Alias2'],
2186
                ],
2187
            ],
2188
            'already processed' => [
2189
                ['choices' => [
2190
                    ['value' => 'Status1', 'text' => 'Alias1'],
2191
                    ['value' => 'Status2', 'text' => 'Alias2'],
2192
                ]],
2193
                [
2194
                    ['value' => 'Status1', 'text' => 'Alias1'],
2195
                    ['value' => 'Status2', 'text' => 'Alias2'],
2196
                ],
2197
            ],
2198
            'not required' => [
2199
                [
2200
                    'required' => false,
2201
                    'choices' => ['' => '', 'Status1' => 'Alias1', 'Status2' => 'Alias2'],
2202
                ],
2203
                [
2204
                    ['value' => '', 'text' => ''],
2205
                    ['value' => 'Status1', 'text' => 'Alias1'],
2206
                    ['value' => 'Status2', 'text' => 'Alias2'],
2207
                ],
2208
            ],
2209
            'not required multiple' => [
2210
                [
2211
                    'required' => false,
2212
                    'multiple' => true,
2213
                    'choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2'],
2214
                ],
2215
                [
2216
                    ['value' => 'Status1', 'text' => 'Alias1'],
2217
                    ['value' => 'Status2', 'text' => 'Alias2'],
2218
                ],
2219
            ],
2220
        ];
2221
    }
2222
2223
    /**
2224
     * @dataProvider xEditablechoicesProvider
2225
     */
2226
    public function testGetXEditableChoicesIsIdempotent(array $options, $expectedChoices): void
2227
    {
2228
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2229
        $fieldDescription->expects($this->any())
2230
            ->method('getOption')
2231
            ->withConsecutive(
2232
                ['choices', []],
2233
                ['catalogue'],
2234
                ['required'],
2235
                ['multiple']
2236
            )
2237
            ->will($this->onConsecutiveCalls(
2238
                $options['choices'],
2239
                'MyCatalogue',
2240
                $options['multiple'] ?? null
2241
            ));
2242
2243
        $this->assertSame($expectedChoices, $this->twigExtension->getXEditableChoices($fieldDescription));
2244
    }
2245
2246
    public function select2LocalesProvider()
2247
    {
2248
        return [
2249
            ['ar', 'ar'],
2250
            ['az', 'az'],
2251
            ['bg', 'bg'],
2252
            ['ca', 'ca'],
2253
            ['cs', 'cs'],
2254
            ['da', 'da'],
2255
            ['de', 'de'],
2256
            ['el', 'el'],
2257
            [null, 'en'],
2258
            ['es', 'es'],
2259
            ['et', 'et'],
2260
            ['eu', 'eu'],
2261
            ['fa', 'fa'],
2262
            ['fi', 'fi'],
2263
            ['fr', 'fr'],
2264
            ['gl', 'gl'],
2265
            ['he', 'he'],
2266
            ['hr', 'hr'],
2267
            ['hu', 'hu'],
2268
            ['id', 'id'],
2269
            ['is', 'is'],
2270
            ['it', 'it'],
2271
            ['ja', 'ja'],
2272
            ['ka', 'ka'],
2273
            ['ko', 'ko'],
2274
            ['lt', 'lt'],
2275
            ['lv', 'lv'],
2276
            ['mk', 'mk'],
2277
            ['ms', 'ms'],
2278
            ['nb', 'nb'],
2279
            ['nl', 'nl'],
2280
            ['pl', 'pl'],
2281
            ['pt-PT', 'pt'],
2282
            ['pt-BR', 'pt-BR'],
2283
            ['pt-PT', 'pt-PT'],
2284
            ['ro', 'ro'],
2285
            ['rs', 'rs'],
2286
            ['ru', 'ru'],
2287
            ['sk', 'sk'],
2288
            ['sv', 'sv'],
2289
            ['th', 'th'],
2290
            ['tr', 'tr'],
2291
            ['ug-CN', 'ug'],
2292
            ['ug-CN', 'ug-CN'],
2293
            ['uk', 'uk'],
2294
            ['vi', 'vi'],
2295
            ['zh-CN', 'zh'],
2296
            ['zh-CN', 'zh-CN'],
2297
            ['zh-TW', 'zh-TW'],
2298
        ];
2299
    }
2300
2301
    /**
2302
     * @dataProvider select2LocalesProvider
2303
     */
2304
    public function testCanonicalizedLocaleForSelect2($expected, $original): void
2305
    {
2306
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForSelect2($this->mockExtensionContext($original)));
2307
    }
2308
2309
    public function momentLocalesProvider()
2310
    {
2311
        return [
2312
            ['af', 'af'],
2313
            ['ar-dz', 'ar-dz'],
2314
            ['ar', 'ar'],
2315
            ['ar-ly', 'ar-ly'],
2316
            ['ar-ma', 'ar-ma'],
2317
            ['ar-sa', 'ar-sa'],
2318
            ['ar-tn', 'ar-tn'],
2319
            ['az', 'az'],
2320
            ['be', 'be'],
2321
            ['bg', 'bg'],
2322
            ['bn', 'bn'],
2323
            ['bo', 'bo'],
2324
            ['br', 'br'],
2325
            ['bs', 'bs'],
2326
            ['ca', 'ca'],
2327
            ['cs', 'cs'],
2328
            ['cv', 'cv'],
2329
            ['cy', 'cy'],
2330
            ['da', 'da'],
2331
            ['de-at', 'de-at'],
2332
            ['de', 'de'],
2333
            ['dv', 'dv'],
2334
            ['el', 'el'],
2335
            [null, 'en'],
2336
            [null, 'en-us'],
2337
            ['en-au', 'en-au'],
2338
            ['en-ca', 'en-ca'],
2339
            ['en-gb', 'en-gb'],
2340
            ['en-ie', 'en-ie'],
2341
            ['en-nz', 'en-nz'],
2342
            ['eo', 'eo'],
2343
            ['es-do', 'es-do'],
2344
            ['es', 'es-ar'],
2345
            ['es', 'es-mx'],
2346
            ['es', 'es'],
2347
            ['et', 'et'],
2348
            ['eu', 'eu'],
2349
            ['fa', 'fa'],
2350
            ['fi', 'fi'],
2351
            ['fo', 'fo'],
2352
            ['fr-ca', 'fr-ca'],
2353
            ['fr-ch', 'fr-ch'],
2354
            ['fr', 'fr'],
2355
            ['fy', 'fy'],
2356
            ['gd', 'gd'],
2357
            ['gl', 'gl'],
2358
            ['he', 'he'],
2359
            ['hi', 'hi'],
2360
            ['hr', 'hr'],
2361
            ['hu', 'hu'],
2362
            ['hy-am', 'hy-am'],
2363
            ['id', 'id'],
2364
            ['is', 'is'],
2365
            ['it', 'it'],
2366
            ['ja', 'ja'],
2367
            ['jv', 'jv'],
2368
            ['ka', 'ka'],
2369
            ['kk', 'kk'],
2370
            ['km', 'km'],
2371
            ['ko', 'ko'],
2372
            ['ky', 'ky'],
2373
            ['lb', 'lb'],
2374
            ['lo', 'lo'],
2375
            ['lt', 'lt'],
2376
            ['lv', 'lv'],
2377
            ['me', 'me'],
2378
            ['mi', 'mi'],
2379
            ['mk', 'mk'],
2380
            ['ml', 'ml'],
2381
            ['mr', 'mr'],
2382
            ['ms', 'ms'],
2383
            ['ms-my', 'ms-my'],
2384
            ['my', 'my'],
2385
            ['nb', 'nb'],
2386
            ['ne', 'ne'],
2387
            ['nl-be', 'nl-be'],
2388
            ['nl', 'nl'],
2389
            ['nl', 'nl-nl'],
2390
            ['nn', 'nn'],
2391
            ['pa-in', 'pa-in'],
2392
            ['pl', 'pl'],
2393
            ['pt-br', 'pt-br'],
2394
            ['pt', 'pt'],
2395
            ['ro', 'ro'],
2396
            ['ru', 'ru'],
2397
            ['se', 'se'],
2398
            ['si', 'si'],
2399
            ['sk', 'sk'],
2400
            ['sl', 'sl'],
2401
            ['sq', 'sq'],
2402
            ['sr-cyrl', 'sr-cyrl'],
2403
            ['sr', 'sr'],
2404
            ['ss', 'ss'],
2405
            ['sv', 'sv'],
2406
            ['sw', 'sw'],
2407
            ['ta', 'ta'],
2408
            ['te', 'te'],
2409
            ['tet', 'tet'],
2410
            ['th', 'th'],
2411
            ['tlh', 'tlh'],
2412
            ['tl-ph', 'tl-ph'],
2413
            ['tr', 'tr'],
2414
            ['tzl', 'tzl'],
2415
            ['tzm', 'tzm'],
2416
            ['tzm-latn', 'tzm-latn'],
2417
            ['uk', 'uk'],
2418
            ['uz', 'uz'],
2419
            ['vi', 'vi'],
2420
            ['x-pseudo', 'x-pseudo'],
2421
            ['yo', 'yo'],
2422
            ['zh-cn', 'zh-cn'],
2423
            ['zh-hk', 'zh-hk'],
2424
            ['zh-tw', 'zh-tw'],
2425
        ];
2426
    }
2427
2428
    /**
2429
     * @dataProvider momentLocalesProvider
2430
     */
2431
    public function testCanonicalizedLocaleForMoment($expected, $original): void
2432
    {
2433
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForMoment($this->mockExtensionContext($original)));
2434
    }
2435
2436
    /**
2437
     * This method generates url part for Twig layout.
2438
     *
2439
     * @param array $url
2440
     *
2441
     * @return string
2442
     */
2443
    private function buildTwigLikeUrl($url)
2444
    {
2445
        return htmlspecialchars(http_build_query($url, '', '&', PHP_QUERY_RFC3986));
2446
    }
2447
2448
    private function getMethodAsPublic($privateMethod)
2449
    {
2450
        $reflection = new \ReflectionMethod('Sonata\AdminBundle\Twig\Extension\SonataAdminExtension', $privateMethod);
2451
        $reflection->setAccessible(true);
2452
2453
        return $reflection;
2454
    }
2455
2456
    private function removeExtraWhitespace($string)
2457
    {
2458
        return trim(preg_replace(
2459
            '/\s+/',
2460
            ' ',
2461
            $string
2462
        ));
2463
    }
2464
2465
    private function mockExtensionContext($locale)
2466
    {
2467
        $request = $this->createMock(Request::class);
2468
        $request->method('getLocale')->willReturn($locale);
2469
        $appVariable = $this->createMock(AppVariable::class);
2470
        $appVariable->method('getRequest')->willReturn($request);
2471
2472
        return ['app' => $appVariable];
2473
    }
2474
}
2475