Completed
Push — 3.x ( e95e95...638cd1 )
by Oskar
05:54
created

tests/Datagrid/ListMapperTest.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Datagrid;
15
16
use PHPUnit\Framework\TestCase;
17
use Sonata\AdminBundle\Admin\AbstractAdmin;
18
use Sonata\AdminBundle\Admin\AdminInterface;
19
use Sonata\AdminBundle\Admin\BaseFieldDescription;
20
use Sonata\AdminBundle\Admin\FieldDescriptionCollection;
21
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
22
use Sonata\AdminBundle\Builder\ListBuilderInterface;
23
use Sonata\AdminBundle\Datagrid\ListMapper;
24
use Sonata\AdminBundle\Model\ModelManagerInterface;
25
use Sonata\AdminBundle\Translator\NoopLabelTranslatorStrategy;
26
27
/**
28
 * @author Andrej Hudec <[email protected]>
29
 */
30
class ListMapperTest extends TestCase
31
{
32
    private const DEFAULT_GRANTED_ROLE = 'ROLE_ADMIN_BAZ';
33
34
    /**
35
     * @var ListMapper
36
     */
37
    private $listMapper;
38
39
    /**
40
     * @var FieldDescriptionCollection
41
     */
42
    private $fieldDescriptionCollection;
43
44
    /**
45
     * @var AdminInterface
46
     */
47
    private $admin;
48
49
    protected function setUp(): void
50
    {
51
        $listBuilder = $this->createMock(ListBuilderInterface::class);
52
        $this->fieldDescriptionCollection = new FieldDescriptionCollection();
53
        $this->admin = $this->createMock(AbstractAdmin::class);
54
55
        $listBuilder->expects($this->any())
56
            ->method('addField')
57
            ->willReturnCallback(static function ($list, $type, $fieldDescription, $admin): void {
58
                $list->add($fieldDescription);
59
            });
60
61
        $modelManager = $this->createMock(ModelManagerInterface::class);
62
63
        $modelManager->expects($this->any())
64
            ->method('getNewFieldDescriptionInstance')
65
            ->willReturnCallback(function ($class, $name, array $options = []) {
66
                $fieldDescription = $this->getFieldDescriptionMock();
67
                $fieldDescription->setName($name);
68
                $fieldDescription->setOptions($options);
69
70
                return $fieldDescription;
71
            });
72
73
        $this->admin->expects($this->any())
74
            ->method('getModelManager')
75
            ->willReturn($modelManager);
76
77
        $labelTranslatorStrategy = new NoopLabelTranslatorStrategy();
78
79
        $this->admin->expects($this->any())
80
            ->method('getLabelTranslatorStrategy')
81
            ->willReturn($labelTranslatorStrategy);
82
83
        $this->admin->expects($this->any())
84
            ->method('isGranted')
85
            ->willReturnCallback(static function (string $name, object $object = null): bool {
86
                return self::DEFAULT_GRANTED_ROLE === $name;
87
            });
88
89
        $this->listMapper = new ListMapper($listBuilder, $this->fieldDescriptionCollection, $this->admin);
90
    }
91
92
    public function testFluidInterface(): void
93
    {
94
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
95
96
        $this->assertSame($this->listMapper, $this->listMapper->add($fieldDescription));
0 ignored issues
show
$fieldDescription is of type object<Sonata\AdminBundl...n\BaseFieldDescription>, but the function expects a string.

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...
97
        $this->assertSame($this->listMapper, $this->listMapper->remove('fooName'));
98
        $this->assertSame($this->listMapper, $this->listMapper->reorder([]));
99
    }
100
101
    public function testGet(): void
102
    {
103
        $this->assertFalse($this->listMapper->has('fooName'));
104
105
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
106
107
        $this->listMapper->add($fieldDescription);
108
        $this->assertSame($fieldDescription, $this->listMapper->get('fooName'));
109
    }
110
111
    public function testAddIdentifier(): void
112
    {
113
        $this->assertFalse($this->listMapper->has('fooName'));
114
115
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
116
117
        $this->listMapper->addIdentifier($fieldDescription);
118
        $this->assertTrue($this->listMapper->has('fooName'));
119
120
        $fieldDescription = $this->listMapper->get('fooName');
121
        $this->assertTrue($fieldDescription->getOption('identifier'));
122
    }
123
124
    public function testAddOptionIdentifier(): void
125
    {
126
        $this->assertFalse($this->listMapper->has('fooName'));
127
        $this->assertFalse($this->listMapper->has('barName'));
128
        $this->assertFalse($this->listMapper->has('bazName'));
129
130
        $this->listMapper->add('barName');
131
        $this->assertNull($this->listMapper->get('barName')->getOption('identifier'));
132
        $this->listMapper->add('fooName', null, ['identifier' => true]);
133
        $this->assertTrue($this->listMapper->has('fooName'));
134
        $this->assertTrue($this->listMapper->get('fooName')->getOption('identifier'));
135
        $this->listMapper->add('bazName', null, ['identifier' => false]);
136
        $this->assertTrue($this->listMapper->has('bazName'));
137
        $this->assertFalse($this->listMapper->get('bazName')->getOption('identifier'));
138
    }
139
140
    /**
141
     * @group legacy
142
     *
143
     * @expectedDeprecation Passing a non boolean value for the "identifier" option is deprecated since sonata-project/admin-bundle 3.x and will throw an exception in 4.0.
144
     *
145
     * @dataProvider getWrongIdentifierOptions
146
     */
147
    public function testAddOptionIdentifierWithDeprecatedValue(bool $expected, $value): void
148
    {
149
        $this->assertFalse($this->listMapper->has('fooName'));
150
        $this->listMapper->add('fooName', null, ['identifier' => $value]);
151
        $this->assertTrue($this->listMapper->has('fooName'));
152
        $this->assertSame($expected, $this->listMapper->get('fooName')->getOption('identifier'));
153
    }
154
155
    /**
156
     * @dataProvider getWrongIdentifierOptions
157
     */
158
    public function testAddOptionIdentifierWithWrongValue(bool $expected, $value): void
159
    {
160
        // NEXT_MAJOR: Remove the following `markTestSkipped()` call and the `testAddOptionIdentifierWithDeprecatedValue()` test
161
        $this->markTestSkipped('This test must be run in 4.0');
162
163
        $this->assertFalse($this->listMapper->has('fooName'));
164
165
        $this->expectException(\InvalidArgumentException::class);
166
        $this->expectExceptionMessageRegExp('{^Value for "identifier" option must be boolean, [^]+ given.$}');
167
168
        $this->listMapper->add('fooName', null, ['identifier' => $value]);
169
    }
170
171
    public function getWrongIdentifierOptions(): iterable
172
    {
173
        return [
174
            [true, 1],
175
            [true, 'string'],
176
            [true, new \stdClass()],
177
            [true, [null]],
178
            [false, 0],
179
            [false, null],
180
            [false, ''],
181
            [false, '0'],
182
            [false, []],
183
        ];
184
    }
185
186
    public function testAdd(): void
187
    {
188
        $this->listMapper->add('fooName');
189
        $this->listMapper->add('fooNameLabelBar', null, ['label' => 'Foo Bar']);
190
        $this->listMapper->add('fooNameLabelFalse', null, ['label' => false]);
191
192
        $this->assertTrue($this->listMapper->has('fooName'));
193
194
        $fieldDescription = $this->listMapper->get('fooName');
195
        $fieldLabelBar = $this->listMapper->get('fooNameLabelBar');
196
        $fieldLabelFalse = $this->listMapper->get('fooNameLabelFalse');
197
198
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
199
        $this->assertSame('fooName', $fieldDescription->getName());
200
        $this->assertSame('fooName', $fieldDescription->getOption('label'));
201
        $this->assertSame('Foo Bar', $fieldLabelBar->getOption('label'));
202
        $this->assertFalse($fieldLabelFalse->getOption('label'));
203
    }
204
205
    /**
206
     * @group legacy
207
     */
208
    public function testLegacyAddViewInlineAction(): void
209
    {
210
        $this->assertFalse($this->listMapper->has('_action'));
211
        $this->listMapper->add('_action', 'actions', ['actions' => ['view' => []]]);
212
213
        $this->assertTrue($this->listMapper->has('_action'));
214
215
        $fieldDescription = $this->listMapper->get('_action');
216
217
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
218
        $this->assertSame('_action', $fieldDescription->getName());
219
        $this->assertCount(1, $fieldDescription->getOption('actions'));
220
        $this->assertSame(['show' => []], $fieldDescription->getOption('actions'));
221
    }
222
223
    public function testAddViewInlineAction(): void
224
    {
225
        $this->assertFalse($this->listMapper->has('_action'));
226
        $this->listMapper->add('_action', 'actions', ['actions' => ['show' => []]]);
227
228
        $this->assertTrue($this->listMapper->has('_action'));
229
230
        $fieldDescription = $this->listMapper->get('_action');
231
232
        $this->assertInstanceOf(FieldDescriptionInterface::class, $fieldDescription);
233
        $this->assertSame('_action', $fieldDescription->getName());
234
        $this->assertCount(1, $fieldDescription->getOption('actions'));
235
        $this->assertSame(['show' => []], $fieldDescription->getOption('actions'));
236
    }
237
238
    public function testAddRemove(): void
239
    {
240
        $this->assertFalse($this->listMapper->has('fooName'));
241
242
        $fieldDescription = $this->getFieldDescriptionMock('fooName', 'fooLabel');
243
244
        $this->listMapper->add($fieldDescription);
245
        $this->assertTrue($this->listMapper->has('fooName'));
246
247
        $this->listMapper->remove('fooName');
248
        $this->assertFalse($this->listMapper->has('fooName'));
249
    }
250
251
    public function testAddDuplicateNameException(): void
252
    {
253
        $tmpNames = [];
254
        $this->admin->expects($this->any())
255
            ->method('hasListFieldDescription')
256
            ->willReturnCallback(static function ($name) use (&$tmpNames) {
257
                if (isset($tmpNames[$name])) {
258
                    return true;
259
                }
260
                $tmpNames[$name] = $name;
261
262
                return false;
263
            });
264
265
        $this->expectException(\RuntimeException::class, 'Duplicate field name "fooName" in list mapper. Names should be unique.');
266
267
        $this->listMapper->add('fooName');
268
        $this->listMapper->add('fooName');
269
    }
270
271
    public function testAddWrongTypeException(): void
272
    {
273
        $this->expectException(\RuntimeException::class, 'Unknown field name in list mapper. Field name should be either of FieldDescriptionInterface interface or string.');
274
275
        $this->listMapper->add(12345);
276
    }
277
278
    public function testAutoAddVirtualOption(): void
279
    {
280
        foreach (['actions', 'batch', 'select'] as $type) {
281
            $this->listMapper->add('_'.$type, $type);
282
        }
283
284
        foreach ($this->fieldDescriptionCollection->getElements() as $field) {
285
            $this->assertTrue(
286
                $field->isVirtual(),
287
                'Failed asserting that FieldDescription with type "'.$field->getType().'" is tagged with virtual flag.'
288
            );
289
        }
290
    }
291
292
    public function testKeys(): void
293
    {
294
        $fieldDescription1 = $this->getFieldDescriptionMock('fooName1', 'fooLabel1');
295
        $fieldDescription2 = $this->getFieldDescriptionMock('fooName2', 'fooLabel2');
296
297
        $this->listMapper->add($fieldDescription1);
298
        $this->listMapper->add($fieldDescription2);
299
300
        $this->assertSame(['fooName1', 'fooName2'], $this->listMapper->keys());
301
    }
302
303
    public function testReorder(): void
304
    {
305
        $fieldDescription1 = $this->getFieldDescriptionMock('fooName1', 'fooLabel1');
306
        $fieldDescription2 = $this->getFieldDescriptionMock('fooName2', 'fooLabel2');
307
        $fieldDescription3 = $this->getFieldDescriptionMock('fooName3', 'fooLabel3');
308
        $fieldDescription4 = $this->getFieldDescriptionMock('fooName4', 'fooLabel4');
309
310
        $this->listMapper->add($fieldDescription1);
311
        $this->listMapper->add($fieldDescription2);
312
        $this->listMapper->add($fieldDescription3);
313
        $this->listMapper->add($fieldDescription4);
314
315
        $this->assertSame([
316
            'fooName1' => $fieldDescription1,
317
            'fooName2' => $fieldDescription2,
318
            'fooName3' => $fieldDescription3,
319
            'fooName4' => $fieldDescription4,
320
        ], $this->fieldDescriptionCollection->getElements());
321
322
        $this->listMapper->reorder(['fooName3', 'fooName2', 'fooName1', 'fooName4']);
323
324
        // print_r is used to compare order of items in associative arrays
325
        $this->assertSame(print_r([
326
            'fooName3' => $fieldDescription3,
327
            'fooName2' => $fieldDescription2,
328
            'fooName1' => $fieldDescription1,
329
            'fooName4' => $fieldDescription4,
330
        ], true), print_r($this->fieldDescriptionCollection->getElements(), true));
331
    }
332
333
    public function testAddOptionRole(): void
334
    {
335
        $this->listMapper->add('bar', 'bar');
336
337
        $this->assertTrue($this->listMapper->has('bar'));
338
339
        $this->listMapper->add('quux', 'bar', ['role' => 'ROLE_QUX']);
340
341
        $this->assertTrue($this->listMapper->has('bar'));
342
        $this->assertFalse($this->listMapper->has('quux'));
343
344
        $this->listMapper
345
            ->add('foobar', 'bar', ['role' => self::DEFAULT_GRANTED_ROLE])
346
            ->add('foo', 'bar', ['role' => 'ROLE_QUX'])
347
            ->add('baz', 'bar');
348
349
        $this->assertTrue($this->listMapper->has('foobar'));
350
        $this->assertFalse($this->listMapper->has('foo'));
351
        $this->assertTrue($this->listMapper->has('baz'));
352
    }
353
354
    private function getFieldDescriptionMock(?string $name = null, ?string $label = null): BaseFieldDescription
355
    {
356
        $fieldDescription = $this->getMockForAbstractClass(BaseFieldDescription::class);
357
358
        if (null !== $name) {
359
            $fieldDescription->setName($name);
360
        }
361
362
        if (null !== $label) {
363
            $fieldDescription->setOption('label', $label);
364
        }
365
366
        return $fieldDescription;
367
    }
368
}
369