Completed
Push — 3.x ( f37b5a...b37d45 )
by Christian
26:43
created

testFlattenExtensionConfiguration()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 65

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 65
rs 8.7636
c 0
b 0
f 0
cc 1
nc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\AdminBundle\Tests\DependencyInjection\Compiler;
15
16
use Knp\Menu\FactoryInterface;
17
use Knp\Menu\Matcher\MatcherInterface;
18
use Knp\Menu\Provider\MenuProviderInterface;
19
use PHPUnit\Framework\TestCase;
20
use Sonata\AdminBundle\Admin\AbstractAdmin;
21
use Sonata\AdminBundle\Admin\AdminExtensionInterface;
22
use Sonata\AdminBundle\Controller\CRUDController;
23
use Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass;
24
use Sonata\AdminBundle\DependencyInjection\SonataAdminExtension;
25
use Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait;
26
use Sonata\BlockBundle\DependencyInjection\SonataBlockExtension;
27
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
28
use Symfony\Bundle\FrameworkBundle\Translation\TranslatorInterface;
29
use Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory;
30
use Symfony\Component\Config\FileLocatorInterface;
31
use Symfony\Component\DependencyInjection\ContainerBuilder;
32
use Symfony\Component\EventDispatcher\EventDispatcher;
33
use Symfony\Component\Form\FormFactoryInterface;
34
use Symfony\Component\HttpFoundation\RequestStack;
35
use Symfony\Component\HttpFoundation\Session\Session;
36
use Symfony\Component\HttpKernel\KernelInterface;
37
use Symfony\Component\PropertyAccess\PropertyAccessor;
38
use Symfony\Component\Routing\RouterInterface;
39
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
40
use Symfony\Component\Validator\Validator\ValidatorInterface;
41
42
class ExtensionCompilerPassTest extends TestCase
43
{
44
    /** @var SonataAdminExtension $extension */
45
    private $extension;
46
47
    /** @var array $config */
48
    private $config;
49
50
    /**
51
     * Root name of the configuration.
52
     *
53
     * @var string
54
     */
55
    private $root;
56
57
    public function setUp(): void
58
    {
59
        $this->extension = new SonataAdminExtension();
60
        $this->config = $this->getConfig();
61
        $this->root = 'sonata.admin';
62
    }
63
64
    /**
65
     * @covers \Sonata\AdminBundle\DependencyInjection\SonataAdminExtension::load
66
     */
67
    public function testAdminExtensionLoad(): void
68
    {
69
        $this->extension->load([], $container = $this->getContainer());
70
71
        $this->assertTrue($container->hasParameter($this->root.'.extension.map'));
72
        $this->assertIsArray($extensionMap = $container->getParameter($this->root.'.extension.map'));
73
74
        $this->assertArrayHasKey('admins', $extensionMap);
75
        $this->assertArrayHasKey('excludes', $extensionMap);
76
        $this->assertArrayHasKey('implements', $extensionMap);
77
        $this->assertArrayHasKey('extends', $extensionMap);
78
        $this->assertArrayHasKey('instanceof', $extensionMap);
79
        $this->assertArrayHasKey('uses', $extensionMap);
80
    }
81
82
    /**
83
     * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::flattenExtensionConfiguration
84
     */
85
    public function testFlattenEmptyExtensionConfiguration(): void
86
    {
87
        $this->extension->load([], $container = $this->getContainer());
88
        $extensionMap = $container->getParameter($this->root.'.extension.map');
89
90
        $method = new \ReflectionMethod(
91
            ExtensionCompilerPass::class, 'flattenExtensionConfiguration'
92
        );
93
94
        $method->setAccessible(true);
95
        $extensionMap = $method->invokeArgs(new ExtensionCompilerPass(), [$extensionMap]);
96
97
        $this->assertArrayHasKey('admins', $extensionMap);
98
        $this->assertArrayHasKey('excludes', $extensionMap);
99
        $this->assertArrayHasKey('implements', $extensionMap);
100
        $this->assertArrayHasKey('extends', $extensionMap);
101
        $this->assertArrayHasKey('instanceof', $extensionMap);
102
        $this->assertArrayHasKey('uses', $extensionMap);
103
104
        $this->assertEmpty($extensionMap['admins']);
105
        $this->assertEmpty($extensionMap['excludes']);
106
        $this->assertEmpty($extensionMap['implements']);
107
        $this->assertEmpty($extensionMap['extends']);
108
        $this->assertEmpty($extensionMap['instanceof']);
109
        $this->assertEmpty($extensionMap['uses']);
110
    }
111
112
    /**
113
     * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::flattenExtensionConfiguration
114
     */
115
    public function testFlattenExtensionConfiguration(): void
116
    {
117
        $config = $this->getConfig();
118
        $this->extension->load([$config], $container = $this->getContainer());
119
        $extensionMap = $container->getParameter($this->root.'.extension.map');
120
121
        $method = new \ReflectionMethod(
122
            ExtensionCompilerPass::class, 'flattenExtensionConfiguration'
123
        );
124
125
        $method->setAccessible(true);
126
        $extensionMap = $method->invokeArgs(new ExtensionCompilerPass(), [$extensionMap]);
127
128
        // Admins
129
        $this->assertArrayHasKey('admins', $extensionMap);
130
        $this->assertCount(1, $extensionMap['admins']);
131
132
        $this->assertArrayHasKey('sonata_extension_publish', $extensionMap['admins']['sonata_post_admin']);
133
        $this->assertCount(1, $extensionMap['admins']['sonata_post_admin']);
134
135
        // Excludes
136
        $this->assertArrayHasKey('excludes', $extensionMap);
137
        $this->assertCount(2, $extensionMap['excludes']);
138
139
        $this->assertArrayHasKey('sonata_article_admin', $extensionMap['excludes']);
140
        $this->assertCount(1, $extensionMap['excludes']['sonata_article_admin']);
141
        $this->assertArrayHasKey('sonata_extension_history', $extensionMap['excludes']['sonata_article_admin']);
142
143
        $this->assertArrayHasKey('sonata_post_admin', $extensionMap['excludes']);
144
        $this->assertCount(1, $extensionMap['excludes']['sonata_post_admin']);
145
        $this->assertArrayHasKey('sonata_extension_order', $extensionMap['excludes']['sonata_post_admin']);
146
147
        // Implements
148
        $this->assertArrayHasKey('implements', $extensionMap);
149
        $this->assertCount(1, $extensionMap['implements']);
150
151
        $this->assertArrayHasKey(Publishable::class, $extensionMap['implements']);
152
        $this->assertCount(2, $extensionMap['implements'][Publishable::class]);
153
        $this->assertArrayHasKey('sonata_extension_publish', $extensionMap['implements'][Publishable::class]);
154
        $this->assertArrayHasKey('sonata_extension_order', $extensionMap['implements'][Publishable::class]);
155
156
        // Extends
157
        $this->assertArrayHasKey('extends', $extensionMap);
158
        $this->assertCount(1, $extensionMap['extends']);
159
160
        $this->assertArrayHasKey(Post::class, $extensionMap['extends']);
161
        $this->assertCount(1, $extensionMap['extends'][Post::class]);
162
        $this->assertArrayHasKey('sonata_extension_order', $extensionMap['extends'][Post::class]);
163
164
        // Instanceof
165
        $this->assertArrayHasKey('instanceof', $extensionMap);
166
        $this->assertCount(1, $extensionMap['instanceof']);
167
168
        $this->assertArrayHasKey(Post::class, $extensionMap['instanceof']);
169
        $this->assertCount(1, $extensionMap['instanceof'][Post::class]);
170
        $this->assertArrayHasKey('sonata_extension_history', $extensionMap['instanceof'][Post::class]);
171
172
        // Uses
173
        $this->assertArrayHasKey('uses', $extensionMap);
174
175
        $this->assertCount(1, $extensionMap['uses']);
176
        $this->assertArrayHasKey(TimestampableTrait::class, $extensionMap['uses']);
177
        $this->assertCount(1, $extensionMap['uses'][TimestampableTrait::class]);
178
        $this->assertArrayHasKey('sonata_extension_post', $extensionMap['uses'][TimestampableTrait::class]);
179
    }
180
181
    /**
182
     * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::process
183
     */
184
    public function testProcessWithInvalidExtensionId(): void
185
    {
186
        $this->expectException(\InvalidArgumentException::class);
187
188
        $config = [
189
            'extensions' => [
190
                'sonata_extension_unknown' => [
191
                    'excludes' => ['sonata_article_admin'],
192
                    'instanceof' => [Post::class],
193
                ],
194
            ],
195
        ];
196
197
        $container = $this->getContainer();
198
        $this->extension->load([$config], $container);
199
200
        $extensionsPass = new ExtensionCompilerPass();
201
        $extensionsPass->process($container);
202
        $container->compile();
203
    }
204
205
    /**
206
     * @doesNotPerformAssertions
207
     * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::process
208
     */
209
    public function testProcessWithInvalidAdminId(): void
210
    {
211
        $config = [
212
            'extensions' => [
213
                'sonata_extension_publish' => [
214
                    'admins' => ['sonata_unknown_admin'],
215
                    'implements' => [Publishable::class],
216
                ],
217
            ],
218
        ];
219
220
        $container = $this->getContainer();
221
        $this->extension->load([$config], $container);
222
223
        $extensionsPass = new ExtensionCompilerPass();
224
        $extensionsPass->process($container);
225
        $container->compile();
226
227
        // nothing should fail the extension just isn't added to the 'sonata_unknown_admin'
228
    }
229
230
    /**
231
     * @covers \Sonata\AdminBundle\DependencyInjection\Compiler\ExtensionCompilerPass::process
232
     */
233
    public function testProcess(): void
234
    {
235
        $container = $this->getContainer();
236
        $this->extension->load([$this->config], $container);
237
238
        $extensionsPass = new ExtensionCompilerPass();
239
        $extensionsPass->process($container);
240
        $container->compile();
241
242
        $this->assertTrue($container->hasDefinition('sonata_extension_publish'));
243
        $this->assertTrue($container->hasDefinition('sonata_extension_history'));
244
        $this->assertTrue($container->hasDefinition('sonata_extension_order'));
245
        $this->assertTrue($container->hasDefinition('sonata_extension_security'));
246
        $this->assertTrue($container->hasDefinition('sonata_extension_timestamp'));
247
248
        $this->assertTrue($container->hasDefinition('sonata_post_admin'));
249
        $this->assertTrue($container->hasDefinition('sonata_article_admin'));
250
        $this->assertTrue($container->hasDefinition('sonata_news_admin'));
251
252
        $securityExtension = $container->get('sonata_extension_security');
253
        $publishExtension = $container->get('sonata_extension_publish');
254
        $historyExtension = $container->get('sonata_extension_history');
255
        $orderExtension = $container->get('sonata_extension_order');
256
        $filterExtension = $container->get('sonata_extension_filter');
257
258
        $def = $container->get('sonata_post_admin');
259
        $extensions = $def->getExtensions();
260
        $this->assertCount(4, $extensions);
261
262
        $this->assertSame($historyExtension, $extensions[0]);
263
        $this->assertSame($publishExtension, $extensions[2]);
264
        $this->assertSame($securityExtension, $extensions[3]);
265
266
        $def = $container->get('sonata_article_admin');
267
        $extensions = $def->getExtensions();
268
        $this->assertCount(5, $extensions);
269
270
        $this->assertSame($filterExtension, $extensions[0]);
271
        $this->assertSame($securityExtension, $extensions[1]);
272
        $this->assertSame($publishExtension, $extensions[2]);
273
        $this->assertSame($orderExtension, $extensions[4]);
274
275
        $def = $container->get('sonata_news_admin');
276
        $extensions = $def->getExtensions();
277
        $this->assertCount(5, $extensions);
278
        $this->assertSame($historyExtension, $extensions[0]);
279
        $this->assertSame($securityExtension, $extensions[1]);
280
        $this->assertSame($filterExtension, $extensions[2]);
281
        $this->assertSame($orderExtension, $extensions[4]);
282
    }
283
284
    /**
285
     * @doesNotPerformAssertions
286
     */
287
    public function testProcessThrowsExceptionIfTraitsAreNotAvailable(): void
288
    {
289
        $config = [
290
            'extensions' => [
291
                'sonata_extension_post' => [
292
                    'uses' => [TimestampableTrait::class],
293
                ],
294
            ],
295
        ];
296
297
        $container = $this->getContainer();
298
        $this->extension->load([$config], $container);
299
300
        $extensionsPass = new ExtensionCompilerPass();
301
        $extensionsPass->process($container);
302
        $container->compile();
303
    }
304
305
    /**
306
     * @return array
307
     */
308
    protected function getConfig()
309
    {
310
        $config = [
311
            'extensions' => [
312
                'sonata_extension_publish' => [
313
                    'admins' => ['sonata_post_admin'],
314
                    'implements' => [Publishable::class],
315
                ],
316
                'sonata_extension_history' => [
317
                    'excludes' => ['sonata_article_admin'],
318
                    'instanceof' => [Post::class],
319
                    'priority' => 255,
320
                ],
321
                'sonata_extension_order' => [
322
                    'excludes' => ['sonata_post_admin'],
323
                    'extends' => [Post::class],
324
                    'implements' => [Publishable::class],
325
                    'priority' => -128,
326
                ],
327
            ],
328
        ];
329
330
        $config['extensions']['sonata_extension_post']['uses'] = [TimestampableTrait::class];
331
332
        return $config;
333
    }
334
335
    private function getContainer(): ContainerBuilder
336
    {
337
        $container = new ContainerBuilder();
338
        $container->setParameter('kernel.bundles', [
339
            'SonataCoreBundle' => true,
340
            'KnpMenuBundle' => true,
341
        ]);
342
        $container->setParameter('kernel.cache_dir', '/tmp');
343
        $container->setParameter('kernel.debug', true);
344
345
        // Add dependencies for SonataAdminBundle (these services will never get called so dummy classes will do)
346
        $container
347
            ->register('twig')
348
            ->setClass(EngineInterface::class);
349
        $container
350
            ->register('templating')
351
            ->setClass(EngineInterface::class);
352
        $container
353
            ->register('translator')
354
            ->setClass(TranslatorInterface::class);
355
        $container
356
            ->register('validator.validator_factory')
357
            ->setClass(ConstraintValidatorFactory::class);
358
        $container
359
            ->register('router')
360
            ->setClass(RouterInterface::class);
361
        $container
362
            ->register('property_accessor')
363
            ->setClass(PropertyAccessor::class);
364
        $container
365
            ->register('form.factory')
366
            ->setClass(FormFactoryInterface::class);
367
        $container
368
            ->register('validator')
369
            ->setClass(ValidatorInterface::class);
370
        $container
371
            ->register('knp_menu.factory')
372
            ->setClass(FactoryInterface::class);
373
        $container
374
            ->register('knp_menu.matcher')
375
            ->setClass(MatcherInterface::class);
376
        $container
377
            ->register('knp_menu.menu_provider')
378
            ->setClass(MenuProviderInterface::class);
379
        $container
380
            ->register('request_stack')
381
            ->setClass(RequestStack::class);
382
        $container
383
            ->register('session')
384
            ->setClass(Session::class);
385
        $container
386
            ->register('security.authorization_checker')
387
            ->setClass(AuthorizationCheckerInterface::class);
388
389
        // Add admin definition's
390
        $container
391
            ->register('sonata_post_admin')
392
            ->setPublic(true)
393
            ->setClass(MockAdmin::class)
394
            ->setArguments(['', Post::class, CRUDController::class])
395
            ->addTag('sonata.admin');
396
        $container
397
            ->register('sonata_news_admin')
398
            ->setPublic(true)
399
            ->setClass(MockAdmin::class)
400
            ->setArguments(['', News::class, CRUDController::class])
401
            ->addTag('sonata.admin');
402
        $container
403
            ->register('sonata_article_admin')
404
            ->setPublic(true)
405
            ->setClass(MockAdmin::class)
406
            ->setArguments(['', Article::class, CRUDController::class])
407
            ->addTag('sonata.admin');
408
        $container
409
            ->register('event_dispatcher')
410
            ->setClass(EventDispatcher::class);
411
412
        // Add admin extension definition's
413
        $extensionClass = \get_class($this->createMock(AdminExtensionInterface::class));
414
415
        $container
416
            ->register('sonata_extension_publish')
417
            ->setPublic(true)
418
            ->setClass($extensionClass);
419
        $container
420
            ->register('sonata_extension_history')
421
            ->setPublic(true)
422
            ->setClass($extensionClass);
423
        $container
424
            ->register('sonata_extension_order')
425
            ->setPublic(true)
426
            ->setClass($extensionClass);
427
        $container
428
            ->register('sonata_extension_timestamp')
429
            ->setPublic(true)
430
            ->setClass($extensionClass);
431
        $container
432
            ->register('sonata_extension_security')
433
            ->setPublic(true)
434
            ->setClass($extensionClass)
435
            ->addTag('sonata.admin.extension', ['global' => true]);
436
        $container
437
            ->register('sonata_extension_filter')
438
            ->setPublic(true)
439
            ->setClass($extensionClass)
440
            ->addTag('sonata.admin.extension', ['target' => 'sonata_news_admin'])
441
            ->addTag('sonata.admin.extension', ['target' => 'sonata_article_admin']);
442
443
        // Add definitions for sonata.templating service
444
        $container
445
            ->register('kernel')
446
            ->setClass(KernelInterface::class);
447
        $container
448
            ->register('file_locator')
449
            ->setClass(FileLocatorInterface::class);
450
451
        $blockExtension = new SonataBlockExtension();
452
        $blockExtension->load([], $container);
453
454
        return $container;
455
    }
456
}
457
458
class MockAdmin extends AbstractAdmin
459
{
460
}
461
462
class MockAbstractServiceAdmin extends AbstractAdmin
463
{
464
    private $extraArgument;
465
466
    public function __construct($code, $class, $baseControllerName, $extraArgument)
467
    {
468
        $this->extraArgument = $extraArgument;
469
470
        parent::__construct($code, $class, $baseControllerName);
471
    }
472
}
473
474
class Post
475
{
476
}
477
interface Publishable
478
{
479
}
480
class News extends Post
481
{
482
}
483
class Article implements Publishable
484
{
485
}
486