Passed
Push — master ( 123b22...6ed3d5 )
by Jan
09:22 queued 11s
created

PartsTableActionHandler::handleAction()   C

Complexity

Conditions 13
Paths 10

Size

Total Lines 41
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 33
c 1
b 0
f 0
nc 10
nop 3
dl 0
loc 41
rs 6.6166

How to fix   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
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
4
 *
5
 * Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as published
9
 * by the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
namespace App\Services\Parts;
22
23
24
use App\Entity\Parts\Category;
25
use App\Entity\Parts\Footprint;
26
use App\Entity\Parts\Manufacturer;
27
use App\Entity\Parts\MeasurementUnit;
28
use App\Entity\Parts\Part;
29
use Doctrine\ORM\EntityManagerInterface;
30
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
31
use Symfony\Component\Security\Core\Security;
32
33
final class PartsTableActionHandler
34
{
35
    private $entityManager;
36
    private $security;
37
38
    public function __construct(EntityManagerInterface $entityManager, Security $security)
39
    {
40
        $this->entityManager = $entityManager;
41
        $this->security = $security;
42
    }
43
44
    /**
45
     * Converts the given array to an array of Parts
46
     * @param  string  $ids A comma separated list of Part IDs.
47
     * @return Part[]
48
     */
49
    public function idStringToArray(string $ids): array
50
    {
51
        $id_array = explode(',', $ids);
52
53
        $repo = $this->entityManager->getRepository(Part::class);
54
        return $repo->getElementsFromIDArray($id_array);
55
    }
56
57
    /**
58
     * @param  string  $action
59
     * @param  Part[]  $selected_parts
60
     * @param  int|null  $target_id
61
     */
62
    public function handleAction(string $action, array $selected_parts, ?int $target_id): void
63
    {
64
        //Iterate over the parts and apply the action to it:
65
        foreach ($selected_parts as $part) {
66
            if (!$part instanceof Part) {
67
                throw new \InvalidArgumentException('$selected_parts must be an array of Part elements!');
68
            }
69
70
            //We modify parts, so you have to have the permission to modify it
71
            $this->denyAccessUnlessGranted('edit', $part);
72
73
            switch ($action) {
74
                case 'favorite':
75
                    $part->setFavorite(true);
76
                    break;
77
                case 'unfavorite':
78
                    $part->setFavorite(false);
79
                    break;
80
                case 'delete':
81
                    $this->denyAccessUnlessGranted('delete', $part);
82
                    $this->entityManager->remove($part);
83
                    break;
84
                case 'change_category':
85
                    $this->denyAccessUnlessGranted('category.edit', $part);
86
                    $part->setCategory($this->entityManager->find(Category::class, $target_id));
87
                    break;
88
                case 'change_footprint':
89
                    $this->denyAccessUnlessGranted('footprint.edit', $part);
90
                    $part->setFootprint($target_id === null ? null : $this->entityManager->find(Footprint::class, $target_id));
91
                    break;
92
                case 'change_manufacturer':
93
                    $this->denyAccessUnlessGranted('manufacturer.edit', $part);
94
                    $part->setManufacturer($target_id === null ? null : $this->entityManager->find(Manufacturer::class, $target_id));
95
                    break;
96
                case 'change_unit':
97
                    $this->denyAccessUnlessGranted('unit.edit', $part);
98
                    $part->setPartUnit($target_id === null ? null : $this->entityManager->find(MeasurementUnit::class, $target_id));
99
                    break;
100
101
                default:
102
                    throw new \InvalidArgumentException('The given action is unknown! (' . $action . ')');
103
            }
104
        }
105
    }
106
107
    /**
108
     * Throws an exception unless the attributes are granted against the current authentication token and optionally
109
     * supplied subject.
110
     *
111
     * @throws AccessDeniedException
112
     */
113
    private function denyAccessUnlessGranted($attributes, $subject = null, string $message = 'Access Denied.'): void
114
    {
115
        if (!$this->security->isGranted($attributes, $subject)) {
116
            $exception = new AccessDeniedException($message);
117
            $exception->setAttributes($attributes);
118
            $exception->setSubject($subject);
119
120
            throw $exception;
121
        }
122
    }
123
}