Completed
Push — 3.x ( b75183...b1c847 )
by Oskar
04:45
created

tests/Admin/BreadcrumbsBuilderTest.php (2 issues)

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\Admin;
15
16
use Knp\Menu\FactoryInterface;
17
use Knp\Menu\ItemInterface;
18
use Knp\Menu\MenuFactory;
19
use PHPUnit\Framework\TestCase;
20
use Sonata\AdminBundle\Admin\AbstractAdmin;
21
use Sonata\AdminBundle\Admin\BreadcrumbsBuilder;
22
use Sonata\AdminBundle\Admin\Pool;
23
use Sonata\AdminBundle\Model\ModelManagerInterface;
24
use Sonata\AdminBundle\Route\RouteGeneratorInterface;
25
use Sonata\AdminBundle\Tests\Fixtures\Admin\CommentAdmin;
26
use Sonata\AdminBundle\Tests\Fixtures\Admin\PostAdmin;
27
use Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity\Comment;
28
use Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity\DummySubject;
29
use Sonata\AdminBundle\Translator\LabelTranslatorStrategyInterface;
30
use Symfony\Component\DependencyInjection\ContainerInterface;
31
use Symfony\Component\HttpFoundation\Request;
32
33
/**
34
 * This test class contains unit and integration tests. Maybe it could be
35
 * separated into two classes.
36
 *
37
 * @author Grégoire Paris <[email protected]>
38
 */
39
class BreadcrumbsBuilderTest extends TestCase
40
{
41
    /**
42
     * @group legacy
43
     */
44
    public function testGetBreadcrumbs(): void
45
    {
46
        $postAdminSubjectId = 42;
47
        $commentAdminSubjectId = 100500;
48
49
        $menuFactory = $this->getMockForAbstractClass(FactoryInterface::class);
50
        $menu = $this->getMockForAbstractClass(ItemInterface::class);
51
        $translatorStrategy = $this->getMockForAbstractClass(LabelTranslatorStrategyInterface::class);
52
        $modelManager = $this->getMockForAbstractClass(ModelManagerInterface::class);
53
        $routeGenerator = $this->getMockForAbstractClass(RouteGeneratorInterface::class);
54
        $container = $this->getMockForAbstractClass(ContainerInterface::class);
55
        $pool = $this->getMockBuilder(Pool::class)
56
            ->disableOriginalConstructor()
57
            ->getMock();
58
59
        $menu->expects($this->any())
60
            ->method('addChild')
61
            ->willReturnCallback(function () use ($menu) {
62
                return $menu;
63
            });
64
65
        $postAdmin = new PostAdmin('sonata.post.admin.post', DummySubject::class, 'SonataNewsBundle:PostAdmin');
66
        $commentAdmin = new CommentAdmin('sonata.post.admin.comment', Comment::class, 'SonataNewsBundle:CommentAdmin');
67
        $subCommentAdmin = new CommentAdmin('sonata.post.admin.comment', Comment::class, 'SonataNewsBundle:CommentAdmin');
68
69
        $postAdmin->addChild($commentAdmin);
70
        $postAdmin->setRequest(new Request(['id' => $postAdminSubjectId]));
71
        $postAdmin->setModelManager($modelManager);
72
73
        $commentAdmin->setRequest(new Request(['childId' => $commentAdminSubjectId]));
74
        $commentAdmin->setModelManager($modelManager);
75
76
        $commentAdmin->initialize();
77
        $postAdmin->initialize();
78
79
        $commentAdmin->setCurrentChild($subCommentAdmin);
80
81
        $container->expects($this->any())
82
            ->method('getParameter')
83
            ->with('sonata.admin.configuration.breadcrumbs')
84
            ->will($this->returnValue([]));
85
86
        $pool->expects($this->any())
87
            ->method('getContainer')
88
            ->will($this->returnValue($container));
89
90
        $postAdmin->setConfigurationPool($pool);
91
        $postAdmin->setMenuFactory($menuFactory);
92
        $postAdmin->setLabelTranslatorStrategy($translatorStrategy);
93
        $postAdmin->setRouteGenerator($routeGenerator);
94
95
        $commentAdmin->setLabelTranslatorStrategy($translatorStrategy);
0 ignored issues
show
$translatorStrategy is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Sonata\AdminBundl...latorStrategyInterface>.

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...
96
        $commentAdmin->setRouteGenerator($routeGenerator);
0 ignored issues
show
$routeGenerator is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Sonata\AdminBundl...outeGeneratorInterface>.

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
98
        $modelManager->expects($this->any())
99
            ->method('find')
100
            ->willReturnCallback(function ($class, $id) use ($postAdminSubjectId, $commentAdminSubjectId) {
101
                if (DummySubject::class === $class && $postAdminSubjectId === $id) {
102
                    return new DummySubject();
103
                }
104
105
                if (Comment::class === $class && $commentAdminSubjectId === $id) {
106
                    return new Comment();
107
                }
108
109
                throw new \Exception('Unexpected class and id combination');
110
            });
111
112
        $menuFactory->expects($this->exactly(5))
113
            ->method('createItem')
114
            ->with('root')
115
            ->will($this->returnValue($menu));
116
117
        $menu->expects($this->once())
118
            ->method('setUri')
119
            ->with($this->identicalTo(false));
120
121
        $menu->expects($this->exactly(5))
122
            ->method('getParent')
123
            ->will($this->returnValue(false));
124
125
        $routeGenerator->expects($this->exactly(5))
126
            ->method('generate')
127
            ->with('sonata_admin_dashboard')
128
            ->will($this->returnValue('http://somehost.com'));
129
130
        $translatorStrategy->expects($this->exactly(10))
131
            ->method('getLabel')
132
            ->withConsecutive(
133
                ['DummySubject_list'],
134
                ['Comment_list'],
135
                ['DummySubject_list'],
136
                ['Comment_list'],
137
                ['DummySubject_list'],
138
139
                ['Comment_list'],
140
                ['DummySubject_list'],
141
                ['Comment_list'],
142
143
                ['DummySubject_list'],
144
                ['Comment_list'],
145
                ['Comment_edit'],
146
147
                ['DummySubject_list'],
148
                ['Comment_list'],
149
150
                ['DummySubject_list'],
151
                ['Comment_list']
152
            )
153
            ->will($this->onConsecutiveCalls(
154
                'someOtherLabel',
155
                'someInterestingLabel',
156
                'someFancyLabel',
157
158
                'someTipTopLabel',
159
                'someFunkyLabel',
160
                'someAwesomeLabel',
161
162
                'someMildlyInterestingLabel',
163
                'someWTFLabel',
164
                'someBadLabel',
165
166
                'someLongLabel',
167
                'someEndlessLabel',
168
169
                'someOriginalLabel',
170
                'someOkayishLabel'
171
            ));
172
173
        $menu->expects($this->exactly(24))
174
            ->method('addChild')
175
            ->withConsecutive(
176
                ['link_breadcrumb_dashboard'],
177
                ['someOtherLabel'],
178
                ['dummy subject representation'],
179
                ['someInterestingLabel'],
180
                ['this is a comment'],
181
182
                ['link_breadcrumb_dashboard'],
183
                ['someFancyLabel'],
184
                ['dummy subject representation'],
185
                ['someTipTopLabel'],
186
                ['this is a comment'],
187
                ['link_breadcrumb_dashboard'],
188
189
                ['someFunkyLabel'],
190
                ['dummy subject representation'],
191
                ['someAwesomeLabel'],
192
                ['this is a comment'],
193
                ['link_breadcrumb_dashboard'],
194
195
                ['someMildlyInterestingLabel'],
196
                ['dummy subject representation'],
197
                ['someWTFLabel'],
198
                ['link_breadcrumb_dashboard'],
199
200
                ['someBadLabel'],
201
                ['dummy subject representation'],
202
                ['someLongLabel'],
203
                ['this is a comment']
204
            )
205
            ->will($this->returnValue($menu));
206
207
        $postAdmin->getBreadcrumbs('repost');
208
        $postAdmin->setSubject(new DummySubject());
209
        $postAdmin->getBreadcrumbs('flag');
210
211
        $commentAdmin->setConfigurationPool($pool);
212
        $commentAdmin->getBreadcrumbs('edit');
213
214
        $commentAdmin->getBreadcrumbs('list');
215
        $commentAdmin->setSubject(new Comment());
216
        $commentAdmin->getBreadcrumbs('reply');
217
    }
218
219
    /**
220
     * @group legacy
221
     */
222
    public function testGetBreadcrumbsWithNoCurrentAdmin(): void
223
    {
224
        $postAdminSubjectId = 42;
225
        $commentAdminSubjectId = 100500;
226
227
        $menuFactory = $this->getMockForAbstractClass(FactoryInterface::class);
228
        $menu = $this->getMockForAbstractClass(ItemInterface::class);
229
        $translatorStrategy = $this->getMockForAbstractClass(LabelTranslatorStrategyInterface::class);
230
        $routeGenerator = $this->getMockForAbstractClass(RouteGeneratorInterface::class);
231
        $modelManager = $this->getMockForAbstractClass(ModelManagerInterface::class);
232
        $container = $this->getMockForAbstractClass(ContainerInterface::class);
233
        $pool = $this->getMockBuilder(Pool::class)
234
            ->disableOriginalConstructor()
235
            ->getMock();
236
237
        $postAdmin = new PostAdmin('sonata.post.admin.post', DummySubject::class, 'SonataNewsBundle:PostAdmin');
238
        $commentAdmin = new CommentAdmin('sonata.post.admin.comment', Comment::class, 'SonataNewsBundle:CommentAdmin');
239
240
        $postAdmin->addChild($commentAdmin);
241
        $postAdmin->setRequest(new Request(['id' => $postAdminSubjectId]));
242
243
        $commentAdmin->setRequest(new Request(['childId' => $commentAdminSubjectId]));
244
245
        $commentAdmin->setModelManager($modelManager);
246
        $postAdmin->setModelManager($modelManager);
247
248
        $commentAdmin->initialize();
249
        $postAdmin->initialize();
250
251
        $postAdmin->setMenuFactory($menuFactory);
252
        $postAdmin->setLabelTranslatorStrategy($translatorStrategy);
253
        $postAdmin->setRouteGenerator($routeGenerator);
254
255
        $menuFactory->expects($this->any())
256
            ->method('createItem')
257
            ->with('root')
258
            ->will($this->returnValue($menu));
259
260
        $translatorStrategy->expects($this->any())
261
            ->method('getLabel')
262
            ->withConsecutive(
263
                ['DummySubject_list'],
264
                ['DummySubject_repost'],
265
266
                ['DummySubject_list']
267
            )
268
            ->will($this->onConsecutiveCalls(
269
                'someOtherLabel',
270
                'someInterestingLabel',
271
272
                'someCoolLabel'
273
            ));
274
275
        $menu->expects($this->any())
276
            ->method('addChild')
277
            ->withConsecutive(
278
                ['link_breadcrumb_dashboard'],
279
                ['someOtherLabel'],
280
                ['someInterestingLabel'],
281
282
                ['link_breadcrumb_dashboard'],
283
                ['someCoolLabel'],
284
                ['dummy subject representation']
285
            )
286
            ->will($this->returnValue($menu));
287
288
        $container->expects($this->any())
289
            ->method('getParameter')
290
            ->with('sonata.admin.configuration.breadcrumbs')
291
            ->will($this->returnValue([]));
292
293
        $pool->expects($this->any())
294
            ->method('getContainer')
295
            ->will($this->returnValue($container));
296
297
        $postAdmin->setConfigurationPool($pool);
298
299
        $postAdmin->getBreadcrumbs('repost');
300
        $postAdmin->setSubject(new DummySubject());
301
        $flagBreadcrumb = $postAdmin->getBreadcrumbs('flag');
302
        $this->assertSame($flagBreadcrumb, $postAdmin->getBreadcrumbs('flag'));
303
    }
304
305
    public function testUnitChildGetBreadCrumbs(): void
306
    {
307
        $menu = $this->prophesize(ItemInterface::class);
308
        $menu->getParent()->willReturn(null);
309
310
        $dashboardMenu = $this->prophesize(ItemInterface::class);
311
        $dashboardMenu->getParent()->willReturn($menu);
312
313
        $adminListMenu = $this->prophesize(ItemInterface::class);
314
        $adminListMenu->getParent()->willReturn($dashboardMenu);
315
316
        $adminSubjectMenu = $this->prophesize(ItemInterface::class);
317
        $adminSubjectMenu->getParent()->willReturn($adminListMenu);
318
319
        $childMenu = $this->prophesize(ItemInterface::class);
320
        $childMenu->getParent()->willReturn($adminSubjectMenu);
321
322
        $leafMenu = $this->prophesize(ItemInterface::class);
323
        $leafMenu->getParent()->willReturn($childMenu);
324
325
        $action = 'my_action';
326
        $breadcrumbsBuilder = new BreadcrumbsBuilder(['child_admin_route' => 'show']);
327
        $admin = $this->prophesize(AbstractAdmin::class);
328
        $admin->isChild()->willReturn(false);
329
330
        $menuFactory = $this->prophesize(MenuFactory::class);
331
        $menuFactory->createItem('root')->willReturn($menu);
332
        $admin->getMenuFactory()->willReturn($menuFactory);
333
        $labelTranslatorStrategy = $this->prophesize(
334
            LabelTranslatorStrategyInterface::class
335
        );
336
337
        $routeGenerator = $this->prophesize(RouteGeneratorInterface::class);
338
        $routeGenerator->generate('sonata_admin_dashboard')->willReturn('/dashboard');
339
340
        $admin->getRouteGenerator()->willReturn($routeGenerator->reveal());
341
        $menu->addChild('link_breadcrumb_dashboard', [
342
            'uri' => '/dashboard',
343
            'extras' => [
344
                'translation_domain' => 'SonataAdminBundle',
345
            ],
346
        ])->willReturn(
347
            $dashboardMenu->reveal()
348
        );
349
        $labelTranslatorStrategy->getLabel(
350
            'my_class_name_list',
351
            'breadcrumb',
352
            'link'
353
        )->willReturn('My class');
354
        $labelTranslatorStrategy->getLabel(
355
            'my_child_class_name_list',
356
            'breadcrumb',
357
            'link'
358
        )->willReturn('My child class');
359
        $childAdmin = $this->prophesize(AbstractAdmin::class);
360
        $childAdmin->isChild()->willReturn(true);
361
        $childAdmin->getParent()->willReturn($admin->reveal());
362
        $childAdmin->getTranslationDomain()->willReturn('ChildBundle');
363
        $childAdmin->getLabelTranslatorStrategy()
364
            ->shouldBeCalled()
365
            ->willReturn($labelTranslatorStrategy->reveal());
366
        $childAdmin->getClassnameLabel()->willReturn('my_child_class_name');
367
        $childAdmin->hasRoute('list')->willReturn(true);
368
        $childAdmin->hasAccess('list')->willReturn(true);
369
        $childAdmin->generateUrl('list')->willReturn('/myadmin/my-object/mychildadmin/list');
370
        $childAdmin->getCurrentChildAdmin()->willReturn(null);
371
        $childAdmin->hasSubject()->willReturn(true);
372
        $childAdmin->getSubject()->willReturn('my subject');
373
        $childAdmin->toString('my subject')->willReturn('My subject');
374
375
        $admin->hasAccess('show', 'my subject')->willReturn(true)->shouldBeCalled();
376
        $admin->hasRoute('show')->willReturn(true);
377
        $admin->generateUrl('show', ['id' => 'my-object'])->willReturn('/myadmin/my-object');
378
379
        $admin->trans('My class', [], null)->willReturn('Ma classe');
380
        $admin->hasRoute('list')->willReturn(true);
381
        $admin->hasAccess('list')->willReturn(true);
382
        $admin->generateUrl('list')->willReturn('/myadmin/list');
383
        $admin->getCurrentChildAdmin()->willReturn($childAdmin->reveal());
384
        $request = $this->prophesize(Request::class);
385
        $request->get('slug')->willReturn('my-object');
386
387
        $admin->getIdParameter()->willReturn('slug');
388
        $admin->hasRoute('edit')->willReturn(true);
389
        $admin->hasAccess('edit')->willReturn(true);
390
        $admin->generateUrl('edit', ['id' => 'my-object'])->willReturn('/myadmin/my-object');
391
        $admin->getRequest()->willReturn($request->reveal());
392
        $admin->hasSubject()->willReturn(true);
393
        $admin->getSubject()->willReturn('my subject');
394
        $admin->toString('my subject')->willReturn('My subject');
395
        $admin->getTranslationDomain()->willReturn('FooBundle');
396
        $admin->getLabelTranslatorStrategy()->willReturn(
397
            $labelTranslatorStrategy->reveal()
398
        );
399
        $admin->getClassnameLabel()->willReturn('my_class_name');
400
401
        $dashboardMenu->addChild('My class', [
402
            'extras' => [
403
                'translation_domain' => 'FooBundle',
404
            ],
405
            'uri' => '/myadmin/list',
406
        ])->shouldBeCalled()->willReturn($adminListMenu->reveal());
407
408
        $adminListMenu->addChild('My subject', [
409
            'uri' => '/myadmin/my-object',
410
            'extras' => [
411
                'translation_domain' => false,
412
            ],
413
        ])->shouldBeCalled()->willReturn($adminSubjectMenu->reveal());
414
415
        $adminSubjectMenu->addChild('My child class', [
416
            'extras' => [
417
                'translation_domain' => 'ChildBundle',
418
            ],
419
            'uri' => '/myadmin/my-object/mychildadmin/list',
420
        ])->shouldBeCalled()->willReturn($childMenu->reveal());
421
        $adminSubjectMenu->setExtra('safe_label', false)->willReturn($childMenu);
422
423
        $childMenu->addChild('My subject', [
424
            'extras' => [
425
                'translation_domain' => false,
426
            ],
427
        ])->shouldBeCalled()->willReturn($leafMenu->reveal());
428
429
        $breadcrumbs = $breadcrumbsBuilder->getBreadcrumbs($childAdmin->reveal(), $action);
430
        $this->assertCount(5, $breadcrumbs);
431
    }
432
433
    public function actionProvider()
434
    {
435
        return [
436
            ['my_action'],
437
            ['list'],
438
            ['edit'],
439
            ['create'],
440
        ];
441
    }
442
443
    /**
444
     * @dataProvider actionProvider
445
     */
446
    public function testUnitBuildBreadcrumbs($action): void
447
    {
448
        $breadcrumbsBuilder = new BreadcrumbsBuilder();
449
450
        $menu = $this->prophesize(ItemInterface::class);
451
        $menuFactory = $this->prophesize(MenuFactory::class);
452
        $menuFactory->createItem('root')->willReturn($menu);
453
        $admin = $this->prophesize(AbstractAdmin::class);
454
        $admin->getMenuFactory()->willReturn($menuFactory);
455
        $labelTranslatorStrategy = $this->prophesize(LabelTranslatorStrategyInterface::class);
456
457
        $routeGenerator = $this->prophesize(RouteGeneratorInterface::class);
458
        $routeGenerator->generate('sonata_admin_dashboard')->willReturn('/dashboard');
459
        $admin->getRouteGenerator()->willReturn($routeGenerator->reveal());
460
        $menu->addChild('link_breadcrumb_dashboard', [
461
            'uri' => '/dashboard',
462
            'extras' => [
463
                'translation_domain' => 'SonataAdminBundle',
464
            ],
465
        ])->willReturn(
466
            $menu->reveal()
467
        );
468
        $labelTranslatorStrategy->getLabel(
469
            'my_class_name_list',
470
            'breadcrumb',
471
            'link'
472
        )->willReturn('My class');
473
        $labelTranslatorStrategy->getLabel(
474
            'my_child_class_name_list',
475
            'breadcrumb',
476
            'link'
477
        )->willReturn('My child class');
478
        $labelTranslatorStrategy->getLabel(
479
            'my_child_class_name_my_action',
480
            'breadcrumb',
481
            'link'
482
        )->willReturn('My action');
483
        if ('create' === $action) {
484
            $labelTranslatorStrategy->getLabel(
485
                'my_class_name_create',
486
                'breadcrumb',
487
                'link'
488
            )->willReturn('create my object');
489
            $menu->addChild('create my object', [
490
                'extras' => [
491
                    'translation_domain' => 'FooBundle',
492
                ],
493
            ])->willReturn($menu);
494
        }
495
        $childAdmin = $this->prophesize(AbstractAdmin::class);
496
        $childAdmin->getTranslationDomain()->willReturn('ChildBundle');
497
        $childAdmin->getLabelTranslatorStrategy()->willReturn($labelTranslatorStrategy->reveal());
498
        $childAdmin->getClassnameLabel()->willReturn('my_child_class_name');
499
        $childAdmin->hasRoute('list')->willReturn(false);
500
        $childAdmin->getCurrentChildAdmin()->willReturn(null);
501
        $childAdmin->hasSubject()->willReturn(false);
502
503
        $admin->hasRoute('list')->willReturn(true);
504
        $admin->hasAccess('list')->willReturn(true);
505
        $admin->generateUrl('list')->willReturn('/myadmin/list');
506
        $admin->getCurrentChildAdmin()->willReturn(
507
            'my_action' === $action ? $childAdmin->reveal() : false
508
        );
509
        if ('list' === $action) {
510
            $admin->isChild()->willReturn(true);
511
            $menu->setUri(false)->shouldBeCalled();
512
        } else {
513
            $menu->setUri()->shouldNotBeCalled();
514
        }
515
        $request = $this->prophesize(Request::class);
516
        $request->get('slug')->willReturn('my-object');
517
518
        $admin->getIdParameter()->willReturn('slug');
519
        $admin->hasRoute('edit')->willReturn(false);
520
        $admin->getRequest()->willReturn($request->reveal());
521
        $admin->hasSubject()->willReturn(true);
522
        $admin->getSubject()->willReturn('my subject');
523
        $admin->toString('my subject')->willReturn('My subject');
524
        $admin->getTranslationDomain()->willReturn('FooBundle');
525
        $admin->getLabelTranslatorStrategy()->willReturn(
526
            $labelTranslatorStrategy->reveal()
527
        );
528
        $admin->getClassnameLabel()->willReturn('my_class_name');
529
530
        $menu->addChild('My class', [
531
            'uri' => '/myadmin/list',
532
            'extras' => [
533
                'translation_domain' => 'FooBundle',
534
            ],
535
        ])->willReturn($menu->reveal());
536
        $menu->addChild('My subject', [
537
            'extras' => [
538
                'translation_domain' => false,
539
            ],
540
        ])->willReturn($menu);
541
        $menu->addChild('My subject', [
542
            'uri' => null,
543
            'extras' => [
544
                'translation_domain' => false,
545
            ],
546
        ])->willReturn($menu);
547
        $menu->addChild('My child class', [
548
            'extras' => [
549
                'translation_domain' => 'ChildBundle',
550
            ],
551
            'uri' => null,
552
        ])->willReturn($menu);
553
        $menu->setExtra('safe_label', false)->willReturn($menu);
554
        $menu->addChild('My action', [
555
            'extras' => [
556
                'translation_domain' => 'ChildBundle',
557
            ],
558
        ])->willReturn($menu);
559
560
        $breadcrumbsBuilder->buildBreadCrumbs($admin->reveal(), $action);
561
    }
562
}
563