Completed
Push — master ( 3eb757...3bc7c8 )
by Oleg
03:46
created

SavePermissionsAction   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Test Coverage

Coverage 83.78%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 17
dl 0
loc 164
ccs 62
cts 74
cp 0.8378
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 1
B process() 0 41 9
A processResources() 0 23 3
A processItemsToRemove() 0 15 3
A processItemsToAdd() 0 14 2
1
<?php
2
declare(strict_types=1);
3
4
namespace SlayerBirden\DataFlowServer\Authorization\Controller;
5
6
use Doctrine\Common\Collections\Criteria;
7
use Doctrine\Common\Collections\Selectable;
8
use Doctrine\ORM\ORMException;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\ServerRequestInterface;
11
use Psr\Http\Server\MiddlewareInterface;
12
use Psr\Http\Server\RequestHandlerInterface;
13
use Psr\Log\LoggerInterface;
14
use SlayerBirden\DataFlowServer\Authorization\Entities\Permission;
15
use SlayerBirden\DataFlowServer\Authorization\Exception\NoChangesException;
16
use SlayerBirden\DataFlowServer\Authorization\HistoryManagementInterface;
17
use SlayerBirden\DataFlowServer\Doctrine\Middleware\ResourceMiddlewareInterface;
18
use SlayerBirden\DataFlowServer\Doctrine\Persistence\EntityManagerRegistry;
19
use SlayerBirden\DataFlowServer\Domain\Entities\ClaimedResourceInterface;
20
use SlayerBirden\DataFlowServer\Domain\Entities\User;
21
use SlayerBirden\DataFlowServer\Stdlib\Validation\DataValidationResponseFactory;
22
use SlayerBirden\DataFlowServer\Stdlib\Validation\GeneralErrorResponseFactory;
23
use SlayerBirden\DataFlowServer\Stdlib\Validation\GeneralSuccessResponseFactory;
24
use SlayerBirden\DataFlowServer\Stdlib\Validation\ValidationResponseFactory;
25
use Zend\Hydrator\HydratorInterface;
26
use Zend\InputFilter\InputFilterInterface;
27
28
final class SavePermissionsAction implements MiddlewareInterface
29
{
30
    /**
31
     * @var LoggerInterface
32
     */
33
    private $logger;
34
    /**
35
     * @var InputFilterInterface
36
     */
37
    private $inputFilter;
38
    /**
39
     * @var HistoryManagementInterface
40
     */
41
    private $historyManagement;
42
    /**
43
     * @var HydratorInterface
44
     */
45
    private $hydrator;
46
    /**
47
     * @var EntityManagerRegistry
48
     */
49
    private $managerRegistry;
50
    /**
51
     * @var Selectable
52
     */
53
    private $permissionRepository;
54
55 10
    public function __construct(
56
        EntityManagerRegistry $managerRegistry,
57
        Selectable $permissionRepository,
58
        LoggerInterface $logger,
59
        InputFilterInterface $inputFilter,
60
        HistoryManagementInterface $historyManagement,
61
        HydratorInterface $hydrator
62
    ) {
63 10
        $this->managerRegistry = $managerRegistry;
64 10
        $this->permissionRepository = $permissionRepository;
65 10
        $this->logger = $logger;
66 10
        $this->inputFilter = $inputFilter;
67 10
        $this->historyManagement = $historyManagement;
68 10
        $this->hydrator = $hydrator;
69 10
    }
70
71
    /**
72
     * @inheritdoc
73
     */
74 10
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
75
    {
76 10
        $data = $request->getParsedBody();
77 10
        if (!is_array($data)) {
78
            return (new DataValidationResponseFactory())('permissions', []);
79
        }
80 10
        $user = $request->getAttribute(ResourceMiddlewareInterface::DATA_RESOURCE);
81
82 10
        $this->inputFilter->setData($data);
83 10
        if (!$this->inputFilter->isValid()) {
84 4
            return (new ValidationResponseFactory())('permissions', $this->inputFilter, []);
85
        }
86
        try {
87 6
            $em = $this->managerRegistry->getManagerForClass(Permission::class);
88 6
            $em->beginTransaction();
89 6
            $permissions = $this->processResources(
90 6
                $user,
91 6
                $data[ClaimedResourceInterface::OWNER_PARAM],
92 6
                ...$data['resources']
93
            );
94 6
            $em->flush();
95 6
            $em->commit();
96 6
            $msg = 'Successfully set permissions to resources.';
97 6
            $extractedPermissions = array_map([$this->hydrator, 'extract'], $permissions);
98 6
            $count = count($extractedPermissions);
99 6
            return (new GeneralSuccessResponseFactory())($msg, 'permissions', $extractedPermissions, 200, $count);
100
        } catch (ORMException $exception) {
101
            $this->logger->error((string)$exception);
102
            if (isset($em) && $em->getConnection()->isTransactionActive()) {
103
                $em->rollback();
104
            }
105
            $msg = 'There was an error while setting the permissions.';
106
            return (new GeneralErrorResponseFactory())($msg, 'permissions', 400, [], 0);
107
        } catch (\Exception $exception) {
108
            $this->logger->error((string)$exception);
109
            if (isset($em) && $em->getConnection()->isTransactionActive()) {
110
                $em->rollback();
111
            }
112
            return (new GeneralErrorResponseFactory())('Internal error', 'permissions', 500, [], 0);
113
        }
114
    }
115
116
    /**
117
     * @param User $user
118
     * @param User $owner
119
     * @param string ...$resources
120
     * @return Permission[]
121
     * @throws ORMException
122
     */
123 6
    private function processResources(User $user, User $owner, string ...$resources): array
124
    {
125 6
        $result = [];
126 6
        $collection = $this->permissionRepository->matching(
127 6
            Criteria::create()->where(Criteria::expr()->eq('user', $user))
128
        );
129
130
        $currentResources = array_map(function (Permission $permission) {
131 6
            return $permission->getResource();
132 6
        }, $collection->toArray());
133
134 6
        $toRemove = array_diff($currentResources, $resources);
135 6
        $toAdd = array_diff($resources, $currentResources);
136
137 6
        if (empty($toAdd) && empty($toRemove)) {
138 2
            return [];
139
        }
140
141 4
        $this->processItemsToRemove($collection, $toRemove, $owner, $result);
142 4
        $this->processItemsToAdd($toAdd, $user, $owner, $result);
143
144 4
        return $result;
145
    }
146
147
    /**
148
     * @param $collection
149
     * @param $toRemove
150
     * @param $owner
151
     * @param $result
152
     * @throws ORMException
153
     */
154 4
    private function processItemsToRemove($collection, $toRemove, $owner, &$result): void
155
    {
156 4
        $em = $this->managerRegistry->getManagerForClass(Permission::class);
157
        /** @var Permission $permission */
158 4
        foreach ($collection as $permission) {
159 4
            if (in_array($permission->getResource(), $toRemove, true)) {
160 2
                $em->remove($permission);
161 2
                $history = $this->historyManagement->fromPermission($permission);
162 2
                $history->setOwner($owner);
163 2
                $em->persist($history);
164
            } else {
165 2
                $result[] = $permission;
166
            }
167
        }
168 4
    }
169
170
    /**
171
     * @param $toAdd
172
     * @param $user
173
     * @param $owner
174
     * @param $result
175
     * @throws ORMException
176
     */
177 4
    private function processItemsToAdd($toAdd, $user, $owner, &$result): void
178
    {
179 4
        $em = $this->managerRegistry->getManagerForClass(Permission::class);
180 4
        foreach ($toAdd as $resource) {
181 4
            $permission = new Permission();
182 4
            $permission->setResource($resource);
183 4
            $permission->setUser($user);
184 4
            $result[] = $permission;
185 4
            $em->persist($permission);
186 4
            $history = $this->historyManagement->fromPermission($permission);
187 4
            $history->setOwner($owner);
188 4
            $em->persist($history);
189
        }
190 4
    }
191
}
192