Completed
Push — 3.x ( fd3361...37d5d4 )
by Grégoire
04:42
created

SonataAdminExtensionTest   F

Complexity

Total Complexity 72

Size/Duplication

Total Lines 2621
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 19

Importance

Changes 0
Metric Value
wmc 72
lcom 1
cbo 19
dl 0
loc 2621
rs 1.44
c 0
b 0
f 0

35 Methods

Rating   Name   Duplication   Size   Complexity  
B setUp() 0 148 4
C testRenderListElement() 0 83 15
A testDeprecatedRenderListElement() 0 45 1
A getDeprecatedRenderListElementTests() 0 15 1
B getRenderListElementTests() 0 912 1
A testRenderListElementNonExistentTemplate() 0 37 1
A testRenderListElementErrorLoadingTemplate() 0 20 1
C testRenderViewElement() 0 68 14
B getRenderViewElementTests() 0 551 1
A testGetValueFromFieldDescription() 0 11 1
A testGetValueFromFieldDescriptionWithRemoveLoopException() 0 12 1
A testGetValueFromFieldDescriptionWithNoValueException() 0 17 1
A testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance() 0 21 1
A testOutput() 0 48 1
A testRenderWithDebug() 0 39 1
A testRenderRelationElementNoObject() 0 4 1
A testRenderRelationElementToString() 0 13 2
A testDeprecatedRelationElementToString() 0 16 2
A testRenderRelationElementCustomToString() 0 23 3
A testRenderRelationElementMethodNotExist() 0 16 2
A testRenderRelationElementWithPropertyPath() 0 16 2
A testRenderRelationElementWithClosure() 0 21 2
A testGetUrlsafeIdentifier() 0 15 1
A testGetUrlsafeIdentifier_GivenAdmin_Foo() 0 24 1
A testGetUrlsafeIdentifier_GivenAdmin_Bar() 0 21 1
A xEditableChoicesProvider() 0 44 1
A testGetXEditableChoicesIsIdempotent() 0 19 1
A select2LocalesProvider() 0 54 1
A testCanonicalizedLocaleForSelect2() 0 4 1
B momentLocalesProvider() 0 119 1
A testCanonicalizedLocaleForMoment() 0 4 1
A testIsGrantedAffirmative() 0 8 1
A buildTwigLikeUrl() 0 4 1
A removeExtraWhitespace() 0 8 1
A mockExtensionContext() 0 9 1

How to fix   Complexity   

Complex Class

Complex classes like SonataAdminExtensionTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SonataAdminExtensionTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\AdminBundle\Tests\Twig\Extension;
15
16
use PHPUnit\Framework\TestCase;
17
use Prophecy\Argument;
18
use Psr\Log\LoggerInterface;
19
use Sonata\AdminBundle\Admin\AbstractAdmin;
20
use Sonata\AdminBundle\Admin\AdminInterface;
21
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
22
use Sonata\AdminBundle\Admin\Pool;
23
use Sonata\AdminBundle\Exception\NoValueException;
24
use Sonata\AdminBundle\Templating\TemplateRegistryInterface;
25
use Sonata\AdminBundle\Tests\Fixtures\Entity\FooToString;
26
use Sonata\AdminBundle\Twig\Extension\SonataAdminExtension;
27
use Symfony\Bridge\Twig\AppVariable;
28
use Symfony\Bridge\Twig\Extension\RoutingExtension;
29
use Symfony\Bridge\Twig\Extension\TranslationExtension;
30
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
31
use Symfony\Component\Config\FileLocator;
32
use Symfony\Component\DependencyInjection\ContainerInterface;
33
use Symfony\Component\HttpFoundation\Request;
34
use Symfony\Component\Routing\Generator\UrlGenerator;
35
use Symfony\Component\Routing\Loader\XmlFileLoader;
36
use Symfony\Component\Routing\RequestContext;
37
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
38
use Symfony\Component\Translation\DependencyInjection\TranslationDumperPass;
39
use Symfony\Component\Translation\Loader\XliffFileLoader;
40
use Symfony\Component\Translation\MessageSelector;
41
use Symfony\Component\Translation\Translator;
42
use Symfony\Component\Translation\TranslatorInterface;
43
44
/**
45
 * Test for SonataAdminExtension.
46
 *
47
 * @author Andrej Hudec <[email protected]>
48
 */
49
class SonataAdminExtensionTest extends TestCase
50
{
51
    /**
52
     * @var SonataAdminExtension
53
     */
54
    private $twigExtension;
55
56
    /**
57
     * @var \Twig_Environment
58
     */
59
    private $environment;
60
61
    /**
62
     * @var AdminInterface
63
     */
64
    private $admin;
65
66
    /**
67
     * @var AdminInterface
68
     */
69
    private $adminBar;
70
71
    /**
72
     * @var FieldDescriptionInterface
73
     */
74
    private $fieldDescription;
75
76
    /**
77
     * @var \stdClass
78
     */
79
    private $object;
80
81
    /**
82
     * @var Pool
83
     */
84
    private $pool;
85
86
    /**
87
     * @var LoggerInterface
88
     */
89
    private $logger;
90
91
    /**
92
     * @var string[]
93
     */
94
    private $xEditableTypeMapping;
95
96
    /**
97
     * @var TranslatorInterface
98
     */
99
    private $translator;
100
101
    /**
102
     * @var ContainerInterface
103
     */
104
    private $container;
105
106
    /**
107
     * @var TemplateRegistryInterface
108
     */
109
    private $templateRegistry;
110
111
    /**
112
     * @var AuthorizationCheckerInterface
113
     */
114
    private $securityChecker;
115
116
    public function setUp()
117
    {
118
        date_default_timezone_set('Europe/London');
119
120
        $container = $this->getMockForAbstractClass(ContainerInterface::class);
121
122
        $this->pool = new Pool($container, '', '');
123
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
124
        $this->pool->setAdminClasses(['fooClass' => ['sonata_admin_foo_service']]);
125
126
        $this->logger = $this->getMockForAbstractClass(LoggerInterface::class);
127
        $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...
128
            'choice' => 'select',
129
            'boolean' => 'select',
130
            'text' => 'text',
131
            'textarea' => 'textarea',
132
            'html' => 'textarea',
133
            'email' => 'email',
134
            'string' => 'text',
135
            'smallint' => 'text',
136
            'bigint' => 'text',
137
            'integer' => 'number',
138
            'decimal' => 'number',
139
            'currency' => 'number',
140
            'percent' => 'number',
141
            'url' => 'url',
142
        ];
143
144
        // translation extension
145
        $translator = new Translator(
146
            'en',
147
            // NEXT_MAJOR: simplify this when dropping symfony < 3.4
148
            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...
Deprecated Code introduced by
The class Symfony\Component\Translation\MessageSelector has been deprecated with message: since Symfony 4.2, use IdentityTranslator instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
149
        );
150
        $translator->addLoader('xlf', new XliffFileLoader());
151
        $translator->addResource(
152
            'xlf',
153
            __DIR__.'/../../../src/Resources/translations/SonataAdminBundle.en.xliff',
154
            'en',
155
            'SonataAdminBundle'
156
        );
157
158
        $this->translator = $translator;
159
160
        $this->templateRegistry = $this->prophesize(TemplateRegistryInterface::class);
161
        $this->container = $this->prophesize(ContainerInterface::class);
162
        $this->container->get('sonata_admin_foo_service.template_registry')->willReturn($this->templateRegistry->reveal());
163
164
        $this->securityChecker = $this->prophesize(AuthorizationCheckerInterface::class);
165
        $this->securityChecker->isGranted(['foo', 'bar'], null)->willReturn(false);
166
        $this->securityChecker->isGranted(Argument::type('string'), null)->willReturn(true);
167
168
        $this->twigExtension = new SonataAdminExtension(
169
            $this->pool, $this->logger, $this->translator, $this->container->reveal(), $this->securityChecker->reveal()
170
        );
171
        $this->twigExtension->setXEditableTypeMapping($this->xEditableTypeMapping);
172
173
        $request = $this->createMock(Request::class);
174
        $request->expects($this->any())->method('get')->with('_sonata_admin')->willReturn('sonata_admin_foo_service');
175
176
        $loader = new StubFilesystemLoader([
177
            __DIR__.'/../../../src/Resources/views/CRUD',
178
        ]);
179
        $loader->addPath(__DIR__.'/../../../src/Resources/views/', 'SonataAdmin');
180
181
        $this->environment = new \Twig_Environment($loader, [
182
            'strict_variables' => true,
183
            'cache' => false,
184
            'autoescape' => 'html',
185
            'optimizations' => 0,
186
        ]);
187
        $this->environment->addExtension($this->twigExtension);
188
        $this->environment->addExtension(new TranslationExtension($translator));
189
        $this->environment->addExtension(new FakeTemplateRegistryExtension());
190
191
        // routing extension
192
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../../src/Resources/config/routing']));
193
        $routeCollection = $xmlFileLoader->load('sonata_admin.xml');
194
195
        $xmlFileLoader = new XmlFileLoader(new FileLocator([__DIR__.'/../../Fixtures/Resources/config/routing']));
196
        $testRouteCollection = $xmlFileLoader->load('routing.xml');
197
198
        $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...
199
        $requestContext = new RequestContext();
200
        $urlGenerator = new UrlGenerator($routeCollection, $requestContext);
201
        $this->environment->addExtension(new RoutingExtension($urlGenerator));
202
        $this->environment->addExtension(new \Twig_Extensions_Extension_Text());
203
204
        // initialize object
205
        $this->object = new \stdClass();
206
207
        // initialize admin
208
        $this->admin = $this->createMock(AbstractAdmin::class);
209
210
        $this->admin->expects($this->any())
211
            ->method('getCode')
212
            ->will($this->returnValue('sonata_admin_foo_service'));
213
214
        $this->admin->expects($this->any())
215
            ->method('id')
216
            ->with($this->equalTo($this->object))
217
            ->will($this->returnValue(12345));
218
219
        $this->admin->expects($this->any())
220
            ->method('getNormalizedIdentifier')
221
            ->with($this->equalTo($this->object))
222
            ->will($this->returnValue(12345));
223
224
        $this->admin->expects($this->any())
225
            ->method('trans')
226
            ->will($this->returnCallback(function ($id, $parameters = [], $domain = null) use ($translator) {
227
                return $translator->trans($id, $parameters, $domain);
228
            }));
229
230
        $this->adminBar = $this->createMock(AbstractAdmin::class);
231
        $this->adminBar->expects($this->any())
232
            ->method('hasAccess')
233
            ->will($this->returnValue(true));
234
        $this->adminBar->expects($this->any())
235
            ->method('getNormalizedIdentifier')
236
            ->with($this->equalTo($this->object))
237
            ->will($this->returnValue(12345));
238
239
        $container->expects($this->any())
240
            ->method('get')
241
            ->will($this->returnCallback(function ($id) {
242
                if ('sonata_admin_foo_service' == $id) {
243
                    return $this->admin;
244
                } elseif ('sonata_admin_bar_service' == $id) {
245
                    return $this->adminBar;
246
                }
247
            }));
248
249
        // initialize field description
250
        $this->fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
251
252
        $this->fieldDescription->expects($this->any())
253
            ->method('getName')
254
            ->will($this->returnValue('fd_name'));
255
256
        $this->fieldDescription->expects($this->any())
257
            ->method('getAdmin')
258
            ->will($this->returnValue($this->admin));
259
260
        $this->fieldDescription->expects($this->any())
261
            ->method('getLabel')
262
            ->will($this->returnValue('Data'));
263
    }
264
265
    /**
266
     * @group legacy
267
     * @expectedDeprecation The Sonata\AdminBundle\Admin\AbstractAdmin::getTemplate method is deprecated (since 3.34, will be dropped in 4.0. Use TemplateRegistry services instead).
268
     * @dataProvider getRenderListElementTests
269
     */
270
    public function testRenderListElement($expected, $type, $value, array $options)
271
    {
272
        $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...
273
            ->method('getPersistentParameters')
274
            ->will($this->returnValue(['context' => 'foo']));
275
276
        $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...
277
            ->method('hasAccess')
278
            ->will($this->returnValue(true));
279
280
        // NEXT_MAJOR: Remove this line
281
        $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...
282
            ->method('getTemplate')
283
            ->with('base_list_field')
284
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
285
286
        $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...
287
288
        $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...
289
            ->method('getValue')
290
            ->will($this->returnValue($value));
291
292
        $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...
293
            ->method('getType')
294
            ->will($this->returnValue($type));
295
296
        $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...
297
            ->method('getOptions')
298
            ->will($this->returnValue($options));
299
300
        $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...
301
            ->method('getOption')
302
            ->will($this->returnCallback(function ($name, $default = null) use ($options) {
303
                return $options[$name] ?? $default;
304
            }));
305
306
        $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...
307
            ->method('getTemplate')
308
            ->will($this->returnCallback(function () use ($type) {
309
                switch ($type) {
310
                    case 'string':
311
                        return '@SonataAdmin/CRUD/list_string.html.twig';
312
                    case 'boolean':
313
                        return '@SonataAdmin/CRUD/list_boolean.html.twig';
314
                    case 'datetime':
315
                        return '@SonataAdmin/CRUD/list_datetime.html.twig';
316
                    case 'date':
317
                        return '@SonataAdmin/CRUD/list_date.html.twig';
318
                    case 'time':
319
                        return '@SonataAdmin/CRUD/list_time.html.twig';
320
                    case 'currency':
321
                        return '@SonataAdmin/CRUD/list_currency.html.twig';
322
                    case 'percent':
323
                        return '@SonataAdmin/CRUD/list_percent.html.twig';
324
                    case 'email':
325
                        return '@SonataAdmin/CRUD/list_email.html.twig';
326
                    case 'choice':
327
                        return '@SonataAdmin/CRUD/list_choice.html.twig';
328
                    case 'array':
329
                        return '@SonataAdmin/CRUD/list_array.html.twig';
330
                    case 'trans':
331
                        return '@SonataAdmin/CRUD/list_trans.html.twig';
332
                    case 'url':
333
                        return '@SonataAdmin/CRUD/list_url.html.twig';
334
                    case 'html':
335
                        return '@SonataAdmin/CRUD/list_html.html.twig';
336
                    case 'nonexistent':
337
                        // template doesn`t exist
338
                        return '@SonataAdmin/CRUD/list_nonexistent_template.html.twig';
339
                    default:
340
                        return false;
341
                }
342
            }));
343
344
        $this->assertSame(
345
            $this->removeExtraWhitespace($expected),
346
            $this->removeExtraWhitespace($this->twigExtension->renderListElement(
347
                $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...
348
                $this->object,
349
                $this->fieldDescription
350
            ))
351
        );
352
    }
353
354
    /**
355
     * @dataProvider getDeprecatedRenderListElementTests
356
     * @group legacy
357
     */
358
    public function testDeprecatedRenderListElement($expected, $value, array $options)
359
    {
360
        $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...
361
            ->method('hasAccess')
362
            ->will($this->returnValue(true));
363
364
        // NEXT_MAJOR: Remove this line
365
        $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...
366
            ->method('getTemplate')
367
            ->with('base_list_field')
368
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
369
370
        $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...
371
372
        $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...
373
            ->method('getValue')
374
            ->will($this->returnValue($value));
375
376
        $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...
377
            ->method('getType')
378
            ->will($this->returnValue('nonexistent'));
379
380
        $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...
381
            ->method('getOptions')
382
            ->will($this->returnValue($options));
383
384
        $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...
385
            ->method('getOption')
386
            ->will($this->returnCallback(function ($name, $default = null) use ($options) {
387
                return $options[$name] ?? $default;
388
            }));
389
390
        $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...
391
            ->method('getTemplate')
392
            ->will($this->returnValue('@SonataAdmin/CRUD/list_nonexistent_template.html.twig'));
393
394
        $this->assertSame(
395
            $this->removeExtraWhitespace($expected),
396
            $this->removeExtraWhitespace($this->twigExtension->renderListElement(
397
                $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...
398
                $this->object,
399
                $this->fieldDescription
400
            ))
401
        );
402
    }
403
404
    public function getDeprecatedRenderListElementTests()
405
    {
406
        return [
407
            [
408
                '<td class="sonata-ba-list-field sonata-ba-list-field-nonexistent" objectId="12345"> Example </td>',
409
                'Example',
410
                [],
411
            ],
412
            [
413
                '<td class="sonata-ba-list-field sonata-ba-list-field-nonexistent" objectId="12345"> </td>',
414
                null,
415
                [],
416
            ],
417
        ];
418
    }
419
420
    public function getRenderListElementTests()
421
    {
422
        return [
423
            [
424
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> Example </td>',
425
                'string',
426
                'Example',
427
                [],
428
            ],
429
            [
430
                '<td class="sonata-ba-list-field sonata-ba-list-field-string" objectId="12345"> </td>',
431
                'string',
432
                null,
433
                [],
434
            ],
435
            [
436
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> Example </td>',
437
                'text',
438
                'Example',
439
                [],
440
            ],
441
            [
442
                '<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345"> </td>',
443
                'text',
444
                null,
445
                [],
446
            ],
447
            [
448
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> Example </td>',
449
                'textarea',
450
                'Example',
451
                [],
452
            ],
453
            [
454
                '<td class="sonata-ba-list-field sonata-ba-list-field-textarea" objectId="12345"> </td>',
455
                'textarea',
456
                null,
457
                [],
458
            ],
459
            'datetime field' => [
460
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
461
                    December 24, 2013 10:11
462
                </td>',
463
                'datetime',
464
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
465
                [],
466
            ],
467
            [
468
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
469
                    December 24, 2013 18:11
470
                </td>',
471
                'datetime',
472
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
473
                ['timezone' => 'Asia/Hong_Kong'],
474
            ],
475
            [
476
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
477
                'datetime',
478
                null,
479
                [],
480
            ],
481
            [
482
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
483
                    24.12.2013 10:11:12
484
                </td>',
485
                'datetime',
486
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
487
                ['format' => 'd.m.Y H:i:s'],
488
            ],
489
            [
490
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
491
                'datetime',
492
                null,
493
                ['format' => 'd.m.Y H:i:s'],
494
            ],
495
            [
496
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345">
497
                    24.12.2013 18:11:12
498
                </td>',
499
                'datetime',
500
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
501
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
502
            ],
503
            [
504
                '<td class="sonata-ba-list-field sonata-ba-list-field-datetime" objectId="12345"> &nbsp; </td>',
505
                'datetime',
506
                null,
507
                ['format' => 'd.m.Y H:i:s', 'timezone' => 'Asia/Hong_Kong'],
508
            ],
509
            [
510
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> December 24, 2013 </td>',
511
                'date',
512
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
513
                [],
514
            ],
515
            [
516
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
517
                'date',
518
                null,
519
                [],
520
            ],
521
            [
522
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> 24.12.2013 </td>',
523
                'date',
524
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
525
                ['format' => 'd.m.Y'],
526
            ],
527
            [
528
                '<td class="sonata-ba-list-field sonata-ba-list-field-date" objectId="12345"> &nbsp; </td>',
529
                'date',
530
                null,
531
                ['format' => 'd.m.Y'],
532
            ],
533
            [
534
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> 10:11:12 </td>',
535
                'time',
536
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
537
                [],
538
            ],
539
            [
540
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> 18:11:12 </td>',
541
                'time',
542
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
543
                ['timezone' => 'Asia/Hong_Kong'],
544
            ],
545
            [
546
                '<td class="sonata-ba-list-field sonata-ba-list-field-time" objectId="12345"> &nbsp; </td>',
547
                'time',
548
                null,
549
                [],
550
            ],
551
            [
552
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> 10.746135 </td>',
553
                'number', 10.746135,
554
                [],
555
            ],
556
            [
557
                '<td class="sonata-ba-list-field sonata-ba-list-field-number" objectId="12345"> </td>',
558
                'number',
559
                null,
560
                [],
561
            ],
562
            [
563
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> 5678 </td>',
564
                'integer',
565
                5678,
566
                [],
567
            ],
568
            [
569
                '<td class="sonata-ba-list-field sonata-ba-list-field-integer" objectId="12345"> </td>',
570
                'integer',
571
                null,
572
                [],
573
            ],
574
            [
575
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 1074.6135 % </td>',
576
                'percent',
577
                10.746135,
578
                [],
579
            ],
580
            [
581
                '<td class="sonata-ba-list-field sonata-ba-list-field-percent" objectId="12345"> 0 % </td>',
582
                'percent',
583
                null,
584
                [],
585
            ],
586
            [
587
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> EUR 10.746135 </td>',
588
                'currency',
589
                10.746135,
590
                ['currency' => 'EUR'],
591
            ],
592
            [
593
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
594
                'currency',
595
                null,
596
                ['currency' => 'EUR'],
597
            ],
598
            [
599
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> GBP 51.23456 </td>',
600
                'currency',
601
                51.23456,
602
                ['currency' => 'GBP'],
603
            ],
604
            [
605
                '<td class="sonata-ba-list-field sonata-ba-list-field-currency" objectId="12345"> </td>',
606
                'currency',
607
                null,
608
                ['currency' => 'GBP'],
609
            ],
610
            [
611
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> &nbsp; </td>',
612
                'email',
613
                null,
614
                [],
615
            ],
616
            [
617
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> <a href="mailto:[email protected]">[email protected]</a> </td>',
618
                'email',
619
                '[email protected]',
620
                [],
621
            ],
622
            [
623
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
624
                    <a href="mailto:[email protected]">[email protected]</a> </td>',
625
                'email',
626
                '[email protected]',
627
                ['as_string' => false],
628
            ],
629
            [
630
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
631
                'email',
632
                '[email protected]',
633
                ['as_string' => true],
634
            ],
635
            [
636
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
637
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a>  </td>',
638
                'email',
639
                '[email protected]',
640
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
641
            ],
642
            [
643
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
644
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a>  </td>',
645
                'email',
646
                '[email protected]',
647
                ['subject' => 'Main Theme'],
648
            ],
649
            [
650
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345">
651
                    <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a>  </td>',
652
                'email',
653
                '[email protected]',
654
                ['body' => 'Message Body'],
655
            ],
656
            [
657
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
658
                'email',
659
                '[email protected]',
660
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
661
            ],
662
            [
663
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
664
                'email',
665
                '[email protected]',
666
                ['as_string' => true, 'body' => 'Message Body'],
667
            ],
668
            [
669
                '<td class="sonata-ba-list-field sonata-ba-list-field-email" objectId="12345"> [email protected] </td>',
670
                'email',
671
                '[email protected]',
672
                ['as_string' => true, 'subject' => 'Main Theme'],
673
            ],
674
            [
675
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345">
676
                    [1 => First] [2 => Second]
677
                </td>',
678
                'array',
679
                [1 => 'First', 2 => 'Second'],
680
                [],
681
            ],
682
            [
683
                '<td class="sonata-ba-list-field sonata-ba-list-field-array" objectId="12345"> </td>',
684
                'array',
685
                null,
686
                [],
687
            ],
688
            [
689
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
690
                    <span class="label label-success">yes</span>
691
                </td>',
692
                'boolean',
693
                true,
694
                ['editable' => false],
695
            ],
696
            [
697
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
698
                    <span class="label label-danger">no</span>
699
                </td>',
700
                'boolean',
701
                false,
702
                ['editable' => false],
703
            ],
704
            [
705
                '<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
706
                    <span class="label label-danger">no</span>
707
                </td>',
708
                'boolean',
709
                null,
710
                ['editable' => false],
711
            ],
712
            [
713
                <<<'EOT'
714
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
715
    <span
716
        class="x-editable"
717
        data-type="select"
718
        data-value="1"
719
        data-title="Data"
720
        data-pk="12345"
721
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
722
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
723
    >
724
        <span class="label label-success">yes</span>
725
    </span>
726
</td>
727
EOT
728
            ,
729
                'boolean',
730
                true,
731
                ['editable' => true],
732
            ],
733
            [
734
                <<<'EOT'
735
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
736
    <span
737
        class="x-editable"
738
        data-type="select"
739
        data-value="0"
740
        data-title="Data"
741
        data-pk="12345"
742
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
743
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]"
744
    >
745
    <span class="label label-danger">no</span> </span>
746
</td>
747
EOT
748
                ,
749
                'boolean',
750
                false,
751
                ['editable' => true],
752
            ],
753
            [
754
                <<<'EOT'
755
<td class="sonata-ba-list-field sonata-ba-list-field-boolean" objectId="12345">
756
    <span
757
        class="x-editable"
758
        data-type="select"
759
        data-value="0"
760
        data-title="Data"
761
        data-pk="12345"
762
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
763
        data-source="[{value: 0, text: 'no'},{value: 1, text: 'yes'}]" >
764
        <span class="label label-danger">no</span> </span>
765
</td>
766
EOT
767
                ,
768
                'boolean',
769
                null,
770
                ['editable' => true],
771
            ],
772
            [
773
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
774
                'trans',
775
                'action_delete',
776
                ['catalogue' => 'SonataAdminBundle'],
777
            ],
778
            [
779
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> </td>',
780
                'trans',
781
                null,
782
                ['catalogue' => 'SonataAdminBundle'],
783
            ],
784
            [
785
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345"> Delete </td>',
786
                'trans',
787
                'action_delete',
788
                ['format' => '%s', 'catalogue' => 'SonataAdminBundle'],
789
            ],
790
            [
791
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
792
                action.action_delete
793
                </td>',
794
                'trans',
795
                'action_delete',
796
                ['format' => 'action.%s'],
797
            ],
798
            [
799
                '<td class="sonata-ba-list-field sonata-ba-list-field-trans" objectId="12345">
800
                action.action_delete
801
                </td>',
802
                'trans',
803
                'action_delete',
804
                ['format' => 'action.%s', 'catalogue' => 'SonataAdminBundle'],
805
            ],
806
            [
807
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
808
                'choice',
809
                'Status1',
810
                [],
811
            ],
812
            [
813
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Status1 </td>',
814
                'choice',
815
                ['Status1'],
816
                ['choices' => [], 'multiple' => true],
817
            ],
818
            [
819
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 </td>',
820
                'choice',
821
                'Status1',
822
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
823
            ],
824
            [
825
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
826
                'choice',
827
                null,
828
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
829
            ],
830
            [
831
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
832
                NoValidKeyInChoices
833
                </td>',
834
                'choice',
835
                'NoValidKeyInChoices',
836
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2', 'Status3' => 'Alias3']],
837
            ],
838
            [
839
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete </td>',
840
                'choice',
841
                'Foo',
842
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
843
                    'Foo' => 'action_delete',
844
                    'Status2' => 'Alias2',
845
                    'Status3' => 'Alias3',
846
                ]],
847
            ],
848
            [
849
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1, Alias3 </td>',
850
                'choice',
851
                ['Status1', 'Status3'],
852
                ['choices' => [
853
                    'Status1' => 'Alias1',
854
                    'Status2' => 'Alias2',
855
                    'Status3' => 'Alias3',
856
                ], 'multiple' => true], ],
857
            [
858
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Alias1 | Alias3 </td>',
859
                'choice',
860
                ['Status1', 'Status3'],
861
                ['choices' => [
862
                    'Status1' => 'Alias1',
863
                    'Status2' => 'Alias2',
864
                    'Status3' => 'Alias3',
865
                ], 'multiple' => true, 'delimiter' => ' | '], ],
866
            [
867
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> </td>',
868
                'choice',
869
                null,
870
                ['choices' => [
871
                    'Status1' => 'Alias1',
872
                    'Status2' => 'Alias2',
873
                    'Status3' => 'Alias3',
874
                ], 'multiple' => true],
875
            ],
876
            [
877
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
878
                NoValidKeyInChoices
879
                </td>',
880
                'choice',
881
                ['NoValidKeyInChoices'],
882
                ['choices' => [
883
                    'Status1' => 'Alias1',
884
                    'Status2' => 'Alias2',
885
                    'Status3' => 'Alias3',
886
                ], 'multiple' => true],
887
            ],
888
            [
889
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
890
                NoValidKeyInChoices, Alias2
891
                </td>',
892
                'choice',
893
                ['NoValidKeyInChoices', 'Status2'],
894
                ['choices' => [
895
                    'Status1' => 'Alias1',
896
                    'Status2' => 'Alias2',
897
                    'Status3' => 'Alias3',
898
                ], 'multiple' => true],
899
            ],
900
            [
901
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345"> Delete, Alias3 </td>',
902
                'choice',
903
                ['Foo', 'Status3'],
904
                ['catalogue' => 'SonataAdminBundle', 'choices' => [
905
                    'Foo' => 'action_delete',
906
                    'Status2' => 'Alias2',
907
                    'Status3' => 'Alias3',
908
                ], 'multiple' => true],
909
            ],
910
            [
911
                '<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
912
                &lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;
913
            </td>',
914
                'choice',
915
                ['Status1', 'Status3'],
916
                ['choices' => [
917
                    'Status1' => '<b>Alias1</b>',
918
                    'Status2' => '<b>Alias2</b>',
919
                    'Status3' => '<b>Alias3</b>',
920
                ], 'multiple' => true], ],
921
            [
922
                <<<'EOT'
923
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
924
    <span
925
        class="x-editable"
926
        data-type="select"
927
        data-value="Status1"
928
        data-title="Data"
929
        data-pk="12345"
930
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
931
        data-source="[]"
932
    >
933
        Status1
934
    </span>
935
</td>
936
EOT
937
                ,
938
                'choice',
939
                'Status1',
940
                ['editable' => true],
941
            ],
942
            [
943
                <<<'EOT'
944
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
945
    <span
946
        class="x-editable"
947
        data-type="select"
948
        data-value="Status1"
949
        data-title="Data"
950
        data-pk="12345"
951
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
952
        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;}]" >
953
        Alias1 </span>
954
</td>
955
EOT
956
                ,
957
                'choice',
958
                'Status1',
959
                [
960
                    'editable' => true,
961
                    'choices' => [
962
                        'Status1' => 'Alias1',
963
                        'Status2' => 'Alias2',
964
                        'Status3' => 'Alias3',
965
                    ],
966
                ],
967
            ],
968
            [
969
                <<<'EOT'
970
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
971
    <span
972
        class="x-editable"
973
        data-type="select"
974
        data-value=""
975
        data-title="Data"
976
        data-pk="12345"
977
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
978
        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;}]" >
979
980
    </span>
981
</td>
982
EOT
983
                ,
984
                'choice',
985
                null,
986
                [
987
                    'editable' => true,
988
                    'choices' => [
989
                        'Status1' => 'Alias1',
990
                        'Status2' => 'Alias2',
991
                        'Status3' => 'Alias3',
992
                    ],
993
                ],
994
            ],
995
            [
996
                <<<'EOT'
997
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
998
    <span
999
        class="x-editable"
1000
        data-type="select"
1001
        data-value="NoValidKeyInChoices"
1002
        data-title="Data" data-pk="12345"
1003
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1004
        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;}]" >
1005
        NoValidKeyInChoices
1006
    </span>
1007
</td>
1008
EOT
1009
                ,
1010
                'choice',
1011
                'NoValidKeyInChoices',
1012
                [
1013
                    'editable' => true,
1014
                    'choices' => [
1015
                        'Status1' => 'Alias1',
1016
                        'Status2' => 'Alias2',
1017
                        'Status3' => 'Alias3',
1018
                    ],
1019
                ],
1020
            ],
1021
            [
1022
                <<<'EOT'
1023
<td class="sonata-ba-list-field sonata-ba-list-field-choice" objectId="12345">
1024
    <span
1025
        class="x-editable"
1026
        data-type="select"
1027
        data-value="Foo"
1028
        data-title="Data"
1029
        data-pk="12345"
1030
        data-url="/core/set-object-field-value?context=list&amp;field=fd_name&amp;objectId=12345&amp;code=sonata_admin_foo_service"
1031
        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;}]" >
1032
         Delete
1033
    </span>
1034
</td>
1035
EOT
1036
                ,
1037
                'choice',
1038
                'Foo',
1039
                [
1040
                    'editable' => true,
1041
                    'catalogue' => 'SonataAdminBundle',
1042
                    'choices' => [
1043
                        'Foo' => 'action_delete',
1044
                        'Status2' => 'Alias2',
1045
                        'Status3' => 'Alias3',
1046
                    ],
1047
                ],
1048
            ],
1049
            [
1050
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1051
                'url',
1052
                null,
1053
                [],
1054
            ],
1055
            [
1056
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1057
                'url',
1058
                null,
1059
                ['url' => 'http://example.com'],
1060
            ],
1061
            [
1062
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345"> &nbsp; </td>',
1063
                'url',
1064
                null,
1065
                ['route' => ['name' => 'sonata_admin_foo']],
1066
            ],
1067
            [
1068
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1069
                <a href="http://example.com">http://example.com</a>
1070
                </td>',
1071
                'url',
1072
                'http://example.com',
1073
                [],
1074
            ],
1075
            [
1076
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1077
                <a href="https://example.com">https://example.com</a>
1078
                </td>',
1079
                'url',
1080
                'https://example.com',
1081
                [],
1082
            ],
1083
            [
1084
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1085
                <a href="https://example.com" target="_blank">https://example.com</a>
1086
                </td>',
1087
                'url',
1088
                'https://example.com',
1089
                ['attributes' => ['target' => '_blank']],
1090
            ],
1091
            [
1092
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1093
                <a href="https://example.com" target="_blank" class="fooLink">https://example.com</a>
1094
                </td>',
1095
                'url',
1096
                'https://example.com',
1097
                ['attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1098
            ],
1099
            [
1100
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1101
                <a href="http://example.com">example.com</a>
1102
                </td>',
1103
                'url',
1104
                'http://example.com',
1105
                ['hide_protocol' => true],
1106
            ],
1107
            [
1108
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1109
                <a href="https://example.com">example.com</a>
1110
                </td>',
1111
                'url',
1112
                'https://example.com',
1113
                ['hide_protocol' => true],
1114
            ],
1115
            [
1116
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1117
                <a href="http://example.com">http://example.com</a>
1118
                </td>',
1119
                'url',
1120
                'http://example.com',
1121
                ['hide_protocol' => false],
1122
            ],
1123
            [
1124
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1125
                <a href="https://example.com">https://example.com</a>
1126
                </td>',
1127
                'url',
1128
                'https://example.com',
1129
                ['hide_protocol' => false],
1130
            ],
1131
            [
1132
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1133
                <a href="http://example.com">Foo</a>
1134
                </td>',
1135
                'url',
1136
                'Foo',
1137
                ['url' => 'http://example.com'],
1138
            ],
1139
            [
1140
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1141
                <a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a>
1142
                </td>',
1143
                'url',
1144
                '<b>Foo</b>',
1145
                ['url' => 'http://example.com'],
1146
            ],
1147
            [
1148
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1149
                <a href="/foo">Foo</a>
1150
                </td>',
1151
                'url',
1152
                'Foo',
1153
                ['route' => ['name' => 'sonata_admin_foo']],
1154
            ],
1155
            [
1156
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1157
                <a href="http://localhost/foo">Foo</a>
1158
                </td>',
1159
                'url',
1160
                'Foo',
1161
                ['route' => ['name' => 'sonata_admin_foo', 'absolute' => true]],
1162
            ],
1163
            [
1164
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1165
                <a href="/foo">foo/bar?a=b&amp;c=123456789</a>
1166
                </td>',
1167
                'url',
1168
                'http://foo/bar?a=b&c=123456789',
1169
                ['route' => ['name' => 'sonata_admin_foo'],
1170
                'hide_protocol' => true, ],
1171
            ],
1172
            [
1173
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1174
                <a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a>
1175
                </td>',
1176
                'url',
1177
                'http://foo/bar?a=b&c=123456789',
1178
                [
1179
                    'route' => ['name' => 'sonata_admin_foo', 'absolute' => true],
1180
                    'hide_protocol' => true,
1181
                ],
1182
            ],
1183
            [
1184
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1185
                <a href="/foo/abcd/efgh?param3=ijkl">Foo</a>
1186
                </td>',
1187
                'url',
1188
                'Foo',
1189
                [
1190
                    'route' => ['name' => 'sonata_admin_foo_param',
1191
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1192
                ],
1193
            ],
1194
            [
1195
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1196
                <a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a>
1197
                </td>',
1198
                'url',
1199
                'Foo',
1200
                [
1201
                    'route' => ['name' => 'sonata_admin_foo_param',
1202
                    'absolute' => true,
1203
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'], ],
1204
                ],
1205
            ],
1206
            [
1207
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1208
                <a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1209
                </td>',
1210
                'url',
1211
                'Foo',
1212
                [
1213
                    'route' => ['name' => 'sonata_admin_foo_object',
1214
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1215
                    'identifier_parameter_name' => 'barId', ],
1216
                ],
1217
            ],
1218
            [
1219
                '<td class="sonata-ba-list-field sonata-ba-list-field-url" objectId="12345">
1220
                <a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a>
1221
                </td>',
1222
                'url',
1223
                'Foo',
1224
                [
1225
                    'route' => ['name' => 'sonata_admin_foo_object',
1226
                    'absolute' => true,
1227
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1228
                    'identifier_parameter_name' => 'barId', ],
1229
                ],
1230
            ],
1231
            [
1232
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1233
                <p><strong>Creating a Template for the Field</strong> and form</p>
1234
                </td>',
1235
                'html',
1236
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1237
                [],
1238
            ],
1239
            [
1240
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1241
                Creating a Template for the Field and form
1242
                </td>',
1243
                'html',
1244
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1245
                ['strip' => true],
1246
            ],
1247
            [
1248
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1249
                Creating a Template for the Fi...
1250
                </td>',
1251
                'html',
1252
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1253
                ['truncate' => true],
1254
            ],
1255
            [
1256
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345"> Creating a... </td>',
1257
                'html',
1258
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1259
                ['truncate' => ['length' => 10]],
1260
            ],
1261
            [
1262
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1263
                Creating a Template for the Field...
1264
                </td>',
1265
                'html',
1266
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1267
                ['truncate' => ['preserve' => true]],
1268
            ],
1269
            [
1270
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1271
                Creating a Template for the Fi etc.
1272
                </td>',
1273
                'html',
1274
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1275
                ['truncate' => ['separator' => ' etc.']],
1276
            ],
1277
            [
1278
                '<td class="sonata-ba-list-field sonata-ba-list-field-html" objectId="12345">
1279
                Creating a Template for[...]
1280
                </td>',
1281
                'html',
1282
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1283
                [
1284
                    'truncate' => [
1285
                        'length' => 20,
1286
                        'preserve' => true,
1287
                        'separator' => '[...]',
1288
                    ],
1289
                ],
1290
            ],
1291
1292
            [
1293
                <<<'EOT'
1294
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1295
<div
1296
    class="sonata-readmore"
1297
    data-readmore-height="40"
1298
    data-readmore-more="Read more"
1299
    data-readmore-less="Close">A very long string</div>
1300
</td>
1301
EOT
1302
                ,
1303
                'text',
1304
                'A very long string',
1305
                [
1306
                    'collapse' => true,
1307
                ],
1308
            ],
1309
            [
1310
                <<<'EOT'
1311
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectId="12345">
1312
<div
1313
    class="sonata-readmore"
1314
    data-readmore-height="10"
1315
    data-readmore-more="More"
1316
    data-readmore-less="Less">A very long string</div>
1317
</td>
1318
EOT
1319
                ,
1320
                'text',
1321
                'A very long string',
1322
                [
1323
                    'collapse' => [
1324
                        'height' => 10,
1325
                        'more' => 'More',
1326
                        'less' => 'Less',
1327
                    ],
1328
                ],
1329
            ],
1330
        ];
1331
    }
1332
1333
    /**
1334
     * @group legacy
1335
     */
1336
    public function testRenderListElementNonExistentTemplate()
1337
    {
1338
        // NEXT_MAJOR: Remove this line
1339
        $this->admin->method('getTemplate')
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1340
            ->with('base_list_field')
1341
            ->willReturn('@SonataAdmin/CRUD/base_list_field.html.twig');
1342
1343
        $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...
1344
1345
        $this->fieldDescription->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1346
            ->method('getValue')
1347
            ->will($this->returnValue('Foo'));
1348
1349
        $this->fieldDescription->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1350
            ->method('getFieldName')
1351
            ->will($this->returnValue('Foo_name'));
1352
1353
        $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...
1354
            ->method('getType')
1355
            ->will($this->returnValue('nonexistent'));
1356
1357
        $this->fieldDescription->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1358
            ->method('getTemplate')
1359
            ->will($this->returnValue('@SonataAdmin/CRUD/list_nonexistent_template.html.twig'));
1360
1361
        $this->logger->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Psr\Log\LoggerInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1362
            ->method('warning')
1363
            ->with(($this->stringStartsWith($this->removeExtraWhitespace(
1364
                'An error occured trying to load the template
1365
                "@SonataAdmin/CRUD/list_nonexistent_template.html.twig"
1366
                for the field "Foo_name", the default template
1367
                    "@SonataAdmin/CRUD/base_list_field.html.twig" was used
1368
                    instead.'
1369
            ))));
1370
1371
        $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription);
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...
1372
    }
1373
1374
    /**
1375
     * @group                    legacy
1376
     */
1377
    public function testRenderListElementErrorLoadingTemplate()
1378
    {
1379
        $this->expectException(\Twig_Error_Loader::class);
1380
        $this->expectExceptionMessage('Unable to find template "@SonataAdmin/CRUD/base_list_nonexistent_field.html.twig"');
1381
1382
        // NEXT_MAJOR: Remove this line
1383
        $this->admin->method('getTemplate')
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<Sonata\AdminBundle\Admin\AdminInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1384
            ->with('base_list_field')
1385
            ->willReturn('@SonataAdmin/CRUD/base_list_nonexistent_field.html.twig');
1386
1387
        $this->templateRegistry->getTemplate('base_list_field')->willReturn('@SonataAdmin/CRUD/base_list_nonexistent_field.html.twig');
0 ignored issues
show
Bug introduced by
The method willReturn cannot be called on $this->templateRegistry-...late('base_list_field') (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1388
1389
        $this->fieldDescription->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Sonata\AdminBundl...ldDescriptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1390
            ->method('getTemplate')
1391
            ->will($this->returnValue('@SonataAdmin/CRUD/list_nonexistent_template.html.twig'));
1392
1393
        $this->twigExtension->renderListElement($this->environment, $this->object, $this->fieldDescription);
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...
1394
1395
        $this->templateRegistry->getTemplate('base_list_field')->shouldHaveBeenCalled();
0 ignored issues
show
Bug introduced by
The method shouldHaveBeenCalled cannot be called on $this->templateRegistry-...late('base_list_field') (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1396
    }
1397
1398
    /**
1399
     * @dataProvider getRenderViewElementTests
1400
     */
1401
    public function testRenderViewElement($expected, $type, $value, array $options)
1402
    {
1403
        $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...
1404
            ->method('getTemplate')
1405
            ->will($this->returnValue('@SonataAdmin/CRUD/base_show_field.html.twig'));
1406
1407
        $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...
1408
            ->method('getValue')
1409
            ->will($this->returnCallback(function () use ($value) {
1410
                if ($value instanceof NoValueException) {
1411
                    throw  $value;
1412
                }
1413
1414
                return $value;
1415
            }));
1416
1417
        $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...
1418
            ->method('getType')
1419
            ->will($this->returnValue($type));
1420
1421
        $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...
1422
            ->method('getOptions')
1423
            ->will($this->returnValue($options));
1424
1425
        $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...
1426
            ->method('getTemplate')
1427
            ->will($this->returnCallback(function () use ($type) {
1428
                switch ($type) {
1429
                    case 'boolean':
1430
                        return '@SonataAdmin/CRUD/show_boolean.html.twig';
1431
                    case 'datetime':
1432
                        return '@SonataAdmin/CRUD/show_datetime.html.twig';
1433
                    case 'date':
1434
                        return '@SonataAdmin/CRUD/show_date.html.twig';
1435
                    case 'time':
1436
                        return '@SonataAdmin/CRUD/show_time.html.twig';
1437
                    case 'currency':
1438
                        return '@SonataAdmin/CRUD/show_currency.html.twig';
1439
                    case 'percent':
1440
                        return '@SonataAdmin/CRUD/show_percent.html.twig';
1441
                    case 'email':
1442
                        return '@SonataAdmin/CRUD/show_email.html.twig';
1443
                    case 'choice':
1444
                        return '@SonataAdmin/CRUD/show_choice.html.twig';
1445
                    case 'array':
1446
                        return '@SonataAdmin/CRUD/show_array.html.twig';
1447
                    case 'trans':
1448
                        return '@SonataAdmin/CRUD/show_trans.html.twig';
1449
                    case 'url':
1450
                        return '@SonataAdmin/CRUD/show_url.html.twig';
1451
                    case 'html':
1452
                        return '@SonataAdmin/CRUD/show_html.html.twig';
1453
                    default:
1454
                        return false;
1455
                }
1456
            }));
1457
1458
        $this->assertSame(
1459
                $this->removeExtraWhitespace($expected),
1460
                $this->removeExtraWhitespace(
1461
                    $this->twigExtension->renderViewElement(
1462
                        $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...
1463
                        $this->fieldDescription,
1464
                        $this->object
1465
                    )
1466
                )
1467
            );
1468
    }
1469
1470
    public function getRenderViewElementTests()
1471
    {
1472
        return [
1473
            ['<th>Data</th> <td>Example</td>', 'string', 'Example', ['safe' => false]],
1474
            ['<th>Data</th> <td>Example</td>', 'text', 'Example', ['safe' => false]],
1475
            ['<th>Data</th> <td>Example</td>', 'textarea', 'Example', ['safe' => false]],
1476
            [
1477
                '<th>Data</th> <td>December 24, 2013 10:11</td>',
1478
                'datetime',
1479
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')), [],
1480
            ],
1481
            [
1482
                '<th>Data</th> <td>24.12.2013 10:11:12</td>',
1483
                'datetime',
1484
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1485
                ['format' => 'd.m.Y H:i:s'],
1486
            ],
1487
            [
1488
                '<th>Data</th> <td>December 24, 2013 18:11</td>',
1489
                'datetime',
1490
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1491
                ['timezone' => 'Asia/Hong_Kong'],
1492
            ],
1493
            [
1494
                '<th>Data</th> <td>December 24, 2013</td>',
1495
                'date',
1496
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1497
                [],
1498
            ],
1499
            [
1500
                '<th>Data</th> <td>24.12.2013</td>',
1501
                'date',
1502
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1503
                ['format' => 'd.m.Y'],
1504
            ],
1505
            [
1506
                '<th>Data</th> <td>10:11:12</td>',
1507
                'time',
1508
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('Europe/London')),
1509
                [],
1510
            ],
1511
            [
1512
                '<th>Data</th> <td>18:11:12</td>',
1513
                'time',
1514
                new \DateTime('2013-12-24 10:11:12', new \DateTimeZone('UTC')),
1515
                ['timezone' => 'Asia/Hong_Kong'],
1516
            ],
1517
            ['<th>Data</th> <td>10.746135</td>', 'number', 10.746135, ['safe' => false]],
1518
            ['<th>Data</th> <td>5678</td>', 'integer', 5678, ['safe' => false]],
1519
            ['<th>Data</th> <td> 1074.6135 % </td>', 'percent', 10.746135, []],
1520
            ['<th>Data</th> <td> EUR 10.746135 </td>', 'currency', 10.746135, ['currency' => 'EUR']],
1521
            ['<th>Data</th> <td> GBP 51.23456 </td>', 'currency', 51.23456, ['currency' => 'GBP']],
1522
            [
1523
                '<th>Data</th> <td> [1 => First] <br> [2 => Second] </td>',
1524
                'array',
1525
                [1 => 'First', 2 => 'Second'],
1526
                ['safe' => false],
1527
            ],
1528
            [
1529
                '<th>Data</th> <td> [1 => First] [2 => Second] </td>',
1530
                'array',
1531
                [1 => 'First', 2 => 'Second'],
1532
                ['safe' => false, 'inline' => true],
1533
            ],
1534
            [
1535
                '<th>Data</th> <td><span class="label label-success">yes</span></td>',
1536
                'boolean',
1537
                true,
1538
                [],
1539
            ],
1540
            [
1541
                '<th>Data</th> <td><span class="label label-danger">yes</span></td>',
1542
                'boolean',
1543
                true,
1544
                ['inverse' => true],
1545
            ],
1546
            ['<th>Data</th> <td><span class="label label-danger">no</span></td>', 'boolean', false, []],
1547
            [
1548
                '<th>Data</th> <td><span class="label label-success">no</span></td>',
1549
                'boolean',
1550
                false,
1551
                ['inverse' => true],
1552
            ],
1553
            [
1554
                '<th>Data</th> <td> Delete </td>',
1555
                'trans',
1556
                'action_delete',
1557
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1558
            ],
1559
            ['<th>Data</th> <td>Status1</td>', 'choice', 'Status1', ['safe' => false]],
1560
            [
1561
                '<th>Data</th> <td>Alias1</td>',
1562
                'choice',
1563
                'Status1',
1564
                ['safe' => false, 'choices' => [
1565
                    'Status1' => 'Alias1',
1566
                    'Status2' => 'Alias2',
1567
                    'Status3' => 'Alias3',
1568
                ]],
1569
            ],
1570
            [
1571
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1572
                'choice',
1573
                'NoValidKeyInChoices',
1574
                ['safe' => false, 'choices' => [
1575
                    'Status1' => 'Alias1',
1576
                    'Status2' => 'Alias2',
1577
                    'Status3' => 'Alias3',
1578
                ]],
1579
            ],
1580
            [
1581
                '<th>Data</th> <td>Delete</td>',
1582
                'choice',
1583
                'Foo',
1584
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1585
                    'Foo' => 'action_delete',
1586
                    'Status2' => 'Alias2',
1587
                    'Status3' => 'Alias3',
1588
                ]],
1589
            ],
1590
            [
1591
                '<th>Data</th> <td>NoValidKeyInChoices</td>',
1592
                'choice',
1593
                ['NoValidKeyInChoices'],
1594
                ['safe' => false, 'choices' => [
1595
                    'Status1' => 'Alias1',
1596
                    'Status2' => 'Alias2',
1597
                    'Status3' => 'Alias3',
1598
                ], 'multiple' => true],
1599
            ],
1600
            [
1601
                '<th>Data</th> <td>NoValidKeyInChoices, Alias2</td>',
1602
                'choice',
1603
                ['NoValidKeyInChoices', 'Status2'],
1604
                ['safe' => false, 'choices' => [
1605
                    'Status1' => 'Alias1',
1606
                    'Status2' => 'Alias2',
1607
                    'Status3' => 'Alias3',
1608
                ], 'multiple' => true],
1609
            ],
1610
            [
1611
                '<th>Data</th> <td>Alias1, Alias3</td>',
1612
                'choice',
1613
                ['Status1', 'Status3'],
1614
                ['safe' => false, 'choices' => [
1615
                    'Status1' => 'Alias1',
1616
                    'Status2' => 'Alias2',
1617
                    'Status3' => 'Alias3',
1618
                ], 'multiple' => true],
1619
            ],
1620
            [
1621
                '<th>Data</th> <td>Alias1 | Alias3</td>',
1622
                'choice',
1623
                ['Status1', 'Status3'], ['safe' => false, 'choices' => [
1624
                    'Status1' => 'Alias1',
1625
                    'Status2' => 'Alias2',
1626
                    'Status3' => 'Alias3',
1627
                ], 'multiple' => true, 'delimiter' => ' | '],
1628
            ],
1629
            [
1630
                '<th>Data</th> <td>Delete, Alias3</td>',
1631
                'choice',
1632
                ['Foo', 'Status3'],
1633
                ['safe' => false, 'catalogue' => 'SonataAdminBundle', 'choices' => [
1634
                    'Foo' => 'action_delete',
1635
                    'Status2' => 'Alias2',
1636
                    'Status3' => 'Alias3',
1637
                ], 'multiple' => true],
1638
            ],
1639
            [
1640
                '<th>Data</th> <td><b>Alias1</b>, <b>Alias3</b></td>',
1641
                'choice',
1642
                ['Status1', 'Status3'],
1643
                ['safe' => true, 'choices' => [
1644
                    'Status1' => '<b>Alias1</b>',
1645
                    'Status2' => '<b>Alias2</b>',
1646
                    'Status3' => '<b>Alias3</b>',
1647
                ], 'multiple' => true],
1648
            ],
1649
            [
1650
                '<th>Data</th> <td>&lt;b&gt;Alias1&lt;/b&gt;, &lt;b&gt;Alias3&lt;/b&gt;</td>',
1651
                'choice',
1652
                ['Status1', 'Status3'],
1653
                ['safe' => false, 'choices' => [
1654
                    'Status1' => '<b>Alias1</b>',
1655
                    'Status2' => '<b>Alias2</b>',
1656
                    'Status3' => '<b>Alias3</b>',
1657
                ], 'multiple' => true],
1658
            ],
1659
            [
1660
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1661
                'url',
1662
                'http://example.com',
1663
                ['safe' => false],
1664
            ],
1665
            [
1666
                '<th>Data</th> <td><a href="http://example.com" target="_blank">http://example.com</a></td>',
1667
                'url',
1668
                'http://example.com',
1669
                ['safe' => false, 'attributes' => ['target' => '_blank']],
1670
            ],
1671
            [
1672
                '<th>Data</th> <td><a href="http://example.com" target="_blank" class="fooLink">http://example.com</a></td>',
1673
                'url',
1674
                'http://example.com',
1675
                ['safe' => false, 'attributes' => ['target' => '_blank', 'class' => 'fooLink']],
1676
            ],
1677
            [
1678
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1679
                'url',
1680
                'https://example.com',
1681
                ['safe' => false],
1682
            ],
1683
            [
1684
                '<th>Data</th> <td><a href="http://example.com">example.com</a></td>',
1685
                'url',
1686
                'http://example.com',
1687
                ['safe' => false, 'hide_protocol' => true],
1688
            ],
1689
            [
1690
                '<th>Data</th> <td><a href="https://example.com">example.com</a></td>',
1691
                'url',
1692
                'https://example.com',
1693
                ['safe' => false, 'hide_protocol' => true],
1694
            ],
1695
            [
1696
                '<th>Data</th> <td><a href="http://example.com">http://example.com</a></td>',
1697
                'url',
1698
                'http://example.com',
1699
                ['safe' => false, 'hide_protocol' => false],
1700
            ],
1701
            [
1702
                '<th>Data</th> <td><a href="https://example.com">https://example.com</a></td>',
1703
                'url',
1704
                'https://example.com',
1705
                ['safe' => false,
1706
                'hide_protocol' => false, ],
1707
            ],
1708
            [
1709
                '<th>Data</th> <td><a href="http://example.com">Foo</a></td>',
1710
                'url',
1711
                'Foo',
1712
                ['safe' => false, 'url' => 'http://example.com'],
1713
            ],
1714
            [
1715
                '<th>Data</th> <td><a href="http://example.com">&lt;b&gt;Foo&lt;/b&gt;</a></td>',
1716
                'url',
1717
                '<b>Foo</b>',
1718
                ['safe' => false, 'url' => 'http://example.com'],
1719
            ],
1720
            [
1721
                '<th>Data</th> <td><a href="http://example.com"><b>Foo</b></a></td>',
1722
                'url',
1723
                '<b>Foo</b>',
1724
                ['safe' => true, 'url' => 'http://example.com'],
1725
            ],
1726
            [
1727
                '<th>Data</th> <td><a href="/foo">Foo</a></td>',
1728
                'url',
1729
                'Foo',
1730
                ['safe' => false, 'route' => ['name' => 'sonata_admin_foo']],
1731
            ],
1732
            [
1733
                '<th>Data</th> <td><a href="http://localhost/foo">Foo</a></td>',
1734
                'url',
1735
                'Foo',
1736
                ['safe' => false, 'route' => [
1737
                    'name' => 'sonata_admin_foo',
1738
                    'absolute' => true,
1739
                ]],
1740
            ],
1741
            [
1742
                '<th>Data</th> <td><a href="/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1743
                'url',
1744
                'http://foo/bar?a=b&c=123456789',
1745
                [
1746
                    'safe' => false,
1747
                    'route' => ['name' => 'sonata_admin_foo'],
1748
                    'hide_protocol' => true,
1749
                ],
1750
            ],
1751
            [
1752
                '<th>Data</th> <td><a href="http://localhost/foo">foo/bar?a=b&amp;c=123456789</a></td>',
1753
                'url',
1754
                'http://foo/bar?a=b&c=123456789',
1755
                ['safe' => false, 'route' => [
1756
                    'name' => 'sonata_admin_foo',
1757
                    'absolute' => true,
1758
                ], 'hide_protocol' => true],
1759
            ],
1760
            [
1761
                '<th>Data</th> <td><a href="/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1762
                'url',
1763
                'Foo',
1764
                ['safe' => false, 'route' => [
1765
                    'name' => 'sonata_admin_foo_param',
1766
                    'parameters' => ['param1' => 'abcd', 'param2' => 'efgh', 'param3' => 'ijkl'],
1767
                ]],
1768
            ],
1769
            [
1770
                '<th>Data</th> <td><a href="http://localhost/foo/abcd/efgh?param3=ijkl">Foo</a></td>',
1771
                'url',
1772
                'Foo',
1773
                ['safe' => false, 'route' => [
1774
                    'name' => 'sonata_admin_foo_param',
1775
                    'absolute' => true,
1776
                    'parameters' => [
1777
                        'param1' => 'abcd',
1778
                        'param2' => 'efgh',
1779
                        'param3' => 'ijkl',
1780
                    ],
1781
                ]],
1782
            ],
1783
            [
1784
                '<th>Data</th> <td><a href="/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1785
                'url',
1786
                'Foo',
1787
                ['safe' => false, 'route' => [
1788
                    'name' => 'sonata_admin_foo_object',
1789
                    'parameters' => [
1790
                        'param1' => 'abcd',
1791
                        'param2' => 'efgh',
1792
                        'param3' => 'ijkl',
1793
                    ],
1794
                    'identifier_parameter_name' => 'barId',
1795
                ]],
1796
            ],
1797
            [
1798
                '<th>Data</th> <td><a href="http://localhost/foo/obj/abcd/12345/efgh?param3=ijkl">Foo</a></td>',
1799
                'url',
1800
                'Foo',
1801
                ['safe' => false, 'route' => [
1802
                    'name' => 'sonata_admin_foo_object',
1803
                    'absolute' => true,
1804
                    'parameters' => [
1805
                        'param1' => 'abcd',
1806
                        'param2' => 'efgh',
1807
                        'param3' => 'ijkl',
1808
                    ],
1809
                    'identifier_parameter_name' => 'barId',
1810
                ]],
1811
            ],
1812
            [
1813
                '<th>Data</th> <td> &nbsp;</td>',
1814
                'email',
1815
                null,
1816
                [],
1817
            ],
1818
            [
1819
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1820
                'email',
1821
                '[email protected]',
1822
                [],
1823
            ],
1824
            [
1825
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme', 'body' => 'Message Body']).'">[email protected]</a></td>',
1826
                'email',
1827
                '[email protected]',
1828
                ['subject' => 'Main Theme', 'body' => 'Message Body'],
1829
            ],
1830
            [
1831
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['subject' => 'Main Theme']).'">[email protected]</a></td>',
1832
                'email',
1833
                '[email protected]',
1834
                ['subject' => 'Main Theme'],
1835
            ],
1836
            [
1837
                '<th>Data</th> <td> <a href="mailto:[email protected]?'.$this->buildTwigLikeUrl(['body' => 'Message Body']).'">[email protected]</a></td>',
1838
                'email',
1839
                '[email protected]',
1840
                ['body' => 'Message Body'],
1841
            ],
1842
            [
1843
                '<th>Data</th> <td> [email protected]</td>',
1844
                'email',
1845
                '[email protected]',
1846
                ['as_string' => true, 'subject' => 'Main Theme', 'body' => 'Message Body'],
1847
            ],
1848
            [
1849
                '<th>Data</th> <td> [email protected]</td>',
1850
                'email',
1851
                '[email protected]',
1852
                ['as_string' => true, 'subject' => 'Main Theme'],
1853
            ],
1854
            [
1855
                '<th>Data</th> <td> [email protected]</td>',
1856
                'email',
1857
                '[email protected]',
1858
                ['as_string' => true, 'body' => 'Message Body'],
1859
            ],
1860
            [
1861
                '<th>Data</th> <td> <a href="mailto:[email protected]">[email protected]</a></td>',
1862
                'email',
1863
                '[email protected]',
1864
                ['as_string' => false],
1865
            ],
1866
            [
1867
                '<th>Data</th> <td> [email protected]</td>',
1868
                'email',
1869
                '[email protected]',
1870
                ['as_string' => true],
1871
            ],
1872
            [
1873
                '<th>Data</th> <td><p><strong>Creating a Template for the Field</strong> and form</p> </td>',
1874
                'html',
1875
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1876
                [],
1877
            ],
1878
            [
1879
                '<th>Data</th> <td>Creating a Template for the Field and form </td>',
1880
                'html',
1881
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1882
                ['strip' => true],
1883
            ],
1884
            [
1885
                '<th>Data</th> <td> Creating a Template for the Fi... </td>',
1886
                'html',
1887
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1888
                ['truncate' => true],
1889
            ],
1890
            [
1891
                '<th>Data</th> <td> Creating a... </td>',
1892
                'html',
1893
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1894
                ['truncate' => ['length' => 10]],
1895
            ],
1896
            [
1897
                '<th>Data</th> <td> Creating a Template for the Field... </td>',
1898
                'html',
1899
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1900
                ['truncate' => ['preserve' => true]],
1901
            ],
1902
            [
1903
                '<th>Data</th> <td> Creating a Template for the Fi etc. </td>',
1904
                'html',
1905
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1906
                ['truncate' => ['separator' => ' etc.']],
1907
            ],
1908
            [
1909
                '<th>Data</th> <td> Creating a Template for[...] </td>',
1910
                'html',
1911
                '<p><strong>Creating a Template for the Field</strong> and form</p>',
1912
                [
1913
                    'truncate' => [
1914
                        'length' => 20,
1915
                        'preserve' => true,
1916
                        'separator' => '[...]',
1917
                    ],
1918
                ],
1919
            ],
1920
1921
            // NoValueException
1922
            ['<th>Data</th> <td></td>', 'string', new NoValueException(), ['safe' => false]],
1923
            ['<th>Data</th> <td></td>', 'text', new NoValueException(), ['safe' => false]],
1924
            ['<th>Data</th> <td></td>', 'textarea', new NoValueException(), ['safe' => false]],
1925
            ['<th>Data</th> <td>&nbsp;</td>', 'datetime', new NoValueException(), []],
1926
            [
1927
                '<th>Data</th> <td>&nbsp;</td>',
1928
                'datetime',
1929
                new NoValueException(),
1930
                ['format' => 'd.m.Y H:i:s'],
1931
            ],
1932
            ['<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), []],
1933
            ['<th>Data</th> <td>&nbsp;</td>', 'date', new NoValueException(), ['format' => 'd.m.Y']],
1934
            ['<th>Data</th> <td>&nbsp;</td>', 'time', new NoValueException(), []],
1935
            ['<th>Data</th> <td></td>', 'number', new NoValueException(), ['safe' => false]],
1936
            ['<th>Data</th> <td></td>', 'integer', new NoValueException(), ['safe' => false]],
1937
            ['<th>Data</th> <td> 0 % </td>', 'percent', new NoValueException(), []],
1938
            ['<th>Data</th> <td> </td>', 'currency', new NoValueException(), ['currency' => 'EUR']],
1939
            ['<th>Data</th> <td> </td>', 'currency', new NoValueException(), ['currency' => 'GBP']],
1940
            ['<th>Data</th> <td> </td>', 'array', new NoValueException(), ['safe' => false]],
1941
            [
1942
                '<th>Data</th> <td><span class="label label-danger">no</span></td>',
1943
                'boolean',
1944
                new NoValueException(),
1945
                [],
1946
            ],
1947
            [
1948
                '<th>Data</th> <td> </td>',
1949
                'trans',
1950
                new NoValueException(),
1951
                ['safe' => false, 'catalogue' => 'SonataAdminBundle'],
1952
            ],
1953
            [
1954
                '<th>Data</th> <td></td>',
1955
                'choice',
1956
                new NoValueException(),
1957
                ['safe' => false, 'choices' => []],
1958
            ],
1959
            [
1960
                '<th>Data</th> <td></td>',
1961
                'choice',
1962
                new NoValueException(),
1963
                ['safe' => false, 'choices' => [], 'multiple' => true],
1964
            ],
1965
            ['<th>Data</th> <td>&nbsp;</td>', 'url', new NoValueException(), []],
1966
            [
1967
                '<th>Data</th> <td>&nbsp;</td>',
1968
                'url',
1969
                new NoValueException(),
1970
                ['url' => 'http://example.com'],
1971
            ],
1972
            [
1973
                '<th>Data</th> <td>&nbsp;</td>',
1974
                'url',
1975
                new NoValueException(),
1976
                ['route' => ['name' => 'sonata_admin_foo']],
1977
            ],
1978
1979
            [
1980
                <<<'EOT'
1981
<th>Data</th> <td><div
1982
        class="sonata-readmore"
1983
        data-readmore-height="40"
1984
        data-readmore-more="Read more"
1985
        data-readmore-less="Close">
1986
            A very long string
1987
</div></td>
1988
EOT
1989
                ,
1990
                'text',
1991
                ' A very long string ',
1992
                [
1993
                    'collapse' => true,
1994
                    'safe' => false,
1995
                ],
1996
            ],
1997
            [
1998
                <<<'EOT'
1999
<th>Data</th> <td><div
2000
        class="sonata-readmore"
2001
        data-readmore-height="10"
2002
        data-readmore-more="More"
2003
        data-readmore-less="Less">
2004
            A very long string
2005
</div></td>
2006
EOT
2007
                ,
2008
                'text',
2009
                ' A very long string ',
2010
                [
2011
                    'collapse' => [
2012
                        'height' => 10,
2013
                        'more' => 'More',
2014
                        'less' => 'Less',
2015
                    ],
2016
                    'safe' => false,
2017
                ],
2018
            ],
2019
        ];
2020
    }
2021
2022
    public function testGetValueFromFieldDescription()
2023
    {
2024
        $object = new \stdClass();
2025
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2026
2027
        $fieldDescription->expects($this->any())
2028
            ->method('getValue')
2029
            ->will($this->returnValue('test123'));
2030
2031
        $this->assertSame('test123', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2032
    }
2033
2034
    public function testGetValueFromFieldDescriptionWithRemoveLoopException()
2035
    {
2036
        $object = $this->createMock(\ArrayAccess::class);
2037
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2038
2039
        $this->expectException(\RuntimeException::class, 'remove the loop requirement');
2040
2041
        $this->assertSame(
2042
            'anything',
2043
            $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription, ['loop' => true])
2044
        );
2045
    }
2046
2047
    public function testGetValueFromFieldDescriptionWithNoValueException()
2048
    {
2049
        $object = new \stdClass();
2050
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2051
2052
        $fieldDescription->expects($this->any())
2053
            ->method('getValue')
2054
            ->will($this->returnCallback(function () {
2055
                throw new NoValueException();
2056
            }));
2057
2058
        $fieldDescription->expects($this->any())
2059
            ->method('getAssociationAdmin')
2060
            ->will($this->returnValue(null));
2061
2062
        $this->assertNull($this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2063
    }
2064
2065
    public function testGetValueFromFieldDescriptionWithNoValueExceptionNewAdminInstance()
2066
    {
2067
        $object = new \stdClass();
2068
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2069
2070
        $fieldDescription->expects($this->any())
2071
            ->method('getValue')
2072
            ->will($this->returnCallback(function () {
2073
                throw new NoValueException();
2074
            }));
2075
2076
        $fieldDescription->expects($this->any())
2077
            ->method('getAssociationAdmin')
2078
            ->will($this->returnValue($this->admin));
2079
2080
        $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...
2081
            ->method('getNewInstance')
2082
            ->will($this->returnValue('foo'));
2083
2084
        $this->assertSame('foo', $this->twigExtension->getValueFromFieldDescription($object, $fieldDescription));
2085
    }
2086
2087
    /**
2088
     * @group legacy
2089
     */
2090
    public function testOutput()
2091
    {
2092
        $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...
2093
            ->method('getTemplate')
2094
            ->will($this->returnValue('@SonataAdmin/CRUD/base_list_field.html.twig'));
2095
2096
        $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...
2097
            ->method('getFieldName')
2098
            ->will($this->returnValue('fd_name'));
2099
2100
        $this->environment->disableDebug();
2101
2102
        $parameters = [
2103
            'admin' => $this->admin,
2104
            'value' => 'foo',
2105
            'field_description' => $this->fieldDescription,
2106
            'object' => $this->object,
2107
        ];
2108
2109
        $template = $this->environment->loadTemplate('@SonataAdmin/CRUD/base_list_field.html.twig');
2110
2111
        $this->assertSame(
2112
            '<td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>',
2113
            $this->removeExtraWhitespace($this->twigExtension->output(
0 ignored issues
show
Deprecated Code introduced by
The method Sonata\AdminBundle\Twig\...dminExtension::output() has been deprecated with message: since 3.33, to be removed in 4.0. Use render instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2114
                $this->fieldDescription,
2115
                $template,
0 ignored issues
show
Compatibility introduced by
$template of type object<Twig_Template> is not a sub-type of object<Twig\Template>. It seems like you assume a child class of the class Twig_Template 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...
2116
                $parameters,
2117
                $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...
2118
            ))
2119
        );
2120
2121
        $this->environment->enableDebug();
2122
        $this->assertSame(
2123
            $this->removeExtraWhitespace(<<<'EOT'
2124
<!-- START
2125
    fieldName: fd_name
2126
    template: @SonataAdmin/CRUD/base_list_field.html.twig
2127
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
2128
-->
2129
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
2130
<!-- END - fieldName: fd_name -->
2131
EOT
2132
            ),
2133
            $this->removeExtraWhitespace(
2134
                $this->twigExtension->output($this->fieldDescription, $template, $parameters, $this->environment)
0 ignored issues
show
Compatibility introduced by
$template of type object<Twig_Template> is not a sub-type of object<Twig\Template>. It seems like you assume a child class of the class Twig_Template 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...
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...
Deprecated Code introduced by
The method Sonata\AdminBundle\Twig\...dminExtension::output() has been deprecated with message: since 3.33, to be removed in 4.0. Use render instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2135
            )
2136
        );
2137
    }
2138
2139
    /**
2140
     * @group legacy
2141
     * @expectedDeprecation The Sonata\AdminBundle\Admin\AbstractAdmin::getTemplate method is deprecated (since 3.34, will be dropped in 4.0. Use TemplateRegistry services instead).
2142
     */
2143
    public function testRenderWithDebug()
2144
    {
2145
        $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...
2146
            ->method('getTemplate')
2147
            ->will($this->returnValue('@SonataAdmin/CRUD/base_list_field.html.twig'));
2148
2149
        $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...
2150
            ->method('getFieldName')
2151
            ->will($this->returnValue('fd_name'));
2152
2153
        $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...
2154
            ->method('getValue')
2155
            ->will($this->returnValue('foo'));
2156
2157
        $parameters = [
2158
            'admin' => $this->admin,
2159
            'value' => 'foo',
2160
            'field_description' => $this->fieldDescription,
2161
            'object' => $this->object,
2162
        ];
2163
2164
        $this->environment->enableDebug();
2165
2166
        $this->assertSame(
2167
            $this->removeExtraWhitespace(<<<'EOT'
2168
<!-- START
2169
    fieldName: fd_name
2170
    template: @SonataAdmin/CRUD/base_list_field.html.twig
2171
    compiled template: @SonataAdmin/CRUD/base_list_field.html.twig
2172
-->
2173
    <td class="sonata-ba-list-field sonata-ba-list-field-" objectId="12345"> foo </td>
2174
<!-- END - fieldName: fd_name -->
2175
EOT
2176
            ),
2177
            $this->removeExtraWhitespace(
2178
                $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...
2179
            )
2180
        );
2181
    }
2182
2183
    public function testRenderRelationElementNoObject()
2184
    {
2185
        $this->assertSame('foo', $this->twigExtension->renderRelationElement('foo', $this->fieldDescription));
2186
    }
2187
2188
    public function testRenderRelationElementToString()
2189
    {
2190
        $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...
2191
            ->method('getOption')
2192
            ->will($this->returnCallback(function ($value, $default = null) {
2193
                if ('associated_property' == $value) {
2194
                    return $default;
2195
                }
2196
            }));
2197
2198
        $element = new FooToString();
2199
        $this->assertSame('salut', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2200
    }
2201
2202
    /**
2203
     * @group legacy
2204
     */
2205
    public function testDeprecatedRelationElementToString()
2206
    {
2207
        $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...
2208
            ->method('getOption')
2209
            ->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...
2210
                if ('associated_tostring' == $value) {
2211
                    return '__toString';
2212
                }
2213
            }));
2214
2215
        $element = new FooToString();
2216
        $this->assertSame(
2217
            'salut',
2218
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2219
        );
2220
    }
2221
2222
    /**
2223
     * @group legacy
2224
     */
2225
    public function testRenderRelationElementCustomToString()
2226
    {
2227
        $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...
2228
            ->method('getOption')
2229
            ->will($this->returnCallback(function ($value, $default = null) {
2230
                if ('associated_property' == $value) {
2231
                    return $default;
2232
                }
2233
2234
                if ('associated_tostring' == $value) {
2235
                    return 'customToString';
2236
                }
2237
            }));
2238
2239
        $element = $this->getMockBuilder('stdClass')
2240
            ->setMethods(['customToString'])
2241
            ->getMock();
2242
        $element->expects($this->any())
2243
            ->method('customToString')
2244
            ->will($this->returnValue('fooBar'));
2245
2246
        $this->assertSame('fooBar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2247
    }
2248
2249
    /**
2250
     * @group legacy
2251
     */
2252
    public function testRenderRelationElementMethodNotExist()
2253
    {
2254
        $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...
2255
            ->method('getOption')
2256
2257
            ->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...
2258
                if ('associated_tostring' == $value) {
2259
                    return 'nonExistedMethod';
2260
                }
2261
            }));
2262
2263
        $element = new \stdClass();
2264
        $this->expectException(\RuntimeException::class, 'You must define an `associated_property` option or create a `stdClass::__toString');
2265
2266
        $this->twigExtension->renderRelationElement($element, $this->fieldDescription);
2267
    }
2268
2269
    public function testRenderRelationElementWithPropertyPath()
2270
    {
2271
        $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...
2272
            ->method('getOption')
2273
2274
            ->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...
2275
                if ('associated_property' == $value) {
2276
                    return 'foo';
2277
                }
2278
            }));
2279
2280
        $element = new \stdClass();
2281
        $element->foo = 'bar';
2282
2283
        $this->assertSame('bar', $this->twigExtension->renderRelationElement($element, $this->fieldDescription));
2284
    }
2285
2286
    public function testRenderRelationElementWithClosure()
2287
    {
2288
        $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...
2289
            ->method('getOption')
2290
2291
            ->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...
2292
                if ('associated_property' == $value) {
2293
                    return function ($element) {
2294
                        return 'closure '.$element->foo;
2295
                    };
2296
                }
2297
            }));
2298
2299
        $element = new \stdClass();
2300
        $element->foo = 'bar';
2301
2302
        $this->assertSame(
2303
            'closure bar',
2304
            $this->twigExtension->renderRelationElement($element, $this->fieldDescription)
2305
        );
2306
    }
2307
2308
    public function testGetUrlsafeIdentifier()
2309
    {
2310
        $entity = new \stdClass();
2311
2312
        // set admin to pool
2313
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service']);
2314
        $this->pool->setAdminClasses(['stdClass' => ['sonata_admin_foo_service']]);
2315
2316
        $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...
2317
            ->method('getUrlsafeIdentifier')
2318
            ->with($this->equalTo($entity))
2319
            ->will($this->returnValue(1234567));
2320
2321
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity));
2322
    }
2323
2324
    public function testGetUrlsafeIdentifier_GivenAdmin_Foo()
0 ignored issues
show
Coding Style introduced by
Method name "SonataAdminExtensionTest::testGetUrlsafeIdentifier_GivenAdmin_Foo" is not in camel caps format
Loading history...
2325
    {
2326
        $entity = new \stdClass();
2327
2328
        // set admin to pool
2329
        $this->pool->setAdminServiceIds([
2330
            'sonata_admin_foo_service',
2331
            'sonata_admin_bar_service',
2332
        ]);
2333
        $this->pool->setAdminClasses(['stdClass' => [
2334
            'sonata_admin_foo_service',
2335
            'sonata_admin_bar_service',
2336
        ]]);
2337
2338
        $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...
2339
            ->method('getUrlsafeIdentifier')
2340
            ->with($this->equalTo($entity))
2341
            ->will($this->returnValue(1234567));
2342
2343
        $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...
2344
            ->method('getUrlsafeIdentifier');
2345
2346
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->admin));
2347
    }
2348
2349
    public function testGetUrlsafeIdentifier_GivenAdmin_Bar()
0 ignored issues
show
Coding Style introduced by
Method name "SonataAdminExtensionTest::testGetUrlsafeIdentifier_GivenAdmin_Bar" is not in camel caps format
Loading history...
2350
    {
2351
        $entity = new \stdClass();
2352
2353
        // set admin to pool
2354
        $this->pool->setAdminServiceIds(['sonata_admin_foo_service', 'sonata_admin_bar_service']);
2355
        $this->pool->setAdminClasses(['stdClass' => [
2356
            'sonata_admin_foo_service',
2357
            'sonata_admin_bar_service',
2358
        ]]);
2359
2360
        $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...
2361
            ->method('getUrlsafeIdentifier');
2362
2363
        $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...
2364
            ->method('getUrlsafeIdentifier')
2365
            ->with($this->equalTo($entity))
2366
            ->will($this->returnValue(1234567));
2367
2368
        $this->assertSame(1234567, $this->twigExtension->getUrlsafeIdentifier($entity, $this->adminBar));
2369
    }
2370
2371
    public function xEditableChoicesProvider()
2372
    {
2373
        return [
2374
            'needs processing' => [
2375
                ['choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2']],
2376
                [
2377
                    ['value' => 'Status1', 'text' => 'Alias1'],
2378
                    ['value' => 'Status2', 'text' => 'Alias2'],
2379
                ],
2380
            ],
2381
            'already processed' => [
2382
                ['choices' => [
2383
                    ['value' => 'Status1', 'text' => 'Alias1'],
2384
                    ['value' => 'Status2', 'text' => 'Alias2'],
2385
                ]],
2386
                [
2387
                    ['value' => 'Status1', 'text' => 'Alias1'],
2388
                    ['value' => 'Status2', 'text' => 'Alias2'],
2389
                ],
2390
            ],
2391
            'not required' => [
2392
                [
2393
                    'required' => false,
2394
                    'choices' => ['' => '', 'Status1' => 'Alias1', 'Status2' => 'Alias2'],
2395
                ],
2396
                [
2397
                    ['value' => '', 'text' => ''],
2398
                    ['value' => 'Status1', 'text' => 'Alias1'],
2399
                    ['value' => 'Status2', 'text' => 'Alias2'],
2400
                ],
2401
            ],
2402
            'not required multiple' => [
2403
                [
2404
                    'required' => false,
2405
                    'multiple' => true,
2406
                    'choices' => ['Status1' => 'Alias1', 'Status2' => 'Alias2'],
2407
                ],
2408
                [
2409
                    ['value' => 'Status1', 'text' => 'Alias1'],
2410
                    ['value' => 'Status2', 'text' => 'Alias2'],
2411
                ],
2412
            ],
2413
        ];
2414
    }
2415
2416
    /**
2417
     * @dataProvider xEditablechoicesProvider
2418
     */
2419
    public function testGetXEditableChoicesIsIdempotent(array $options, $expectedChoices)
2420
    {
2421
        $fieldDescription = $this->getMockForAbstractClass(FieldDescriptionInterface::class);
2422
        $fieldDescription->expects($this->any())
2423
            ->method('getOption')
2424
            ->withConsecutive(
2425
                ['choices', []],
2426
                ['catalogue'],
2427
                ['required'],
2428
                ['multiple']
2429
            )
2430
            ->will($this->onConsecutiveCalls(
2431
                $options['choices'],
2432
                'MyCatalogue',
2433
                $options['multiple'] ?? null
2434
            ));
2435
2436
        $this->assertSame($expectedChoices, $this->twigExtension->getXEditableChoices($fieldDescription));
2437
    }
2438
2439
    public function select2LocalesProvider()
2440
    {
2441
        return [
2442
            ['ar', 'ar'],
2443
            ['az', 'az'],
2444
            ['bg', 'bg'],
2445
            ['ca', 'ca'],
2446
            ['cs', 'cs'],
2447
            ['da', 'da'],
2448
            ['de', 'de'],
2449
            ['el', 'el'],
2450
            [null, 'en'],
2451
            ['es', 'es'],
2452
            ['et', 'et'],
2453
            ['eu', 'eu'],
2454
            ['fa', 'fa'],
2455
            ['fi', 'fi'],
2456
            ['fr', 'fr'],
2457
            ['gl', 'gl'],
2458
            ['he', 'he'],
2459
            ['hr', 'hr'],
2460
            ['hu', 'hu'],
2461
            ['id', 'id'],
2462
            ['is', 'is'],
2463
            ['it', 'it'],
2464
            ['ja', 'ja'],
2465
            ['ka', 'ka'],
2466
            ['ko', 'ko'],
2467
            ['lt', 'lt'],
2468
            ['lv', 'lv'],
2469
            ['mk', 'mk'],
2470
            ['ms', 'ms'],
2471
            ['nb', 'nb'],
2472
            ['nl', 'nl'],
2473
            ['pl', 'pl'],
2474
            ['pt-PT', 'pt'],
2475
            ['pt-BR', 'pt-BR'],
2476
            ['pt-PT', 'pt-PT'],
2477
            ['ro', 'ro'],
2478
            ['rs', 'rs'],
2479
            ['ru', 'ru'],
2480
            ['sk', 'sk'],
2481
            ['sv', 'sv'],
2482
            ['th', 'th'],
2483
            ['tr', 'tr'],
2484
            ['ug-CN', 'ug'],
2485
            ['ug-CN', 'ug-CN'],
2486
            ['uk', 'uk'],
2487
            ['vi', 'vi'],
2488
            ['zh-CN', 'zh'],
2489
            ['zh-CN', 'zh-CN'],
2490
            ['zh-TW', 'zh-TW'],
2491
        ];
2492
    }
2493
2494
    /**
2495
     * @dataProvider select2LocalesProvider
2496
     */
2497
    public function testCanonicalizedLocaleForSelect2($expected, $original)
2498
    {
2499
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForSelect2($this->mockExtensionContext($original)));
2500
    }
2501
2502
    public function momentLocalesProvider()
2503
    {
2504
        return [
2505
            ['af', 'af'],
2506
            ['ar-dz', 'ar-dz'],
2507
            ['ar', 'ar'],
2508
            ['ar-ly', 'ar-ly'],
2509
            ['ar-ma', 'ar-ma'],
2510
            ['ar-sa', 'ar-sa'],
2511
            ['ar-tn', 'ar-tn'],
2512
            ['az', 'az'],
2513
            ['be', 'be'],
2514
            ['bg', 'bg'],
2515
            ['bn', 'bn'],
2516
            ['bo', 'bo'],
2517
            ['br', 'br'],
2518
            ['bs', 'bs'],
2519
            ['ca', 'ca'],
2520
            ['cs', 'cs'],
2521
            ['cv', 'cv'],
2522
            ['cy', 'cy'],
2523
            ['da', 'da'],
2524
            ['de-at', 'de-at'],
2525
            ['de', 'de'],
2526
            ['dv', 'dv'],
2527
            ['el', 'el'],
2528
            [null, 'en'],
2529
            [null, 'en-us'],
2530
            ['en-au', 'en-au'],
2531
            ['en-ca', 'en-ca'],
2532
            ['en-gb', 'en-gb'],
2533
            ['en-ie', 'en-ie'],
2534
            ['en-nz', 'en-nz'],
2535
            ['eo', 'eo'],
2536
            ['es-do', 'es-do'],
2537
            ['es', 'es-ar'],
2538
            ['es', 'es-mx'],
2539
            ['es', 'es'],
2540
            ['et', 'et'],
2541
            ['eu', 'eu'],
2542
            ['fa', 'fa'],
2543
            ['fi', 'fi'],
2544
            ['fo', 'fo'],
2545
            ['fr-ca', 'fr-ca'],
2546
            ['fr-ch', 'fr-ch'],
2547
            ['fr', 'fr-fr'],
2548
            ['fr', 'fr'],
2549
            ['fy', 'fy'],
2550
            ['gd', 'gd'],
2551
            ['gl', 'gl'],
2552
            ['he', 'he'],
2553
            ['hi', 'hi'],
2554
            ['hr', 'hr'],
2555
            ['hu', 'hu'],
2556
            ['hy-am', 'hy-am'],
2557
            ['id', 'id'],
2558
            ['is', 'is'],
2559
            ['it', 'it'],
2560
            ['ja', 'ja'],
2561
            ['jv', 'jv'],
2562
            ['ka', 'ka'],
2563
            ['kk', 'kk'],
2564
            ['km', 'km'],
2565
            ['ko', 'ko'],
2566
            ['ky', 'ky'],
2567
            ['lb', 'lb'],
2568
            ['lo', 'lo'],
2569
            ['lt', 'lt'],
2570
            ['lv', 'lv'],
2571
            ['me', 'me'],
2572
            ['mi', 'mi'],
2573
            ['mk', 'mk'],
2574
            ['ml', 'ml'],
2575
            ['mr', 'mr'],
2576
            ['ms', 'ms'],
2577
            ['ms-my', 'ms-my'],
2578
            ['my', 'my'],
2579
            ['nb', 'nb'],
2580
            ['ne', 'ne'],
2581
            ['nl-be', 'nl-be'],
2582
            ['nl', 'nl'],
2583
            ['nl', 'nl-nl'],
2584
            ['nn', 'nn'],
2585
            ['pa-in', 'pa-in'],
2586
            ['pl', 'pl'],
2587
            ['pt-br', 'pt-br'],
2588
            ['pt', 'pt'],
2589
            ['ro', 'ro'],
2590
            ['ru', 'ru'],
2591
            ['se', 'se'],
2592
            ['si', 'si'],
2593
            ['sk', 'sk'],
2594
            ['sl', 'sl'],
2595
            ['sq', 'sq'],
2596
            ['sr-cyrl', 'sr-cyrl'],
2597
            ['sr', 'sr'],
2598
            ['ss', 'ss'],
2599
            ['sv', 'sv'],
2600
            ['sw', 'sw'],
2601
            ['ta', 'ta'],
2602
            ['te', 'te'],
2603
            ['tet', 'tet'],
2604
            ['th', 'th'],
2605
            ['tlh', 'tlh'],
2606
            ['tl-ph', 'tl-ph'],
2607
            ['tr', 'tr'],
2608
            ['tzl', 'tzl'],
2609
            ['tzm', 'tzm'],
2610
            ['tzm-latn', 'tzm-latn'],
2611
            ['uk', 'uk'],
2612
            ['uz', 'uz'],
2613
            ['vi', 'vi'],
2614
            ['x-pseudo', 'x-pseudo'],
2615
            ['yo', 'yo'],
2616
            ['zh-cn', 'zh-cn'],
2617
            ['zh-hk', 'zh-hk'],
2618
            ['zh-tw', 'zh-tw'],
2619
        ];
2620
    }
2621
2622
    /**
2623
     * @dataProvider momentLocalesProvider
2624
     */
2625
    public function testCanonicalizedLocaleForMoment($expected, $original)
2626
    {
2627
        $this->assertSame($expected, $this->twigExtension->getCanonicalizedLocaleForMoment($this->mockExtensionContext($original)));
2628
    }
2629
2630
    public function testIsGrantedAffirmative()
2631
    {
2632
        $this->assertTrue(
2633
            $this->twigExtension->isGrantedAffirmative(['foo', 'bar'])
2634
        );
2635
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('foo'));
2636
        $this->assertTrue($this->twigExtension->isGrantedAffirmative('bar'));
2637
    }
2638
2639
    /**
2640
     * This method generates url part for Twig layout.
2641
     *
2642
     * @param array $url
2643
     *
2644
     * @return string
2645
     */
2646
    private function buildTwigLikeUrl($url)
2647
    {
2648
        return htmlspecialchars(http_build_query($url, '', '&', PHP_QUERY_RFC3986));
2649
    }
2650
2651
    private function removeExtraWhitespace($string)
2652
    {
2653
        return trim(preg_replace(
2654
            '/\s+/',
2655
            ' ',
2656
            $string
2657
        ));
2658
    }
2659
2660
    private function mockExtensionContext($locale)
2661
    {
2662
        $request = $this->createMock(Request::class);
2663
        $request->method('getLocale')->willReturn($locale);
2664
        $appVariable = $this->createMock(AppVariable::class);
2665
        $appVariable->method('getRequest')->willReturn($request);
2666
2667
        return ['app' => $appVariable];
2668
    }
2669
}
2670