Completed
Push — master ( d8b95b...caeb59 )
by Axel
09:34 queued 04:32
created

NodeController::contextMenu()   D

Complexity

Conditions 27
Paths 106

Size

Total Lines 131
Code Lines 94

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 27
eloc 94
c 0
b 0
f 0
nc 106
nop 6
dl 0
loc 131
rs 4.1166

How to fix   Long Method    Complexity   

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 Zikula package.
7
 *
8
 * Copyright Zikula - https://ziku.la/
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 Zikula\CategoriesModule\Controller;
15
16
use Symfony\Component\HttpFoundation\JsonResponse;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\Routing\Annotation\Route;
20
use Zikula\Bundle\CoreBundle\Controller\AbstractController;
21
use Zikula\CategoriesModule\Entity\CategoryEntity;
22
use Zikula\CategoriesModule\Entity\Repository\CategoryRepository;
23
use Zikula\CategoriesModule\Form\Type\CategoryType;
24
use Zikula\CategoriesModule\Helper\CategoryProcessingHelper;
25
use Zikula\PermissionsModule\Annotation\PermissionCheck;
26
use Zikula\SettingsModule\Api\ApiInterface\LocaleApiInterface;
27
28
/**
29
 * Class NodeController
30
 *
31
 * @Route("/admin/category")
32
 * @PermissionCheck("admin")
33
 */
34
class NodeController extends AbstractController
35
{
36
    /**
37
     * @var string
38
     */
39
    private $domTreeNodePrefix = 'node_';
40
41
    /**
42
     * @Route("/contextMenu/{action}/{id}", options={"expose"=true}, defaults={"id" = null})
43
     */
44
    public function contextMenu(
45
        Request $request,
46
        CategoryRepository $categoryRepository,
47
        CategoryProcessingHelper $processingHelper,
48
        LocaleApiInterface $localeApi,
49
        string $action = 'edit',
50
        CategoryEntity $category = null
51
    ): JsonResponse {
52
        if (!in_array($action, ['edit', 'delete', 'deleteandmovechildren', 'copy', 'activate', 'deactivate'])) {
53
            return $this->json($this->trans('Data provided was inappropriate.'), Response::HTTP_BAD_REQUEST);
54
        }
55
        $mode = $request->request->get('mode', 'edit');
56
57
        switch ($action) {
58
            case 'copy':
59
                if (!isset($category)) {
60
                    $category = new CategoryEntity($localeApi->getSupportedLocales());
61
                }
62
                $newCategory = clone $category;
63
                $newCategory->setName($category->getName() . 'copy');
64
                $displayNames = [];
65
                foreach ($newCategory->getDisplayName() as $locale => $displayName) {
66
                    $displayNames[$locale] = $displayName . ' ' . $this->trans('copy');
67
                }
68
                $newCategory->setDisplayName($displayNames);
69
                $action = 'edit';
70
                $mode = 'new';
71
                $category = $newCategory;
72
                // intentionally no break here
73
                // no break
74
            case 'edit':
75
                if (!isset($category)) {
76
                    $category = new CategoryEntity($localeApi->getSupportedLocales());
77
                    $parentId = $request->request->get('parent');
78
                    $mode = 'new';
79
                    if (!empty($parentId)) {
80
                        /** @var CategoryEntity $parent */
81
                        $parent = $categoryRepository->find($parentId);
82
                        $category->setParent($parent);
83
                        $category->setRoot($parent->getRoot());
84
                    } elseif (empty($parentId) && $request->request->has('after')) { // sibling of top-level child
85
                        /** @var CategoryEntity $sibling */
86
                        $sibling = $categoryRepository->find($request->request->get('after'));
87
                        $category->setParent($sibling->getParent());
88
                        $category->setRoot($sibling->getRoot());
89
                    }
90
                }
91
                $form = $this->createForm(CategoryType::class, $category, [
92
                    'locales' => $localeApi->getSupportedLocales()
93
                ]);
94
                $form->get('after')->setData($request->request->get('after'));
95
                $form->handleRequest($request);
96
                if ($form->isSubmitted() && $form->isValid()) {
97
                    $category = $form->getData();
98
                    $after = $form->get('after')->getData();
99
                    if (!empty($after)) {
100
                        $sibling = $categoryRepository->find($after);
101
                        $categoryRepository->persistAsNextSiblingOf($category, $sibling);
102
                    } elseif ('new' === $mode) {
103
                        $categoryRepository->persistAsLastChild($category);
104
                    } // no need to persist edited entity
105
                    $this->getDoctrine()->getManager()->flush();
106
107
                    return $this->json([
108
                        'node' => $category->toJson($this->domTreeNodePrefix, $request->getLocale()),
109
                        'mode' => $mode
110
                    ]);
111
                }
112
                $response = [
113
                    'result' => $this->renderView('@ZikulaCategoriesModule/Category/edit.html.twig', [
114
                        'locales' => $localeApi->getSupportedLocaleNames(null, $request->getLocale()),
115
                        'form' => $form->createView()
116
                    ]),
117
                    'action' => $action,
118
                    'id' => $category->getId(),
119
                    'mode' => $mode
120
                ];
121
                break;
122
            case 'deleteandmovechildren':
123
                /** @var CategoryEntity $newParent */
124
                $newParent = $categoryRepository->find($request->request->get('parent', 1));
125
                if (null === $newParent || $newParent === $category->getParent()) {
0 ignored issues
show
Bug introduced by
The method getParent() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

125
                if (null === $newParent || $newParent === $category->/** @scrutinizer ignore-call */ getParent()) {

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...
126
                    $response = ['result' => true];
127
                    break;
128
                }
129
                // move the children
130
                foreach ($category->getChildren() as $child) {
131
                    if ($processingHelper->mayCategoryBeDeletedOrMoved($child)) {
132
                        $category->getChildren()->removeElement($child);
133
                        $newParent->getChildren()->add($child);
134
                        $child->setParent($newParent);
135
                    }
136
                }
137
                $this->getDoctrine()->getManager()->flush();
138
                // intentionally no break here
139
                // no break
140
            case 'delete':
141
                $categoryId = $category->getId();
142
                $this->removeRecursive($category, $processingHelper);
0 ignored issues
show
Bug introduced by
It seems like $category can also be of type null; however, parameter $parent of Zikula\CategoriesModule\...ller::removeRecursive() does only seem to accept Zikula\CategoriesModule\Entity\CategoryEntity, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

142
                $this->removeRecursive(/** @scrutinizer ignore-type */ $category, $processingHelper);
Loading history...
143
                $categoryRemoved = false;
144
                if (0 === $category->getChildren()->count()
145
                    && $processingHelper->mayCategoryBeDeletedOrMoved($category)) {
0 ignored issues
show
Bug introduced by
It seems like $category can also be of type null; however, parameter $category of Zikula\CategoriesModule\...egoryBeDeletedOrMoved() does only seem to accept Zikula\CategoriesModule\Entity\CategoryEntity, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
                    && $processingHelper->mayCategoryBeDeletedOrMoved(/** @scrutinizer ignore-type */ $category)) {
Loading history...
146
                    $this->getDoctrine()->getManager()->remove($category);
147
                    $categoryRemoved = true;
148
                }
149
                $this->getDoctrine()->getManager()->flush();
150
                $response = [
151
                    'result' => $categoryRemoved,
152
                    'id' => $categoryId,
153
                    'action' => $action,
154
                    'parent' => isset($newParent) ? $newParent->getId() : null
155
                ];
156
                $categoryRepository->recover();
157
                $this->getDoctrine()->getManager()->flush();
158
                break;
159
            case 'activate':
160
            case 'deactivate':
161
                $category->setStatus('A' === $category->getStatus() ? 'I' : 'A');
0 ignored issues
show
introduced by
The condition 'A' === $category->getStatus() is always false.
Loading history...
162
                $this->getDoctrine()->getManager()->flush();
163
                $response = [
164
                    'id' => $category->getId(),
165
                    'parent' => null !== $category->getParent() ? $category->getParent()->getId() : null,
166
                    'action' => $action,
167
                    'result' => true
168
                ];
169
                break;
170
            default:
171
                $response = ['result' => true];
172
        }
173
174
        return $this->json($response);
175
    }
176
177
    /**
178
     * Recursive method to remove all generations below parent.
179
     */
180
    private function removeRecursive(CategoryEntity $parent, CategoryProcessingHelper $processingHelper): void
181
    {
182
        $entityManager = $this->getDoctrine()->getManager();
183
        foreach ($parent->getChildren() as $child) {
184
            if ($child->getChildren()->count() > 0) {
185
                $this->removeRecursive($child, $processingHelper);
186
            }
187
            if ($processingHelper->mayCategoryBeDeletedOrMoved($child)) {
188
                $entityManager->remove($child);
189
            }
190
        }
191
    }
192
193
    /**
194
     * Ajax function for use on drag and drop of nodes.
195
     * @Route("/move", options={"expose"=true})
196
     */
197
    public function move(
198
        Request $request,
199
        CategoryRepository $categoryRepository,
200
        CategoryProcessingHelper $processingHelper
201
    ): JsonResponse {
202
        $node = $request->request->get('node');
203
        $entityId = str_replace($this->domTreeNodePrefix, '', $node['id']);
204
        /** @var CategoryEntity $category */
205
        $category = $categoryRepository->find($entityId);
206
        if (!$processingHelper->mayCategoryBeDeletedOrMoved($category)) {
207
            return $this->json(['result' => false]);
208
        }
209
210
        $oldParent = $request->request->get('old_parent');
211
        $oldPosition = (int)$request->request->get('old_position');
212
        $parent = $request->request->get('parent');
213
        $position = (int)$request->request->get('position');
214
        if ($oldParent === $parent) {
215
            $diff = $oldPosition - $position; // if $diff is positive, then node moved up
216
            $methodName = $diff > 0 ? 'moveUp' : 'moveDown';
217
            $categoryRepository->{$methodName}($category, abs($diff));
218
        } else {
219
            $parentEntity = $categoryRepository->find(str_replace($this->domTreeNodePrefix, '', $parent));
220
            if (1 > $position) {
221
                $categoryRepository->persistAsFirstChildOf($category, $parentEntity);
222
            } else {
223
                $children = $categoryRepository->children($parentEntity);
224
                $categoryRepository->persistAsNextSiblingOf($category, $children[$position - 1]);
225
            }
226
        }
227
        $this->getDoctrine()->getManager()->flush();
228
229
        return $this->json(['result' => true]);
230
    }
231
}
232