Completed
Pull Request — master (#5032)
by Grégoire
03:41
created

SonataAdminExtensionTest::testOutput()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 57
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 57
rs 9.6818
c 0
b 0
f 0
cc 1
eloc 35
nc 1
nop 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A SonataAdminExtensionTest::testRenderRelationElementNoObject() 0 4 1
B SonataAdminExtensionTest::testRenderWithDebug() 0 39 1

How to fix   Long Method   

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
     * @dataProvider getRenderListElementTests
254
     */
255
    public function testRenderListElement($expected, $type, $value, array $options): void
256
    {
257
        $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...
258
            ->method('getPersistentParameters')
259
            ->will($this->returnValue(['context' => 'foo']));
260
261
        $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...
262
            ->method('hasAccess')
263
            ->will($this->returnValue(true));
264
265
        $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...
266
267
        $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...
268
            ->method('getValue')
269
            ->will($this->returnValue($value));
270
271
        $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...
272
            ->method('getType')
273
            ->will($this->returnValue($type));
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('getOptions')
277
            ->will($this->returnValue($options));
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('getOption')
281
            ->will($this->returnCallback(function ($name, $default = null) use ($options) {
282
                return $options[$name] ?? $default;
283
            }));
284
285
        $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...
286
            ->method('getTemplate')
287
            ->will($this->returnCallback(function () use ($type) {
288
                switch ($type) {
289
                    case 'string':
290
                        return '@SonataAdmin/CRUD/list_string.html.twig';
291
                    case 'boolean':
292
                        return '@SonataAdmin/CRUD/list_boolean.html.twig';
293
                    case 'datetime':
294
                        return '@SonataAdmin/CRUD/list_datetime.html.twig';
295
                    case 'date':
296
                        return '@SonataAdmin/CRUD/list_date.html.twig';
297
                    case 'time':
298
                        return '@SonataAdmin/CRUD/list_time.html.twig';
299
                    case 'currency':
300
                        return '@SonataAdmin/CRUD/list_currency.html.twig';
301
                    case 'percent':
302
                        return '@SonataAdmin/CRUD/list_percent.html.twig';
303
                    case 'email':
304
                        return '@SonataAdmin/CRUD/list_email.html.twig';
305
                    case 'choice':
306
                        return '@SonataAdmin/CRUD/list_choice.html.twig';
307
                    case 'array':
308
                        return '@SonataAdmin/CRUD/list_array.html.twig';
309
                    case 'trans':
310
                        return '@SonataAdmin/CRUD/list_trans.html.twig';
311
                    case 'url':
312
                        return '@SonataAdmin/CRUD/list_url.html.twig';
313
                    case 'html':
314
                        return '@SonataAdmin/CRUD/list_html.html.twig';
315
                    case 'nonexistent':
316
                        // template doesn't exist
317
                        return '@SonataAdmin/CRUD/list_nonexistent_template.html.twig';
318
                    default:
319
                        return false;
320
                }
321
            }));
322
323
        $this->assertSame(
324
            $this->removeExtraWhitespace($expected),
325
            $this->removeExtraWhitespace($this->twigExtension->renderListElement(
326
                $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...
327
                $this->object,
328
                $this->fieldDescription
329
            ))
330
        );
331
    }
332
333
    public function getRenderListElementTests()
334
    {
335
        return [
336
            [
337
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> Example </td>',
338
                'string',
339
                'Example',
340
                [],
341
            ],
342
            [
343
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> </td>',
344
                'string',
345
                null,
346
                [],
347
            ],
348
            [
349
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> Example </td>',
350
                'text',
351
                'Example',
352
                [],
353
            ],
354
            [
355
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> </td>',
356
                'text',
357
                null,
358
                [],
359
            ],
360
            [
361
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> Example </td>',
362
                'textarea',
363
                'Example',
364
                [],
365
            ],
366
            [
367
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> </td>',
368
                'textarea',
369
                null,
370
                [],
371
            ],
372
            'datetime field' => [
373
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
374
                    December 24, 2013 10:11
375
                </td>',
376
                'datetime',
377
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
378
                [],
379
            ],
380
            [
381
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
382
                    December 24, 2013 18:11
383
                </td>',
384
                'datetime',
385
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
386
                ['timezone' => 'Asia/Hong_Kong'],
387
            ],
388
            [
389
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
390
                'datetime',
391
                null,
392
                [],
393
            ],
394
            [
395
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
396
                    24.12.2013 10:11:12
397
                </td>',
398
                'datetime',
399
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
400
                ['format' => 'd.m.Y H:i:s'],
401
            ],
402
            [
403
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
404
                'datetime',
405
                null,
406
                ['format' => 'd.m.Y H:i:s'],
407
            ],
408
            [
409
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
410
                    24.12.2013 18:11:12
411
                </td>',
412
                'datetime',
413
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
414
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
415
            ],
416
            [
417
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
418
                'datetime',
419
                null,
420
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
421
            ],
422
            [
423
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> December 24, 2013 </td>',
424
                'date',
425
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
426
                [],
427
            ],
428
            [
429
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
430
                'date',
431
                null,
432
                [],
433
            ],
434
            [
435
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> 24.12.2013 </td>',
436
                'date',
437
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
438
                ['format' => 'd.m.Y'],
439
            ],
440
            [
441
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
442
                'date',
443
                null,
444
                ['format' => 'd.m.Y'],
445
            ],
446
            [
447
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> 10:11:12 </td>',
448
                'time',
449
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
450
                [],
451
            ],
452
            [
453
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> &nbsp; </td>',
454
                'time',
455
                null,
456
                [],
457
            ],
458
            [
459
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> 10.746135 </td>',
460
                'number', 10.746135,
461
                [],
462
            ],
463
            [
464
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> </td>',
465
                'number',
466
                null,
467
                [],
468
            ],
469
            [
470
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> 5678 </td>',
471
                'integer',
472
                5678,
473
                [],
474
            ],
475
            [
476
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> </td>',
477
                'integer',
478
                null,
479
                [],
480
            ],
481
            [
482
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 1074.6135 % </td>',
483
                'percent',
484
                10.746135,
485
                [],
486
            ],
487
            [
488
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 0 % </td>',
489
                'percent',
490
                null,
491
                [],
492
            ],
493
            [
494
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> EUR 10.746135 </td>',
495
                'currency',
496
                10.746135,
497
                ['currency' => 'EUR'],
498
            ],
499
            [
500
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
501
                'currency',
502
                null,
503
                ['currency' => 'EUR'],
504
            ],
505
            [
506
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> GBP 51.23456 </td>',
507
                'currency',
508
                51.23456,
509
                ['currency' => 'GBP'],
510
            ],
511
            [
512
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
513
                'currency',
514
                null,
515
                ['currency' => 'GBP'],
516
            ],
517
            [
518
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> &nbsp; </td>',
519
                'email',
520
                null,
521
                [],
522
            ],
523
            [
524
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> <a href="mailto:[email protected]">[email protected]</a> </td>',
525
                'email',
526
                '[email protected]',
527
                [],
528
            ],
529
            [
530
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
531
                    <a href="mailto:[email protected]">[email protected]</a> </td>',
532
                'email',
533
                '[email protected]',
534
                ['as_string' => false],
535
            ],
536
            [
537
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
538
                'email',
539
                '[email protected]',
540
                ['as_string' => true],
541
            ],
542
            [
543
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
544
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a>  </td>',
545
                'email',
546
                '[email protected]',
547
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
548
            ],
549
            [
550
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
551
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a>  </td>',
552
                'email',
553
                '[email protected]',
554
                ['subject' => 'Main Theme'],
555
            ],
556
            [
557
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
558
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a>  </td>',
559
                'email',
560
                '[email protected]',
561
                ['body' => 'Message Body'],
562
            ],
563
            [
564
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
565
                'email',
566
                '[email protected]',
567
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
568
            ],
569
            [
570
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
571
                'email',
572
                '[email protected]',
573
                ['as_string' => true, 'body' => 'Message Body'],
574
            ],
575
            [
576
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
577
                'email',
578
                '[email protected]',
579
                ['as_string' => true, 'subject' => 'Main Theme'],
580
            ],
581
            [
582
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345">
583
                    [1 => First] [2 => Second]
584
                </td>',
585
                'array',
586
                [1 => 'First', 2 => 'Second'],
587
                [],
588
            ],
589
            [
590
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345"> </td>',
591
                'array',
592
                null,
593
                [],
594
            ],
595
            [
596
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
597
                    <span class="label label-success">yes</span>
598
                </td>',
599
                'boolean',
600
                true,
601
                ['editable' => false],
602
            ],
603
            [
604
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
605
                    <span class="label label-danger">no</span>
606
                </td>',
607
                'boolean',
608
                false,
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
                null,
617
                ['editable' => false],
618
            ],
619
            [
620
                <<<'EOT'
621
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
622
    <span
623
        class="x-editable"
624
        data-type="select"
625
        data-value="1"
626
        data-title="Data"
627
        data-pk="12345"
628
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
629
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
630
    >
631
        <span class="label label-success">yes</span>
632
    </span>
633
</td>
634
EOT
635
            ,
636
                'boolean',
637
                true,
638
                ['editable' => true],
639
            ],
640
            [
641
                <<<'EOT'
642
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
643
    <span
644
        class="x-editable"
645
        data-type="select"
646
        data-value="0"
647
        data-title="Data"
648
        data-pk="12345"
649
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
650
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
651
    >
652
    <span class="label label-danger">no</span> </span>
653
</td>
654
EOT
655
                ,
656
                'boolean',
657
                false,
658
                ['editable' => true],
659
            ],
660
            [
661
                <<<'EOT'
662
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
663
    <span
664
        class="x-editable"
665
        data-type="select"
666
        data-value="0"
667
        data-title="Data"
668
        data-pk="12345"
669
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
670
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]" >
671
        <span class="label label-danger">no</span> </span>
672
</td>
673
EOT
674
                ,
675
                'boolean',
676
                null,
677
                ['editable' => true],
678
            ],
679
            [
680
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
681
                'trans',
682
                'action_delete',
683
                ['catalogue' => 'SonataAdminBundle'],
684
            ],
685
            [
686
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> </td>',
687
                'trans',
688
                null,
689
                ['catalogue' => 'SonataAdminBundle'],
690
            ],
691
            [
692
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
693
                'trans',
694
                'action_delete',
695
                ['format' => '%s', 'catalogue' => 'SonataAdminBundle'],
696
            ],
697
            [
698
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
699
                action.action_delete
700
                </td>',
701
                'trans',
702
                'action_delete',
703
                ['format' => 'action.%s'],
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', 'catalogue' => 'SonataAdminBundle'],
712
            ],
713
            [
714
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
715
                'choice',
716
                'Status1',
717
                [],
718
            ],
719
            [
720
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
721
                'choice',
722
                ['Status1'],
723
                ['choices' => [], 'multiple' => true],
724
            ],
725
            [
726
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 </td>',
727
                'choice',
728
                'Status1',
729
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
730
            ],
731
            [
732
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
733
                'choice',
734
                null,
735
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
736
            ],
737
            [
738
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
739
                NoValidKeyInChoices
740
                </td>',
741
                'choice',
742
                'NoValidKeyInChoices',
743
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
744
            ],
745
            [
746
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete </td>',
747
                'choice',
748
                'Foo',
749
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
750
                    'Foo' => 'action_delete',
751
                    'Status2' => 'Alias2',
752
                    'Status3' => 'Alias3',
753
                ]],
754
            ],
755
            [
756
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1, Alias3 </td>',
757
                'choice',
758
                ['Status1', 'Status3'],
759
                ['choices' => [
760
                    'Status1' => 'Alias1',
761
                    'Status2' => 'Alias2',
762
                    'Status3' => 'Alias3',
763
                ], 'multiple' => true], ],
764
            [
765
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 | Alias3 </td>',
766
                'choice',
767
                ['Status1', 'Status3'],
768
                ['choices' => [
769
                    'Status1' => 'Alias1',
770
                    'Status2' => 'Alias2',
771
                    'Status3' => 'Alias3',
772
                ], 'multiple' => true, 'delimiter' => ' | '], ],
773
            [
774
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
775
                'choice',
776
                null,
777
                ['choices' => [
778
                    'Status1' => 'Alias1',
779
                    'Status2' => 'Alias2',
780
                    'Status3' => 'Alias3',
781
                ], 'multiple' => true],
782
            ],
783
            [
784
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
785
                NoValidKeyInChoices
786
                </td>',
787
                'choice',
788
                ['NoValidKeyInChoices'],
789
                ['choices' => [
790
                    'Status1' => 'Alias1',
791
                    'Status2' => 'Alias2',
792
                    'Status3' => 'Alias3',
793
                ], 'multiple' => true],
794
            ],
795
            [
796
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
797
                NoValidKeyInChoices, Alias2
798
                </td>',
799
                'choice',
800
                ['NoValidKeyInChoices', 'Status2'],
801
                ['choices' => [
802
                    'Status1' => 'Alias1',
803
                    'Status2' => 'Alias2',
804
                    'Status3' => 'Alias3',
805
                ], 'multiple' => true],
806
            ],
807
            [
808
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete, Alias3 </td>',
809
                'choice',
810
                ['Foo', 'Status3'],
811
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
812
                    'Foo' => 'action_delete',
813
                    'Status2' => 'Alias2',
814
                    'Status3' => 'Alias3',
815
                ], 'multiple' => true],
816
            ],
817
            [
818
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
819
                &lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;
820
            </td>',
821
                'choice',
822
                ['Status1', 'Status3'],
823
                ['choices' => [
824
                    'Status1' => '<b>Alias1</b>',
825
                    'Status2' => '<b>Alias2</b>',
826
                    'Status3' => '<b>Alias3</b>',
827
                ], 'multiple' => true], ],
828
            [
829
                <<<'EOT'
830
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
831
    <span
832
        class="x-editable"
833
        data-type="select"
834
        data-value="Status1"
835
        data-title="Data"
836
        data-pk="12345"
837
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
838
        data-source="[]"
839
    >
840
        Status1
841
    </span>
842
</td>
843
EOT
844
                ,
845
                'choice',
846
                'Status1',
847
                ['editable' => true],
848
            ],
849
            [
850
                <<<'EOT'
851
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
852
    <span
853
        class="x-editable"
854
        data-type="select"
855
        data-value="Status1"
856
        data-title="Data"
857
        data-pk="12345"
858
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
859
        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;}]" >
860
        Alias1 </span>
861
</td>
862
EOT
863
                ,
864
                'choice',
865
                'Status1',
866
                [
867
                    'editable' => true,
868
                    'choices' => [
869
                        'Status1' => 'Alias1',
870
                        'Status2' => 'Alias2',
871
                        'Status3' => 'Alias3',
872
                    ],
873
                ],
874
            ],
875
            [
876
                <<<'EOT'
877
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
878
    <span
879
        class="x-editable"
880
        data-type="select"
881
        data-value=""
882
        data-title="Data"
883
        data-pk="12345"
884
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
885
        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;}]" >
886
887
    </span>
888
</td>
889
EOT
890
                ,
891
                'choice',
892
                null,
893
                [
894
                    'editable' => true,
895
                    'choices' => [
896
                        'Status1' => 'Alias1',
897
                        'Status2' => 'Alias2',
898
                        'Status3' => 'Alias3',
899
                    ],
900
                ],
901
            ],
902
            [
903
                <<<'EOT'
904
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
905
    <span
906
        class="x-editable"
907
        data-type="select"
908
        data-value="NoValidKeyInChoices"
909
        data-title="Data" data-pk="12345"
910
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
911
        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;}]" >
912
        NoValidKeyInChoices
913
    </span>
914
</td>
915
EOT
916
                ,
917
                'choice',
918
                'NoValidKeyInChoices',
919
                [
920
                    'editable' => true,
921
                    'choices' => [
922
                        'Status1' => 'Alias1',
923
                        'Status2' => 'Alias2',
924
                        'Status3' => 'Alias3',
925
                    ],
926
                ],
927
            ],
928
            [
929
                <<<'EOT'
930
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
931
    <span
932
        class="x-editable"
933
        data-type="select"
934
        data-value="Foo"
935
        data-title="Data"
936
        data-pk="12345"
937
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
938
        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;}]" >
939
         Delete
940
    </span>
941
</td>
942
EOT
943
                ,
944
                'choice',
945
                'Foo',
946
                [
947
                    'editable' => true,
948
                    'catalogue' => 'SonataAdminBundle',
949
                    'choices' => [
950
                        'Foo' => 'action_delete',
951
                        'Status2' => 'Alias2',
952
                        'Status3' => 'Alias3',
953
                    ],
954
                ],
955
            ],
956
            [
957
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
958
                'url',
959
                null,
960
                [],
961
            ],
962
            [
963
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
964
                'url',
965
                null,
966
                ['url' => 'http://example.com'],
967
            ],
968
            [
969
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
970
                'url',
971
                null,
972
                ['route' => ['name' => 'sonata_admin_foo']],
973
            ],
974
            [
975
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
976
                <a href="http://example.com">http://example.com</a>
977
                </td>',
978
                'url',
979
                'http://example.com',
980
                [],
981
            ],
982
            [
983
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
984
                <a href="https://example.com">https://example.com</a>
985
                </td>',
986
                'url',
987
                'https://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" target="_blank">https://example.com</a>
993
                </td>',
994
                'url',
995
                'https://example.com',
996
                ['attributes' => ['target' => '_blank']],
997
            ],
998
            [
999
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1000
                <a href="https://example.com" target="_blank" class="fooLink">https://example.com</a>
1001
                </td>',
1002
                'url',
1003
                'https://example.com',
1004
                ['attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1005
            ],
1006
            [
1007
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1008
                <a href="http://example.com">example.com</a>
1009
                </td>',
1010
                'url',
1011
                'http://example.com',
1012
                ['hide_protocol' => true],
1013
            ],
1014
            [
1015
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1016
                <a href="https://example.com">example.com</a>
1017
                </td>',
1018
                'url',
1019
                'https://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="http://example.com">http://example.com</a>
1025
                </td>',
1026
                'url',
1027
                'http://example.com',
1028
                ['hide_protocol' => false],
1029
            ],
1030
            [
1031
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1032
                <a href="https://example.com">https://example.com</a>
1033
                </td>',
1034
                'url',
1035
                'https://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="http://example.com">Foo</a>
1041
                </td>',
1042
                'url',
1043
                'Foo',
1044
                ['url' => 'http://example.com'],
1045
            ],
1046
            [
1047
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1048
                <a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a>
1049
                </td>',
1050
                'url',
1051
                '<b>Foo</b>',
1052
                ['url' => 'http://example.com'],
1053
            ],
1054
            [
1055
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1056
                <a href="/foo">Foo</a>
1057
                </td>',
1058
                'url',
1059
                'Foo',
1060
                ['route' => ['name' => 'sonata_admin_foo']],
1061
            ],
1062
            [
1063
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1064
                <a href="http://localhost/foo">Foo</a>
1065
                </td>',
1066
                'url',
1067
                'Foo',
1068
                ['route' => ['name' => 'sonata_admin_foo', 'absolute' => true]],
1069
            ],
1070
            [
1071
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1072
                <a href="/foo">foo/bar?a=b&amp;c=123456789</a>
1073
                </td>',
1074
                'url',
1075
                'http://foo/bar?a=b&c=123456789',
1076
                ['route' => ['name' => 'sonata_admin_foo'],
1077
                'hide_protocol' => true, ],
1078
            ],
1079
            [
1080
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1081
                <a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a>
1082
                </td>',
1083
                'url',
1084
                'http://foo/bar?a=b&c=123456789',
1085
                [
1086
                    'route' => ['name' => 'sonata_admin_foo', 'absolute' => true],
1087
                    'hide_protocol' => true,
1088
                ],
1089
            ],
1090
            [
1091
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1092
                <a href="/foo/abcd/efgh?param3=ijkl">Foo</a>
1093
                </td>',
1094
                'url',
1095
                'Foo',
1096
                [
1097
                    'route' => ['name' => 'sonata_admin_foo_param',
1098
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1099
                ],
1100
            ],
1101
            [
1102
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1103
                <a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a>
1104
                </td>',
1105
                'url',
1106
                'Foo',
1107
                [
1108
                    'route' => ['name' => 'sonata_admin_foo_param',
1109
                    'absolute' => true,
1110
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1111
                ],
1112
            ],
1113
            [
1114
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1115
                <a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1116
                </td>',
1117
                'url',
1118
                'Foo',
1119
                [
1120
                    'route' => ['name' => 'sonata_admin_foo_object',
1121
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1122
                    'identifier_parameter_name' => 'barId', ],
1123
                ],
1124
            ],
1125
            [
1126
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1127
                <a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1128
                </td>',
1129
                'url',
1130
                'Foo',
1131
                [
1132
                    'route' => ['name' => 'sonata_admin_foo_object',
1133
                    'absolute' => true,
1134
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1135
                    'identifier_parameter_name' => 'barId', ],
1136
                ],
1137
            ],
1138
            [
1139
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1140
                <p><strong>Creating a Template for the Field</strong> and form</p>
1141
                </td>',
1142
                'html',
1143
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1144
                [],
1145
            ],
1146
            [
1147
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1148
                Creating a Template for the Field and form
1149
                </td>',
1150
                'html',
1151
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1152
                ['strip' => true],
1153
            ],
1154
            [
1155
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1156
                Creating a Template for the Fi...
1157
                </td>',
1158
                'html',
1159
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1160
                ['truncate' => true],
1161
            ],
1162
            [
1163
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345"> Creating a... </td>',
1164
                'html',
1165
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1166
                ['truncate' => ['length' => 10]],
1167
            ],
1168
            [
1169
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1170
                Creating a Template for the Field...
1171
                </td>',
1172
                'html',
1173
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1174
                ['truncate' => ['preserve' => true]],
1175
            ],
1176
            [
1177
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1178
                Creating a Template for the Fi etc.
1179
                </td>',
1180
                'html',
1181
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1182
                ['truncate' => ['separator' => ' etc.']],
1183
            ],
1184
            [
1185
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1186
                Creating a Template for[...]
1187
                </td>',
1188
                'html',
1189
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1190
                [
1191
                    'truncate' => [
1192
                        'length' => 20,
1193
                        'preserve' => true,
1194
                        'separator' => '[...]',
1195
                    ],
1196
                ],
1197
            ],
1198
1199
            [
1200
                <<<'EOT'
1201
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1202
<div
1203
    class="sonata-readmore"
1204
    data-readmore-height="40"
1205
    data-readmore-more="Read more"
1206
    data-readmore-less="Close">A very long string</div>
1207
</td>
1208
EOT
1209
                ,
1210
                'text',
1211
                'A very long string',
1212
                [
1213
                    'collapse' => true,
1214
                ],
1215
            ],
1216
            [
1217
                <<<'EOT'
1218
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1219
<div
1220
    class="sonata-readmore"
1221
    data-readmore-height="10"
1222
    data-readmore-more="More"
1223
    data-readmore-less="Less">A very long string</div>
1224
</td>
1225
EOT
1226
                ,
1227
                'text',
1228
                'A very long string',
1229
                [
1230
                    'collapse' => [
1231
                        'height' => 10,
1232
                        'more' => 'More',
1233
                        'less' => 'Less',
1234
                    ],
1235
                ],
1236
            ],
1237
        ];
1238
    }
1239
1240
    /**
1241
     * @dataProvider getRenderViewElementTests
1242
     */
1243
    public function testRenderViewElement($expected, $type, $value, array $options): void
1244
    {
1245
        $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...
1246
            ->method('getTemplate')
1247
            ->will($this->returnValue('@SonataAdmin/CRUD/base_show_field.html.twig'));
1248
1249
        $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...
1250
            ->method('getValue')
1251
            ->will($this->returnCallback(function () use ($value) {
1252
                if ($value instanceof NoValueException) {
1253
                    throw  $value;
1254
                }
1255
1256
                return $value;
1257
            }));
1258
1259
        $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...
1260
            ->method('getType')
1261
            ->will($this->returnValue($type));
1262
1263
        $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...
1264
            ->method('getOptions')
1265
            ->will($this->returnValue($options));
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('getTemplate')
1269
            ->will($this->returnCallback(function () use ($type) {
1270
                switch ($type) {
1271
                    case 'boolean':
1272
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
1273
                    case 'datetime':
1274
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
1275
                    case 'date':
1276
                        return '@SonataAdmin/CRUD/show_date.html.twig';
1277
                    case 'time':
1278
                        return '@SonataAdmin/CRUD/show_time.html.twig';
1279
                    case 'currency':
1280
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
1281
                    case 'percent':
1282
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
1283
                    case 'email':
1284
                        return '@SonataAdmin/CRUD/show_email.html.twig';
1285
                    case 'choice':
1286
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
1287
                    case 'array':
1288
                        return '@SonataAdmin/CRUD/show_array.html.twig';
1289
                    case 'trans':
1290
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
1291
                    case 'url':
1292
                        return '@SonataAdmin/CRUD/show_url.html.twig';
1293
                    case 'html':
1294
                        return '@SonataAdmin/CRUD/show_html.html.twig';
1295
                    default:
1296
                        return false;
1297
                }
1298
            }));
1299
1300
        $this->assertSame(
1301
                $this->removeExtraWhitespace($expected),
1302
                $this->removeExtraWhitespace(
1303
                    $this->twigExtension->renderViewElement(
1304
                        $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...
1305
                        $this->fieldDescription,
1306
                        $this->object
1307
                    )
1308
                )
1309
            );
1310
    }
1311
1312
    public function getRenderViewElementTests()
1313
    {
1314
        return [
1315
            ['<th>Data</th> <td>Example</td>', 'string', 'Example', ['safe' => false]],
1316
            ['<th>Data</th> <td>Example</td>', 'text', 'Example', ['safe' => false]],
1317
            ['<th>Data</th> <td>Example</td>', 'textarea', 'Example', ['safe' => false]],
1318
            [
1319
                '<th>Data</th> <td>December 24, 2013 10:11</td>',
1320
                'datetime',
1321
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), [],
1322
            ],
1323
            [
1324
                '<th>Data</th> <td>24.12.2013 10:11:12</td>',
1325
                'datetime',
1326
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1327
                ['format' => 'd.m.Y H:i:s'],
1328
            ],
1329
            [
1330
                '<th>Data</th> <td>December 24, 2013</td>',
1331
                'date',
1332
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1333
                [],
1334
            ],
1335
            [
1336
                '<th>Data</th> <td>24.12.2013</td>',
1337
                'date',
1338
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1339
                ['format' => 'd.m.Y'],
1340
            ],
1341
            [
1342
                '<th>Data</th> <td>10:11:12</td>',
1343
                'time',
1344
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1345
                [],
1346
            ],
1347
            ['<th>Data</th> <td>10.746135</td>', 'number', 10.746135, ['safe' => false]],
1348
            ['<th>Data</th> <td>5678</td>', 'integer', 5678, ['safe' => false]],
1349
            ['<th>Data</th> <td> 1074.6135 % </td>', 'percent', 10.746135, []],
1350
            ['<th>Data</th> <td> EUR 10.746135 </td>', 'currency', 10.746135, ['currency' => 'EUR']],
1351
            ['<th>Data</th> <td> GBP 51.23456 </td>', 'currency', 51.23456, ['currency' => 'GBP']],
1352
            [
1353
                '<th>Data</th> <td> [1 => First] <br> [2 => Second] </td>',
1354
                'array',
1355
                [1 => 'First', 2 => 'Second'],
1356
                ['safe' => false],
1357
            ],
1358
            [
1359
                '<th>Data</th> <td> [1 => First] [2 => Second] </td>',
1360
                'array',
1361
                [1 => 'First', 2 => 'Second'],
1362
                ['safe' => false, 'inline' => true],
1363
            ],
1364
            [
1365
                '<th>Data</th> <td><span class="label label-success">yes</span></td>',
1366
                'boolean',
1367
                true,
1368
                [],
1369
            ],
1370
            [
1371
                '<th>Data</th> <td><span class="label label-danger">yes</span></td>',
1372
                'boolean',
1373
                true,
1374
                ['inverse' => true],
1375
            ],
1376
            ['<th>Data</th> <td><span class="label label-danger">no</span></td>', 'boolean', false, []],
1377
            [
1378
                '<th>Data</th> <td><span class="label label-success">no</span></td>',
1379
                'boolean',
1380
                false,
1381
                ['inverse' => true],
1382
            ],
1383
            [
1384
                '<th>Data</th> <td> Delete </td>',
1385
                'trans',
1386
                'action_delete',
1387
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1388
            ],
1389
            ['<th>Data</th> <td>Status1</td>', 'choice', 'Status1', ['safe' => false]],
1390
            [
1391
                '<th>Data</th> <td>Alias1</td>',
1392
                'choice',
1393
                'Status1',
1394
                ['safe' => false, 'choices' => [
1395
                    'Status1' => 'Alias1',
1396
                    'Status2' => 'Alias2',
1397
                    'Status3' => 'Alias3',
1398
                ]],
1399
            ],
1400
            [
1401
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1402
                'choice',
1403
                'NoValidKeyInChoices',
1404
                ['safe' => false, 'choices' => [
1405
                    'Status1' => 'Alias1',
1406
                    'Status2' => 'Alias2',
1407
                    'Status3' => 'Alias3',
1408
                ]],
1409
            ],
1410
            [
1411
                '<th>Data</th> <td>Delete</td>',
1412
                'choice',
1413
                'Foo',
1414
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1415
                    'Foo' => 'action_delete',
1416
                    'Status2' => 'Alias2',
1417
                    'Status3' => 'Alias3',
1418
                ]],
1419
            ],
1420
            [
1421
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1422
                'choice',
1423
                ['NoValidKeyInChoices'],
1424
                ['safe' => false, 'choices' => [
1425
                    'Status1' => 'Alias1',
1426
                    'Status2' => 'Alias2',
1427
                    'Status3' => 'Alias3',
1428
                ], 'multiple' => true],
1429
            ],
1430
            [
1431
                '<th>Data</th> <td>NoValidKeyInChoices, Alias2</td>',
1432
                'choice',
1433
                ['NoValidKeyInChoices', 'Status2'],
1434
                ['safe' => false, 'choices' => [
1435
                    'Status1' => 'Alias1',
1436
                    'Status2' => 'Alias2',
1437
                    'Status3' => 'Alias3',
1438
                ], 'multiple' => true],
1439
            ],
1440
            [
1441
                '<th>Data</th> <td>Alias1, Alias3</td>',
1442
                'choice',
1443
                ['Status1', 'Status3'],
1444
                ['safe' => false, 'choices' => [
1445
                    'Status1' => 'Alias1',
1446
                    'Status2' => 'Alias2',
1447
                    'Status3' => 'Alias3',
1448
                ], 'multiple' => true],
1449
            ],
1450
            [
1451
                '<th>Data</th> <td>Alias1 | Alias3</td>',
1452
                'choice',
1453
                ['Status1', 'Status3'], ['safe' => false, 'choices' => [
1454
                    'Status1' => 'Alias1',
1455
                    'Status2' => 'Alias2',
1456
                    'Status3' => 'Alias3',
1457
                ], 'multiple' => true, 'delimiter' => ' | '],
1458
            ],
1459
            [
1460
                '<th>Data</th> <td>Delete, Alias3</td>',
1461
                'choice',
1462
                ['Foo', 'Status3'],
1463
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1464
                    'Foo' => 'action_delete',
1465
                    'Status2' => 'Alias2',
1466
                    'Status3' => 'Alias3',
1467
                ], 'multiple' => true],
1468
            ],
1469
            [
1470
                '<th>Data</th> <td><b>Alias1</b>, <b>Alias3</b></td>',
1471
                'choice',
1472
                ['Status1', 'Status3'],
1473
                ['safe' => true, 'choices' => [
1474
                    'Status1' => '<b>Alias1</b>',
1475
                    'Status2' => '<b>Alias2</b>',
1476
                    'Status3' => '<b>Alias3</b>',
1477
                ], 'multiple' => true],
1478
            ],
1479
            [
1480
                '<th>Data</th> <td>&lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;</td>',
1481
                'choice',
1482
                ['Status1', 'Status3'],
1483
                ['safe' => false, 'choices' => [
1484
                    'Status1' => '<b>Alias1</b>',
1485
                    'Status2' => '<b>Alias2</b>',
1486
                    'Status3' => '<b>Alias3</b>',
1487
                ], 'multiple' => true],
1488
            ],
1489
            [
1490
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1491
                'url',
1492
                'http://example.com',
1493
                ['safe' => false],
1494
            ],
1495
            [
1496
                '<th>Data</th> <td><a href="http://example.com" target="_blank">http://example.com</a></td>',
1497
                'url',
1498
                'http://example.com',
1499
                ['safe' => false, 'attributes' => ['target' => '_blank']],
1500
            ],
1501
            [
1502
                '<th>Data</th> <td><a href="http://example.com" target="_blank" class="fooLink">http://example.com</a></td>',
1503
                'url',
1504
                'http://example.com',
1505
                ['safe' => false, 'attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1506
            ],
1507
            [
1508
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1509
                'url',
1510
                'https://example.com',
1511
                ['safe' => false],
1512
            ],
1513
            [
1514
                '<th>Data</th> <td><a href="http://example.com">example.com</a></td>',
1515
                'url',
1516
                'http://example.com',
1517
                ['safe' => false, 'hide_protocol' => true],
1518
            ],
1519
            [
1520
                '<th>Data</th> <td><a href="https://example.com">example.com</a></td>',
1521
                'url',
1522
                'https://example.com',
1523
                ['safe' => false, 'hide_protocol' => true],
1524
            ],
1525
            [
1526
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1527
                'url',
1528
                'http://example.com',
1529
                ['safe' => false, 'hide_protocol' => false],
1530
            ],
1531
            [
1532
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1533
                'url',
1534
                'https://example.com',
1535
                ['safe' => false,
1536
                'hide_protocol' => false, ],
1537
            ],
1538
            [
1539
                '<th>Data</th> <td><a href="http://example.com">Foo</a></td>',
1540
                'url',
1541
                'Foo',
1542
                ['safe' => false, 'url' => 'http://example.com'],
1543
            ],
1544
            [
1545
                '<th>Data</th> <td><a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a></td>',
1546
                'url',
1547
                '<b>Foo</b>',
1548
                ['safe' => false, 'url' => 'http://example.com'],
1549
            ],
1550
            [
1551
                '<th>Data</th> <td><a href="http://example.com"><b>Foo</b></a></td>',
1552
                'url',
1553
                '<b>Foo</b>',
1554
                ['safe' => true, 'url' => 'http://example.com'],
1555
            ],
1556
            [
1557
                '<th>Data</th> <td><a href="/foo">Foo</a></td>',
1558
                'url',
1559
                'Foo',
1560
                ['safe' => false, 'route' => ['name' => 'sonata_admin_foo']],
1561
            ],
1562
            [
1563
                '<th>Data</th> <td><a href="http://localhost/foo">Foo</a></td>',
1564
                'url',
1565
                'Foo',
1566
                ['safe' => false, 'route' => [
1567
                    'name' => 'sonata_admin_foo',
1568
                    'absolute' => true,
1569
                ]],
1570
            ],
1571
            [
1572
                '<th>Data</th> <td><a href="/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1573
                'url',
1574
                'http://foo/bar?a=b&c=123456789',
1575
                [
1576
                    'safe' => false,
1577
                    'route' => ['name' => 'sonata_admin_foo'],
1578
                    'hide_protocol' => true,
1579
                ],
1580
            ],
1581
            [
1582
                '<th>Data</th> <td><a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1583
                'url',
1584
                'http://foo/bar?a=b&c=123456789',
1585
                ['safe' => false, 'route' => [
1586
                    'name' => 'sonata_admin_foo',
1587
                    'absolute' => true,
1588
                ], 'hide_protocol' => true],
1589
            ],
1590
            [
1591
                '<th>Data</th> <td><a href="/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1592
                'url',
1593
                'Foo',
1594
                ['safe' => false, 'route' => [
1595
                    'name' => 'sonata_admin_foo_param',
1596
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1597
                ]],
1598
            ],
1599
            [
1600
                '<th>Data</th> <td><a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1601
                'url',
1602
                'Foo',
1603
                ['safe' => false, 'route' => [
1604
                    'name' => 'sonata_admin_foo_param',
1605
                    'absolute' => true,
1606
                    'parameters' => [
1607
                        'param1' => 'abcd',
1608
                        'param2' => 'efgh',
1609
                        'param3' => 'ijkl',
1610
                    ],
1611
                ]],
1612
            ],
1613
            [
1614
                '<th>Data</th> <td><a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1615
                'url',
1616
                'Foo',
1617
                ['safe' => false, 'route' => [
1618
                    'name' => 'sonata_admin_foo_object',
1619
                    'parameters' => [
1620
                        'param1' => 'abcd',
1621
                        'param2' => 'efgh',
1622
                        'param3' => 'ijkl',
1623
                    ],
1624
                    'identifier_parameter_name' => 'barId',
1625
                ]],
1626
            ],
1627
            [
1628
                '<th>Data</th> <td><a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1629
                'url',
1630
                'Foo',
1631
                ['safe' => false, 'route' => [
1632
                    'name' => 'sonata_admin_foo_object',
1633
                    'absolute' => true,
1634
                    'parameters' => [
1635
                        'param1' => 'abcd',
1636
                        'param2' => 'efgh',
1637
                        'param3' => 'ijkl',
1638
                    ],
1639
                    'identifier_parameter_name' => 'barId',
1640
                ]],
1641
            ],
1642
            [
1643
                '<th>Data</th> <td> &nbsp;</td>',
1644
                'email',
1645
                null,
1646
                [],
1647
            ],
1648
            [
1649
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1650
                'email',
1651
                '[email protected]',
1652
                [],
1653
            ],
1654
            [
1655
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a></td>',
1656
                'email',
1657
                '[email protected]',
1658
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
1659
            ],
1660
            [
1661
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a></td>',
1662
                'email',
1663
                '[email protected]',
1664
                ['subject' => 'Main Theme'],
1665
            ],
1666
            [
1667
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a></td>',
1668
                'email',
1669
                '[email protected]',
1670
                ['body' => 'Message Body'],
1671
            ],
1672
            [
1673
                '<th>Data</th> <td> [email protected]</td>',
1674
                'email',
1675
                '[email protected]',
1676
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
1677
            ],
1678
            [
1679
                '<th>Data</th> <td> [email protected]</td>',
1680
                'email',
1681
                '[email protected]',
1682
                ['as_string' => true, 'subject' => 'Main Theme'],
1683
            ],
1684
            [
1685
                '<th>Data</th> <td> [email protected]</td>',
1686
                'email',
1687
                '[email protected]',
1688
                ['as_string' => true, 'body' => 'Message Body'],
1689
            ],
1690
            [
1691
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1692
                'email',
1693
                '[email protected]',
1694
                ['as_string' => false],
1695
            ],
1696
            [
1697
                '<th>Data</th> <td> [email protected]</td>',
1698
                'email',
1699
                '[email protected]',
1700
                ['as_string' => true],
1701
            ],
1702
            [
1703
                '<th>Data</th> <td><p><strong>Creating a Template for the Field</strong> and form</p> </td>',
1704
                'html',
1705
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1706
                [],
1707
            ],
1708
            [
1709
                '<th>Data</th> <td>Creating a Template for the Field and form </td>',
1710
                'html',
1711
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1712
                ['strip' => true],
1713
            ],
1714
            [
1715
                '<th>Data</th> <td> Creating a Template for the Fi... </td>',
1716
                'html',
1717
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1718
                ['truncate' => true],
1719
            ],
1720
            [
1721
                '<th>Data</th> <td> Creating a... </td>',
1722
                'html',
1723
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1724
                ['truncate' => ['length' => 10]],
1725
            ],
1726
            [
1727
                '<th>Data</th> <td> Creating a Template for the Field... </td>',
1728
                'html',
1729
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1730
                ['truncate' => ['preserve' => true]],
1731
            ],
1732
            [
1733
                '<th>Data</th> <td> Creating a Template for the Fi etc. </td>',
1734
                'html',
1735
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1736
                ['truncate' => ['separator' => ' etc.']],
1737
            ],
1738
            [
1739
                '<th>Data</th> <td> Creating a Template for[...] </td>',
1740
                'html',
1741
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1742
                [
1743
                    'truncate' => [
1744
                        'length' => 20,
1745
                        'preserve' => true,
1746
                        'separator' => '[...]',
1747
                    ],
1748
                ],
1749
            ],
1750
1751
            // NoValueException
1752
            ['<th>Data</th> <td></td>', 'string', new NoValueException(), ['safe' => false]],
1753
            ['<th>Data</th> <td></td>', 'text', new NoValueException(), ['safe' => false]],
1754
            ['<th>Data</th> <td></td>', 'textarea', new NoValueException(), ['safe' => false]],
1755
            ['<th>Data</th> <td>&nbsp;</td>', 'datetime', new NoValueException(), []],
1756
            [
1757
                '<th>Data</th> <td>&nbsp;</td>',
1758
                'datetime',
1759
                new NoValueException(),
1760
                ['format' => 'd.m.Y H:i:s'],
1761
            ],
1762
            ['<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), []],
1763
            ['<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), ['format' => 'd.m.Y']],
1764
            ['<th>Data</th> <td>&nbsp;</td>', 'time', new NoValueException(), []],
1765
            ['<th>Data</th> <td></td>', 'number', new NoValueException(), ['safe' => false]],
1766
            ['<th>Data</th> <td></td>', 'integer', new NoValueException(), ['safe' => false]],
1767
            ['<th>Data</th> <td> 0 % </td>', 'percent', new NoValueException(), []],
1768
            ['<th>Data</th> <td> </td>', 'currency', new NoValueException(), ['currency' => 'EUR']],
1769
            ['<th>Data</th> <td> </td>', 'currency', new NoValueException(), ['currency' => 'GBP']],
1770
            ['<th>Data</th> <td> </td>', 'array', new NoValueException(), ['safe' => false]],
1771
            [
1772
                '<th>Data</th> <td><span class="label label-danger">no</span></td>',
1773
                'boolean',
1774
                new NoValueException(),
1775
                [],
1776
            ],
1777
            [
1778
                '<th>Data</th> <td> </td>',
1779
                'trans',
1780
                new NoValueException(),
1781
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1782
            ],
1783
            [
1784
                '<th>Data</th> <td></td>',
1785
                'choice',
1786
                new NoValueException(),
1787
                ['safe' => false, 'choices' => []],
1788
            ],
1789
            [
1790
                '<th>Data</th> <td></td>',
1791
                'choice',
1792
                new NoValueException(),
1793
                ['safe' => false, 'choices' => [], 'multiple' => true],
1794
            ],
1795
            ['<th>Data</th> <td>&nbsp;</td>', 'url', new NoValueException(), []],
1796
            [
1797
                '<th>Data</th> <td>&nbsp;</td>',
1798
                'url',
1799
                new NoValueException(),
1800
                ['url' => 'http://example.com'],
1801
            ],
1802
            [
1803
                '<th>Data</th> <td>&nbsp;</td>',
1804
                'url',
1805
                new NoValueException(),
1806
                ['route' => ['name' => 'sonata_admin_foo']],
1807
            ],
1808
1809
            [
1810
                <<<'EOT'
1811
<th>Data</th> <td><div
1812
        class="sonata-readmore"
1813
        data-readmore-height="40"
1814
        data-readmore-more="Read more"
1815
        data-readmore-less="Close">
1816
            A very long string
1817
</div></td>
1818
EOT
1819
                ,
1820
                'text',
1821
                ' A very long string ',
1822
                [
1823
                    'collapse' => true,
1824
                    'safe' => false,
1825
                ],
1826
            ],
1827
            [
1828
                <<<'EOT'
1829
<th>Data</th> <td><div
1830
        class="sonata-readmore"
1831
        data-readmore-height="10"
1832
        data-readmore-more="More"
1833
        data-readmore-less="Less">
1834
            A very long string
1835
</div></td>
1836
EOT
1837
                ,
1838
                'text',
1839
                ' A very long string ',
1840
                [
1841
                    'collapse' => [
1842
                        'height' => 10,
1843
                        'more' => 'More',
1844
                        'less' => 'Less',
1845
                    ],
1846
                    'safe' => false,
1847
                ],
1848
            ],
1849
        ];
1850
    }
1851
1852
    public function testGetValueFromFieldDescription(): void
1853
    {
1854
        $object = new \stdClass();
1855
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1856
1857
        $fieldDescription->expects($this->any())
1858
            ->method('getValue')
1859
            ->will($this->returnValue('test123'));
1860
1861
        $this->assertSame(
1862
            'test123',
1863
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1864
                $this->twigExtension,
1865
                $object,
1866
                $fieldDescription
1867
            )
1868
        );
1869
    }
1870
1871
    public function testGetValueFromFieldDescriptionWithRemoveLoopException(): void
1872
    {
1873
        $object = $this->createMock(\ArrayAccess::class);
1874
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1875
1876
        $this->expectException(\RuntimeException::class, 'remove the loop requirement');
1877
1878
        $this->assertSame(
1879
            'anything',
1880
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1881
                $this->twigExtension,
1882
                $object,
1883
                $fieldDescription,
1884
                ['loop' => true]
1885
            )
1886
        );
1887
    }
1888
1889
    public function testGetValueFromFieldDescriptionWithNoValueException(): void
1890
    {
1891
        $object = new \stdClass();
1892
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1893
1894
        $fieldDescription->expects($this->any())
1895
            ->method('getValue')
1896
            ->will($this->returnCallback(function (): void {
1897
                throw new NoValueException();
1898
            }));
1899
1900
        $fieldDescription->expects($this->any())
1901
            ->method('getAssociationAdmin')
1902
            ->will($this->returnValue(null));
1903
1904
        $this->assertNull(
1905
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1906
                $this->twigExtension,
1907
                $object,
1908
                $fieldDescription
1909
            )
1910
        );
1911
    }
1912
1913
    public function testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance(): void
1914
    {
1915
        $object = new \stdClass();
1916
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
1917
1918
        $fieldDescription->expects($this->any())
1919
            ->method('getValue')
1920
            ->will($this->returnCallback(function (): void {
1921
                throw new NoValueException();
1922
            }));
1923
1924
        $fieldDescription->expects($this->any())
1925
            ->method('getAssociationAdmin')
1926
            ->will($this->returnValue($this->admin));
1927
1928
        $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...
1929
            ->method('getNewInstance')
1930
            ->will($this->returnValue('foo'));
1931
1932
        $this->assertSame(
1933
            'foo',
1934
            $this->getMethodAsPublic('getValueFromFieldDescription')->invoke(
1935
                $this->twigExtension,
1936
                $object,
1937
                $fieldDescription
1938
            )
1939
        );
1940
    }
1941
1942
    public function testRenderWithDebug(): void
1943
    {
1944
        $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...
1945
            ->method('getTemplate')
1946
            ->will($this->returnValue('@SonataAdmin/CRUD/base_list_field.html.twig'));
1947
1948
        $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...
1949
            ->method('getFieldName')
1950
            ->will($this->returnValue('fd_name'));
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('getValue')
1954
            ->will($this->returnValue('foo'));
1955
1956
        $parameters = [
1957
            'admin' => $this->admin,
1958
            'value' => 'foo',
1959
            'field_description' => $this->fieldDescription,
1960
            'object' => $this->object,
1961
        ];
1962
1963
        $this->environment->enableDebug();
1964
1965
        $this->assertSame(
1966
            $this->removeExtraWhitespace(<<<'EOT'
1967
<!-- START
1968
    fieldName: fd_name
1969
    template: @SonataAdmin/CRUD/base_list_field.html.twig
1970
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
1971
-->
1972
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
1973
<!-- END - fieldName: fd_name -->
1974
EOT
1975
            ),
1976
            $this->removeExtraWhitespace(
1977
                $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...
1978
            )
1979
        );
1980
    }
1981
1982
    public function testRenderRelationElementNoObject(): void
1983
    {
1984
        $this->assertSame('foo', $this->twigExtension->renderRelationElement('foo', $this->fieldDescription));
1985
    }
1986
1987
    public function testRenderRelationElementToString(): void
1988
    {
1989
        $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...
1990
            ->method('getOption')
1991
            ->will($this->returnCallback(function ($value, $default = null) {
1992
                if ('associated_property' == $value) {
1993
                    return $default;
1994
                }
1995
            }));
1996
1997
        $element = new FooToString();
1998
        $this->assertSame('salut', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
1999
    }
2000
2001
    /**
2002
     * @group legacy
2003
     */
2004
    public function testDeprecatedRelationElementToString(): void
2005
    {
2006
        $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...
2007
            ->method('getOption')
2008
            ->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...
2009
                if ('associated_tostring' == $value) {
2010
                    return '__toString';
2011
                }
2012
            }));
2013
2014
        $element = new FooToString();
2015
        $this->assertSame(
2016
            'salut',
2017
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2018
        );
2019
    }
2020
2021
    /**
2022
     * @group legacy
2023
     */
2024
    public function testRenderRelationElementCustomToString(): void
2025
    {
2026
        $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...
2027
            ->method('getOption')
2028
            ->will($this->returnCallback(function ($value, $default = null) {
2029
                if ('associated_property' == $value) {
2030
                    return $default;
2031
                }
2032
2033
                if ('associated_tostring' == $value) {
2034
                    return 'customToString';
2035
                }
2036
            }));
2037
2038
        $element = $this->getMockBuilder('stdClass')
2039
            ->setMethods(['customToString'])
2040
            ->getMock();
2041
        $element->expects($this->any())
2042
            ->method('customToString')
2043
            ->will($this->returnValue('fooBar'));
2044
2045
        $this->assertSame('fooBar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2046
    }
2047
2048
    /**
2049
     * @group legacy
2050
     */
2051
    public function testRenderRelationElementMethodNotExist(): void
2052
    {
2053
        $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...
2054
            ->method('getOption')
2055
2056
            ->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...
2057
                if ('associated_tostring' == $value) {
2058
                    return 'nonExistedMethod';
2059
                }
2060
            }));
2061
2062
        $element = new \stdClass();
2063
        $this->expectException(\RuntimeException::class, 'You must define an `associated_property` option or create a `stdClass::__toString');
2064
2065
        $this->twigExtension->renderRelationElement($element, $this->fieldDescription);
2066
    }
2067
2068
    public function testRenderRelationElementWithPropertyPath(): void
2069
    {
2070
        $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...
2071
            ->method('getOption')
2072
2073
            ->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...
2074
                if ('associated_property' == $value) {
2075
                    return 'foo';
2076
                }
2077
            }));
2078
2079
        $element = new \stdClass();
2080
        $element->foo = 'bar';
2081
2082
        $this->assertSame('bar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2083
    }
2084
2085
    public function testRenderRelationElementWithClosure(): void
2086
    {
2087
        $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...
2088
            ->method('getOption')
2089
2090
            ->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...
2091
                if ('associated_property' == $value) {
2092
                    return function ($element) {
2093
                        return 'closure '.$element->foo;
2094
                    };
2095
                }
2096
            }));
2097
2098
        $element = new \stdClass();
2099
        $element->foo = 'bar';
2100
2101
        $this->assertSame(
2102
            'closure bar',
2103
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2104
        );
2105
    }
2106
2107
    public function testGetUrlsafeIdentifier(): void
2108
    {
2109
        $entity = new \stdClass();
2110
2111
        // set admin to pool
2112
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
2113
        $this->pool->setAdminClasses(['stdClass' => ['sonata_admin_foo_service']]);
2114
2115
        $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...
2116
            ->method('getUrlsafeIdentifier')
2117
            ->with($this->equalTo($entity))
2118
            ->will($this->returnValue(1234567));
2119
2120
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity));
2121
    }
2122
2123
    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...
2124
    {
2125
        $entity = new \stdClass();
2126
2127
        // set admin to pool
2128
        $this->pool->setAdminServiceIds([
2129
            'sonata_admin_foo_service',
2130
            'sonata_admin_bar_service',
2131
        ]);
2132
        $this->pool->setAdminClasses(['stdClass' => [
2133
            'sonata_admin_foo_service',
2134
            'sonata_admin_bar_service',
2135
        ]]);
2136
2137
        $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...
2138
            ->method('getUrlsafeIdentifier')
2139
            ->with($this->equalTo($entity))
2140
            ->will($this->returnValue(1234567));
2141
2142
        $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...
2143
            ->method('getUrlsafeIdentifier');
2144
2145
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->admin));
2146
    }
2147
2148
    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...
2149
    {
2150
        $entity = new \stdClass();
2151
2152
        // set admin to pool
2153
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service', 'sonata_admin_bar_service']);
2154
        $this->pool->setAdminClasses(['stdClass' => [
2155
            'sonata_admin_foo_service',
2156
            'sonata_admin_bar_service',
2157
        ]]);
2158
2159
        $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...
2160
            ->method('getUrlsafeIdentifier');
2161
2162
        $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...
2163
            ->method('getUrlsafeIdentifier')
2164
            ->with($this->equalTo($entity))
2165
            ->will($this->returnValue(1234567));
2166
2167
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->adminBar));
2168
    }
2169
2170
    public function xEditableChoicesProvider()
2171
    {
2172
        return [
2173
            'needs processing' => [
2174
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2']],
2175
                [
2176
                    ['value' => 'Status1', 'text' => 'Alias1'],
2177
                    ['value' => 'Status2', 'text' => 'Alias2'],
2178
                ],
2179
            ],
2180
            'already processed' => [
2181
                ['choices' => [
2182
                    ['value' => 'Status1', 'text' => 'Alias1'],
2183
                    ['value' => 'Status2', 'text' => 'Alias2'],
2184
                ]],
2185
                [
2186
                    ['value' => 'Status1', 'text' => 'Alias1'],
2187
                    ['value' => 'Status2', 'text' => 'Alias2'],
2188
                ],
2189
            ],
2190
            'not required' => [
2191
                [
2192
                    'required' => false,
2193
                    'choices' => ['' => '', 'Status1' => 'Alias1', 'Status2' => 'Alias2'],
2194
                ],
2195
                [
2196
                    ['value' => '', 'text' => ''],
2197
                    ['value' => 'Status1', 'text' => 'Alias1'],
2198
                    ['value' => 'Status2', 'text' => 'Alias2'],
2199
                ],
2200
            ],
2201
            'not required multiple' => [
2202
                [
2203
                    'required' => false,
2204
                    'multiple' => true,
2205
                    'choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2'],
2206
                ],
2207
                [
2208
                    ['value' => 'Status1', 'text' => 'Alias1'],
2209
                    ['value' => 'Status2', 'text' => 'Alias2'],
2210
                ],
2211
            ],
2212
        ];
2213
    }
2214
2215
    /**
2216
     * @dataProvider xEditablechoicesProvider
2217
     */
2218
    public function testGetXEditableChoicesIsIdempotent(array $options, $expectedChoices): void
2219
    {
2220
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2221
        $fieldDescription->expects($this->any())
2222
            ->method('getOption')
2223
            ->withConsecutive(
2224
                ['choices', []],
2225
                ['catalogue'],
2226
                ['required'],
2227
                ['multiple']
2228
            )
2229
            ->will($this->onConsecutiveCalls(
2230
                $options['choices'],
2231
                'MyCatalogue',
2232
                $options['multiple'] ?? null
2233
            ));
2234
2235
        $this->assertSame($expectedChoices, $this->twigExtension->getXEditableChoices($fieldDescription));
2236
    }
2237
2238
    public function select2LocalesProvider()
2239
    {
2240
        return [
2241
            ['ar', 'ar'],
2242
            ['az', 'az'],
2243
            ['bg', 'bg'],
2244
            ['ca', 'ca'],
2245
            ['cs', 'cs'],
2246
            ['da', 'da'],
2247
            ['de', 'de'],
2248
            ['el', 'el'],
2249
            [null, 'en'],
2250
            ['es', 'es'],
2251
            ['et', 'et'],
2252
            ['eu', 'eu'],
2253
            ['fa', 'fa'],
2254
            ['fi', 'fi'],
2255
            ['fr', 'fr'],
2256
            ['gl', 'gl'],
2257
            ['he', 'he'],
2258
            ['hr', 'hr'],
2259
            ['hu', 'hu'],
2260
            ['id', 'id'],
2261
            ['is', 'is'],
2262
            ['it', 'it'],
2263
            ['ja', 'ja'],
2264
            ['ka', 'ka'],
2265
            ['ko', 'ko'],
2266
            ['lt', 'lt'],
2267
            ['lv', 'lv'],
2268
            ['mk', 'mk'],
2269
            ['ms', 'ms'],
2270
            ['nb', 'nb'],
2271
            ['nl', 'nl'],
2272
            ['pl', 'pl'],
2273
            ['pt-PT', 'pt'],
2274
            ['pt-BR', 'pt-BR'],
2275
            ['pt-PT', 'pt-PT'],
2276
            ['ro', 'ro'],
2277
            ['rs', 'rs'],
2278
            ['ru', 'ru'],
2279
            ['sk', 'sk'],
2280
            ['sv', 'sv'],
2281
            ['th', 'th'],
2282
            ['tr', 'tr'],
2283
            ['ug-CN', 'ug'],
2284
            ['ug-CN', 'ug-CN'],
2285
            ['uk', 'uk'],
2286
            ['vi', 'vi'],
2287
            ['zh-CN', 'zh'],
2288
            ['zh-CN', 'zh-CN'],
2289
            ['zh-TW', 'zh-TW'],
2290
        ];
2291
    }
2292
2293
    /**
2294
     * @dataProvider select2LocalesProvider
2295
     */
2296
    public function testCanonicalizedLocaleForSelect2($expected, $original): void
2297
    {
2298
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForSelect2($this->mockExtensionContext($original)));
2299
    }
2300
2301
    public function momentLocalesProvider()
2302
    {
2303
        return [
2304
            ['af', 'af'],
2305
            ['ar-dz', 'ar-dz'],
2306
            ['ar', 'ar'],
2307
            ['ar-ly', 'ar-ly'],
2308
            ['ar-ma', 'ar-ma'],
2309
            ['ar-sa', 'ar-sa'],
2310
            ['ar-tn', 'ar-tn'],
2311
            ['az', 'az'],
2312
            ['be', 'be'],
2313
            ['bg', 'bg'],
2314
            ['bn', 'bn'],
2315
            ['bo', 'bo'],
2316
            ['br', 'br'],
2317
            ['bs', 'bs'],
2318
            ['ca', 'ca'],
2319
            ['cs', 'cs'],
2320
            ['cv', 'cv'],
2321
            ['cy', 'cy'],
2322
            ['da', 'da'],
2323
            ['de-at', 'de-at'],
2324
            ['de', 'de'],
2325
            ['dv', 'dv'],
2326
            ['el', 'el'],
2327
            [null, 'en'],
2328
            [null, 'en-us'],
2329
            ['en-au', 'en-au'],
2330
            ['en-ca', 'en-ca'],
2331
            ['en-gb', 'en-gb'],
2332
            ['en-ie', 'en-ie'],
2333
            ['en-nz', 'en-nz'],
2334
            ['eo', 'eo'],
2335
            ['es-do', 'es-do'],
2336
            ['es', 'es-ar'],
2337
            ['es', 'es-mx'],
2338
            ['es', 'es'],
2339
            ['et', 'et'],
2340
            ['eu', 'eu'],
2341
            ['fa', 'fa'],
2342
            ['fi', 'fi'],
2343
            ['fo', 'fo'],
2344
            ['fr-ca', 'fr-ca'],
2345
            ['fr-ch', 'fr-ch'],
2346
            ['fr', 'fr'],
2347
            ['fy', 'fy'],
2348
            ['gd', 'gd'],
2349
            ['gl', 'gl'],
2350
            ['he', 'he'],
2351
            ['hi', 'hi'],
2352
            ['hr', 'hr'],
2353
            ['hu', 'hu'],
2354
            ['hy-am', 'hy-am'],
2355
            ['id', 'id'],
2356
            ['is', 'is'],
2357
            ['it', 'it'],
2358
            ['ja', 'ja'],
2359
            ['jv', 'jv'],
2360
            ['ka', 'ka'],
2361
            ['kk', 'kk'],
2362
            ['km', 'km'],
2363
            ['ko', 'ko'],
2364
            ['ky', 'ky'],
2365
            ['lb', 'lb'],
2366
            ['lo', 'lo'],
2367
            ['lt', 'lt'],
2368
            ['lv', 'lv'],
2369
            ['me', 'me'],
2370
            ['mi', 'mi'],
2371
            ['mk', 'mk'],
2372
            ['ml', 'ml'],
2373
            ['mr', 'mr'],
2374
            ['ms', 'ms'],
2375
            ['ms-my', 'ms-my'],
2376
            ['my', 'my'],
2377
            ['nb', 'nb'],
2378
            ['ne', 'ne'],
2379
            ['nl-be', 'nl-be'],
2380
            ['nl', 'nl'],
2381
            ['nl', 'nl-nl'],
2382
            ['nn', 'nn'],
2383
            ['pa-in', 'pa-in'],
2384
            ['pl', 'pl'],
2385
            ['pt-br', 'pt-br'],
2386
            ['pt', 'pt'],
2387
            ['ro', 'ro'],
2388
            ['ru', 'ru'],
2389
            ['se', 'se'],
2390
            ['si', 'si'],
2391
            ['sk', 'sk'],
2392
            ['sl', 'sl'],
2393
            ['sq', 'sq'],
2394
            ['sr-cyrl', 'sr-cyrl'],
2395
            ['sr', 'sr'],
2396
            ['ss', 'ss'],
2397
            ['sv', 'sv'],
2398
            ['sw', 'sw'],
2399
            ['ta', 'ta'],
2400
            ['te', 'te'],
2401
            ['tet', 'tet'],
2402
            ['th', 'th'],
2403
            ['tlh', 'tlh'],
2404
            ['tl-ph', 'tl-ph'],
2405
            ['tr', 'tr'],
2406
            ['tzl', 'tzl'],
2407
            ['tzm', 'tzm'],
2408
            ['tzm-latn', 'tzm-latn'],
2409
            ['uk', 'uk'],
2410
            ['uz', 'uz'],
2411
            ['vi', 'vi'],
2412
            ['x-pseudo', 'x-pseudo'],
2413
            ['yo', 'yo'],
2414
            ['zh-cn', 'zh-cn'],
2415
            ['zh-hk', 'zh-hk'],
2416
            ['zh-tw', 'zh-tw'],
2417
        ];
2418
    }
2419
2420
    /**
2421
     * @dataProvider momentLocalesProvider
2422
     */
2423
    public function testCanonicalizedLocaleForMoment($expected, $original): void
2424
    {
2425
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForMoment($this->mockExtensionContext($original)));
2426
    }
2427
2428
    /**
2429
     * This method generates url part for Twig layout.
2430
     *
2431
     * @param array $url
2432
     *
2433
     * @return string
2434
     */
2435
    private function buildTwigLikeUrl($url)
2436
    {
2437
        return htmlspecialchars(http_build_query($url, '', '&', PHP_QUERY_RFC3986));
2438
    }
2439
2440
    private function getMethodAsPublic($privateMethod)
2441
    {
2442
        $reflection = new \ReflectionMethod('Sonata\AdminBundle\Twig\Extension\SonataAdminExtension', $privateMethod);
2443
        $reflection->setAccessible(true);
2444
2445
        return $reflection;
2446
    }
2447
2448
    private function removeExtraWhitespace($string)
2449
    {
2450
        return trim(preg_replace(
2451
            '/\s+/',
2452
            ' ',
2453
            $string
2454
        ));
2455
    }
2456
2457
    private function mockExtensionContext($locale)
2458
    {
2459
        $request = $this->createMock(Request::class);
2460
        $request->method('getLocale')->willReturn($locale);
2461
        $appVariable = $this->createMock(AppVariable::class);
2462
        $appVariable->method('getRequest')->willReturn($request);
2463
2464
        return ['app' => $appVariable];
2465
    }
2466
}
2467