Completed
Push — master ( 6d6774...64f3ed )
by Jeroen
11:23 queued 05:13
created

ActionsMenuBuilder   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 517
Duplicated Lines 27.47 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 78.82%

Importance

Changes 0
Metric Value
wmc 46
lcom 1
cbo 12
dl 142
loc 517
ccs 134
cts 170
cp 0.7882
rs 8.72
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 19 1
A createSubActionsMenu() 0 30 3
F createActionsMenu() 142 310 36
A createTopActionsMenu() 0 11 1
A createHomeActionsMenu() 0 23 1
A createTopHomeActionsMenu() 0 11 1
A setActiveNodeVersion() 0 6 1
A getActiveNodeVersion() 0 4 1
A setEditableNode() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ActionsMenuBuilder 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 ActionsMenuBuilder, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Kunstmaan\NodeBundle\Helper\Menu;
4
5
use Doctrine\ORM\EntityManager;
6
use FOS\UserBundle\Model\UserInterface;
7
use Knp\Menu\FactoryInterface;
8
use Knp\Menu\ItemInterface;
9
use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionMap;
10
use Kunstmaan\NodeBundle\Entity\NodeVersion;
11
use Kunstmaan\NodeBundle\Entity\QueuedNodeTranslationAction;
12
use Kunstmaan\NodeBundle\Event\ConfigureActionMenuEvent;
13
use Kunstmaan\NodeBundle\Event\Events;
14
use Kunstmaan\NodeBundle\Helper\PagesConfiguration;
15
use Kunstmaan\PagePartBundle\Helper\HasPageTemplateInterface;
16
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17
use Symfony\Component\Routing\RouterInterface;
18
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
19
20
class ActionsMenuBuilder
21
{
22
    /**
23
     * @var FactoryInterface
24
     */
25
    private $factory;
26
27
    /**
28
     * @var NodeVersion
29
     */
30
    private $activeNodeVersion;
31
32
    /**
33
     * @var EntityManager
34
     */
35
    private $em;
36
37
    /**
38
     * @var RouterInterface
39
     */
40
    private $router;
41
42
    /**
43
     * @var EventDispatcherInterface
44
     */
45
    private $dispatcher;
46
47
    /**
48
     * @var AuthorizationCheckerInterface
49
     */
50
    private $authorizationChecker;
51
52
    /**
53
     * @var PagesConfiguration
54
     */
55
    private $pagesConfiguration;
56
57
    /**
58
     * @var bool
59
     */
60
    private $isEditableNode = true;
61
62
    /**
63
     * @var bool
64
     */
65
    private $enableExportPageTemplate;
66
67
    /** @var bool */
68
    private $showDuplicateWithChildren;
69
70
    /**
71
     * @param FactoryInterface              $factory
72
     * @param EntityManager                 $em
73
     * @param RouterInterface               $router
74
     * @param EventDispatcherInterface      $dispatcher
75
     * @param AuthorizationCheckerInterface $authorizationChecker
76
     * @param PagesConfiguration            $pagesConfiguration
77
     * @param bool                          $enableExportPageTemplate
78
     * @param bool                          $showDuplicateWithChildren
79
     */
80 8
    public function __construct(
81
        FactoryInterface $factory,
82
        EntityManager $em,
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
83
        RouterInterface $router,
84
        EventDispatcherInterface $dispatcher,
85
        AuthorizationCheckerInterface $authorizationChecker,
86
        PagesConfiguration $pagesConfiguration,
87
        $enableExportPageTemplate = true,
88
        bool $showDuplicateWithChildren = false
89
    ) {
90 8
        $this->factory = $factory;
91 8
        $this->em = $em;
92 8
        $this->router = $router;
93 8
        $this->dispatcher = $dispatcher;
94 8
        $this->authorizationChecker = $authorizationChecker;
95 8
        $this->pagesConfiguration = $pagesConfiguration;
96 8
        $this->enableExportPageTemplate = $enableExportPageTemplate;
97 8
        $this->showDuplicateWithChildren = $showDuplicateWithChildren;
98 8
    }
99
100
    /**
101
     * @return ItemInterface
102
     */
103 1
    public function createSubActionsMenu()
104
    {
105 1
        $activeNodeVersion = $this->getActiveNodeVersion();
106 1
        $menu = $this->factory->createItem('root');
107 1
        $menu->setChildrenAttribute('class', 'page-sub-actions');
108
109 1
        if (null !== $activeNodeVersion && $this->isEditableNode) {
110 1
            $menu->addChild(
111 1
                'subaction.versions',
112
                [
113
                    'linkAttributes' => [
114 1
                        'data-toggle' => 'modal',
115
                        'data-keyboard' => 'true',
116
                        'data-target' => '#versions',
117
                    ],
118
                ]
119
            );
120
        }
121
122 1
        $this->dispatcher->dispatch(
123 1
            Events::CONFIGURE_SUB_ACTION_MENU,
124 1
            new ConfigureActionMenuEvent(
125 1
                $this->factory,
126
                $menu,
127
                $activeNodeVersion
128
            )
129
        );
130
131 1
        return $menu;
132
    }
133
134
    /**
135
     * @return ItemInterface
136
     */
137 6
    public function createActionsMenu()
138
    {
139 6
        $activeNodeVersion = $this->getActiveNodeVersion();
140
141 6
        $translations = $activeNodeVersion->getNodeTranslation()->getNode()->getNodeTranslations(true);
142 6
        $canRecopy = false;
143 6
        foreach ($translations as $translation) {
144 1
            if ($translation->getLang() != $activeNodeVersion->getNodeTranslation()->getLang()) {
145 1
                $canRecopy = true;
146
            }
147
        }
148
149 6
        $menu = $this->factory->createItem('root');
150 6
        $menu->setChildrenAttribute(
151 6
            'class',
152 6
            'page-main-actions js-auto-collapse-buttons'
153
        );
154 6
        $menu->setChildrenAttribute(
155 6
            'data-visible-buttons',
156 6
            '3'
157
        );
158
159 6
        if (null === $activeNodeVersion) {
160
            $this->dispatcher->dispatch(
161
                Events::CONFIGURE_ACTION_MENU,
162
                new ConfigureActionMenuEvent(
163
                    $this->factory,
164
                    $menu,
165
                    $activeNodeVersion
166
                )
167
            );
168
169
            return $menu;
170
        }
171
172 6
        $activeNodeTranslation = $activeNodeVersion->getNodeTranslation();
173 6
        $node = $activeNodeTranslation->getNode();
174 6
        $queuedNodeTranslationAction = $this->em->getRepository(QueuedNodeTranslationAction::class)->findOneBy(['nodeTranslation' => $activeNodeTranslation]);
175
176 6
        $isFirst = true;
177 6
        $canEdit = $this->authorizationChecker->isGranted(PermissionMap::PERMISSION_EDIT, $node);
178 6
        $canPublish = $this->authorizationChecker->isGranted(PermissionMap::PERMISSION_PUBLISH, $node);
179 6
        $isSuperAdmin = $this->authorizationChecker->isGranted(UserInterface::ROLE_SUPER_ADMIN);
180
181 6
        if ($activeNodeVersion->isDraft() && $this->isEditableNode) {
182 1 View Code Duplication
            if ($canEdit) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
183 1
                $menu->addChild(
184 1
                    'action.saveasdraft',
185
                    [
186
                        'linkAttributes' => [
187 1
                            'type' => 'submit',
188
                            'class' => 'js-save-btn btn btn--raise-on-hover btn-primary',
189
                            'value' => 'save',
190
                            'name' => 'save',
191
                        ],
192
                        'extras' => ['renderType' => 'button'],
193
                    ]
194
                );
195 1
                if ($this->enableExportPageTemplate && $isSuperAdmin && is_subclass_of($node->getRefEntityName(), HasPageTemplateInterface::class)) {
196
                    $menu->addChild(
197
                        'action.exportpagetemplate',
198
                        [
199
                            'linkAttributes' => [
200
                                'class' => 'btn btn-default btn--raise-on-hover',
201
                                'data-toggle' => 'modal',
202
                                'data-keyboard' => 'true',
203
                                'data-target' => '#exportPagetemplate',
204
                            ],
205
                        ]
206
                    );
207
                }
208 1
                if ($canRecopy) {
209
                    $menu->addChild(
210
                        'action.recopyfromlanguage',
211
                        [
212
                            'linkAttributes' => [
213
                                'class' => 'btn btn-default btn--raise-on-hover',
214
                                'data-toggle' => 'modal',
215
                                'data-keyboard' => 'true',
216
                                'data-target' => '#recopy',
217
                            ],
218
                        ]
219
                    );
220
                }
221 1
                $isFirst = false;
222
            }
223
224 1
            $menu->addChild(
225 1
                'action.preview',
226
                [
227 1
                    'uri' => $this->router->generate(
228 1
                        '_slug_preview',
229
                        [
230 1
                            'url' => $activeNodeTranslation->getUrl(),
231 1
                            'version' => $activeNodeVersion->getId(),
232
                        ]
233
                    ),
234
                    'linkAttributes' => [
235
                        'target' => '_blank',
236
                        'class' => 'btn btn-default btn--raise-on-hover',
237
                    ],
238
                ]
239
            );
240
241 1 View Code Duplication
            if (empty($queuedNodeTranslationAction) && $canPublish) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
242 1
                $menu->addChild(
243 1
                    'action.publish',
244
                    [
245
                        'linkAttributes' => [
246 1
                            'data-toggle' => 'modal',
247 1
                            'data-target' => '#pub',
248 1
                            'class' => 'btn btn--raise-on-hover'.($isFirst ? ' btn-primary btn-save' : ' btn-default'),
249
                        ],
250
                    ]
251
                );
252
            }
253
        } else {
254 5
            if ($canEdit && $canPublish) {
255 5
                $menu->addChild(
256 5
                    'action.save',
257
                    [
258
                        'linkAttributes' => [
259 5
                            'type' => 'submit',
260
                            'class' => 'js-save-btn btn btn--raise-on-hover btn-primary',
261
                            'value' => 'save',
262
                            'name' => 'save',
263
                        ],
264
                        'extras' => ['renderType' => 'button'],
265
                    ]
266
                );
267 5
                $isFirst = false;
268
            }
269
270 5
            if ($this->isEditableNode) {
271 4
                $menu->addChild(
272 4
                    'action.preview',
273
                    [
274 4
                        'uri' => $this->router->generate(
275 4
                            '_slug_preview',
276 4
                            ['url' => $activeNodeTranslation->getUrl()]
277
                        ),
278
                        'linkAttributes' => [
279
                            'target' => '_blank',
280
                            'class' => 'btn btn-default btn--raise-on-hover',
281
                        ],
282
                    ]
283
                );
284
285 4
                if (empty($queuedNodeTranslationAction)
286 4
                    && $activeNodeTranslation->isOnline()
287 1
                    && $this->authorizationChecker->isGranted(
288 4
                        PermissionMap::PERMISSION_UNPUBLISH,
289
                        $node
290
                    )
291
                ) {
292 1
                    $menu->addChild(
293 1
                        'action.unpublish',
294
                        [
295
                            'linkAttributes' => [
296 1
                                'class' => 'btn btn-default btn--raise-on-hover',
297
                                'data-toggle' => 'modal',
298
                                'data-keyboard' => 'true',
299
                                'data-target' => '#unpub',
300
                            ],
301
                        ]
302
                    );
303 4 View Code Duplication
                } elseif (empty($queuedNodeTranslationAction)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
304 4
                    && !$activeNodeTranslation->isOnline()
305 4
                    && $canPublish
306
                ) {
307 4
                    $menu->addChild(
308 4
                        'action.publish',
309
                        [
310
                            'linkAttributes' => [
311 4
                                'class' => 'btn btn-default btn--raise-on-hover',
312
                                'data-toggle' => 'modal',
313
                                'data-keyboard' => 'true',
314
                                'data-target' => '#pub',
315
                            ],
316
                        ]
317
                    );
318
                }
319
320 4 View Code Duplication
                if ($canEdit) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
321 4
                    $menu->addChild(
322 4
                        'action.saveasdraft',
323
                        [
324
                            'linkAttributes' => [
325 4
                                'type' => 'submit',
326 4
                                'class' => 'btn btn--raise-on-hover'.($isFirst ? ' btn-primary btn-save' : ' btn-default'),
327 4
                                'value' => 'saveasdraft',
328 4
                                'name' => 'saveasdraft',
329
                            ],
330
                            'extras' => ['renderType' => 'button'],
331
                        ]
332
                    );
333 4
                    if ($this->enableExportPageTemplate && $isSuperAdmin && is_subclass_of($node->getRefEntityName(), HasPageTemplateInterface::class)) {
334
                        $menu->addChild(
335
                            'action.exportpagetemplate',
336
                            [
337
                                'linkAttributes' => [
338
                                    'class' => 'btn btn-default btn--raise-on-hover',
339
                                    'data-toggle' => 'modal',
340
                                    'data-keyboard' => 'true',
341
                                    'data-target' => '#exportPagetemplate',
342
                                ],
343
                            ]
344
                        );
345
                    }
346 4
                    if ($canRecopy) {
347 1
                        $menu->addChild(
348 1
                            'action.recopyfromlanguage',
349
                            [
350
                                'linkAttributes' => [
351 1
                                    'class' => 'btn btn-default btn--raise-on-hover',
352
                                    'data-toggle' => 'modal',
353
                                    'data-keyboard' => 'true',
354
                                    'data-target' => '#recopy',
355
                                ],
356
                            ]
357
                        );
358
                    }
359
                }
360
            }
361
        }
362
363 6 View Code Duplication
        if ($this->pagesConfiguration->getPossibleChildTypes(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
364 6
            $node->getRefEntityName()
365
        )
366
        ) {
367
            $menu->addChild(
368
                'action.addsubpage',
369
                [
370
                    'linkAttributes' => [
371
                        'type' => 'button',
372
                        'class' => 'btn btn-default btn--raise-on-hover',
373
                        'data-toggle' => 'modal',
374
                        'data-keyboard' => 'true',
375
                        'data-target' => '#add-subpage-modal',
376
                    ],
377
                    'extras' => ['renderType' => 'button'],
378
                ]
379
            );
380
        }
381
382 6
        if (null !== $node->getParent() && $canEdit) {
383 1
            $menu->addChild(
384 1
                'action.duplicate',
385
                [
386
                    'linkAttributes' => [
387 1
                        'type' => 'button',
388
                        'class' => 'btn btn-default btn--raise-on-hover',
389
                        'data-toggle' => 'modal',
390
                        'data-keyboard' => 'true',
391
                        'data-target' => '#duplicate-page-modal',
392
                    ],
393
                    'extras' => ['renderType' => 'button'],
394
                ]
395
            );
396
397 1 View Code Duplication
            if ($this->showDuplicateWithChildren) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
398
                $menu->addChild(
399
                    'action.duplicate_with_children',
400
                    [
401
                        'linkAttributes' => [
402
                            'type' => 'button',
403
                            'class' => 'btn btn-default btn--raise-on-hover',
404
                            'data-toggle' => 'modal',
405
                            'data-keyboard' => 'true',
406
                            'data-target' => '#duplicate-with-children-page-modal',
407
                        ],
408
                        'extras' => ['renderType' => 'button'],
409
                    ]
410
                );
411
            }
412
        }
413
414 6
        if ((null !== $node->getParent() || $node->getChildren()->isEmpty())
415 6
            && $this->authorizationChecker->isGranted(
416 6
                PermissionMap::PERMISSION_DELETE,
417
                $node
418
            )
419
        ) {
420 6
            $menu->addChild(
421 6
                'action.delete',
422
                [
423
                    'linkAttributes' => [
424 6
                        'type' => 'button',
425
                        'class' => 'btn btn-default btn--raise-on-hover',
426
                        'onClick' => 'oldEdited = isEdited; isEdited=false',
427
                        'data-toggle' => 'modal',
428
                        'data-keyboard' => 'true',
429
                        'data-target' => '#delete-page-modal',
430
                    ],
431
                    'extras' => ['renderType' => 'button'],
432
                ]
433
            );
434
        }
435
436 6
        $this->dispatcher->dispatch(
437 6
            Events::CONFIGURE_ACTION_MENU,
438 6
            new ConfigureActionMenuEvent(
439 6
                $this->factory,
440
                $menu,
441
                $activeNodeVersion
442
            )
443
        );
444
445 6
        return $menu;
446
    }
447
448
    /**
449
     * @return ItemInterface
450
     */
451 1
    public function createTopActionsMenu()
452
    {
453 1
        $menu = $this->createActionsMenu();
454 1
        $menu->setChildrenAttribute('id', 'page-main-actions-top');
455 1
        $menu->setChildrenAttribute(
456 1
            'class',
457 1
            'page-main-actions page-main-actions--top'
458
        );
459
460 1
        return $menu;
461
    }
462
463
    /**
464
     * @return ItemInterface
465
     */
466
    public function createHomeActionsMenu()
467
    {
468
        $menu = $this->factory->createItem('root');
469
        $menu->setChildrenAttribute(
470
            'class',
471
            'page-main-actions js-auto-collapse-buttons'
472
        );
473
        $menu->addChild(
474
            'action.addhomepage',
475
            [
476
                'linkAttributes' => [
477
                    'type' => 'button',
478
                    'class' => 'btn btn-default btn--raise-on-hover',
479
                    'data-toggle' => 'modal',
480
                    'data-keyboard' => 'true',
481
                    'data-target' => '#add-homepage-modal',
482
                ],
483
                'extras' => ['renderType' => 'button'],
484
            ]
485
        );
486
487
        return $menu;
488
    }
489
490
    /**
491
     * @return ItemInterface
492
     */
493
    public function createTopHomeActionsMenu()
494
    {
495
        $menu = $this->createHomeActionsMenu();
496
        $menu->setChildrenAttribute('id', 'page-main-actions-top');
497
        $menu->setChildrenAttribute(
498
            'class',
499
            'page-main-actions page-main-actions--top'
500
        );
501
502
        return $menu;
503
    }
504
505
    /**
506
     * Set activeNodeVersion
507
     *
508
     * @param NodeVersion $activeNodeVersion
509
     *
510
     * @return ActionsMenuBuilder
511
     */
512 8
    public function setActiveNodeVersion(NodeVersion $activeNodeVersion)
513
    {
514 8
        $this->activeNodeVersion = $activeNodeVersion;
515
516 8
        return $this;
517
    }
518
519
    /**
520
     * Get activeNodeVersion
521
     *
522
     * @return NodeVersion
523
     */
524 8
    public function getActiveNodeVersion()
525
    {
526 8
        return $this->activeNodeVersion;
527
    }
528
529
    /**
530
     * @param bool $value
531
     */
532 1
    public function setEditableNode($value)
533
    {
534 1
        $this->isEditableNode = $value;
535 1
    }
536
}
537