Completed
Push — master ( 3bc7c8...a199f7 )
by Oleg
03:54
created

SavePermissionsAction::process()   A

Complexity

Conditions 4
Paths 9

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 4.2211

Importance

Changes 0
Metric Value
dl 0
loc 33
ccs 19
cts 25
cp 0.76
rs 9.392
c 0
b 0
f 0
cc 4
nc 9
nop 2
crap 4.2211
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\HistoryManagementInterface;
16
use SlayerBirden\DataFlowServer\Doctrine\Middleware\ResourceMiddlewareInterface;
17
use SlayerBirden\DataFlowServer\Doctrine\Persistence\EntityManagerRegistry;
18
use SlayerBirden\DataFlowServer\Domain\Entities\ClaimedResourceInterface;
19
use SlayerBirden\DataFlowServer\Domain\Entities\User;
20
use SlayerBirden\DataFlowServer\Stdlib\Validation\DataValidationResponseFactory;
21
use SlayerBirden\DataFlowServer\Stdlib\Validation\GeneralErrorResponseFactory;
22
use SlayerBirden\DataFlowServer\Stdlib\Validation\GeneralSuccessResponseFactory;
23
use SlayerBirden\DataFlowServer\Stdlib\Validation\ValidationResponseFactory;
24
use Zend\Hydrator\HydratorInterface;
25
use Zend\InputFilter\InputFilterInterface;
26
27
final class SavePermissionsAction implements MiddlewareInterface
28
{
29
    /**
30
     * @var LoggerInterface
31
     */
32
    private $logger;
33
    /**
34
     * @var InputFilterInterface
35
     */
36
    private $inputFilter;
37
    /**
38
     * @var HistoryManagementInterface
39
     */
40
    private $historyManagement;
41
    /**
42
     * @var HydratorInterface
43
     */
44
    private $hydrator;
45
    /**
46
     * @var EntityManagerRegistry
47
     */
48
    private $managerRegistry;
49
    /**
50
     * @var Selectable
51
     */
52
    private $permissionRepository;
53
54 10
    public function __construct(
55
        EntityManagerRegistry $managerRegistry,
56
        Selectable $permissionRepository,
57
        LoggerInterface $logger,
58
        InputFilterInterface $inputFilter,
59
        HistoryManagementInterface $historyManagement,
60
        HydratorInterface $hydrator
61
    ) {
62 10
        $this->managerRegistry = $managerRegistry;
63 10
        $this->permissionRepository = $permissionRepository;
64 10
        $this->logger = $logger;
65 10
        $this->inputFilter = $inputFilter;
66 10
        $this->historyManagement = $historyManagement;
67 10
        $this->hydrator = $hydrator;
68 10
    }
69
70
    /**
71
     * @inheritdoc
72
     * @throws ORMException
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 6
        $em = $this->managerRegistry->getManagerForClass(Permission::class);
87 6
        $em->beginTransaction();
88
        try {
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
            $em->rollback();
103
            $msg = 'There was an error while setting the permissions.';
104
            return (new GeneralErrorResponseFactory())($msg, 'permissions', 400, [], 0);
105
        }
106
    }
107
108
    /**
109
     * @param User $user
110
     * @param User $owner
111
     * @param string ...$resources
112
     * @return Permission[]
113
     * @throws ORMException
114
     */
115 6
    private function processResources(User $user, User $owner, string ...$resources): array
116
    {
117 6
        $result = [];
118 6
        $collection = $this->permissionRepository->matching(
119 6
            Criteria::create()->where(Criteria::expr()->eq('user', $user))
120
        );
121
122
        $currentResources = array_map(function (Permission $permission) {
123 6
            return $permission->getResource();
124 6
        }, $collection->toArray());
125
126 6
        $toRemove = array_diff($currentResources, $resources);
127 6
        $toAdd = array_diff($resources, $currentResources);
128
129 6
        if (empty($toAdd) && empty($toRemove)) {
130 2
            return [];
131
        }
132
133 4
        $this->processItemsToRemove($collection, $toRemove, $owner, $result);
134 4
        $this->processItemsToAdd($toAdd, $user, $owner, $result);
135
136 4
        return $result;
137
    }
138
139
    /**
140
     * @param $collection
141
     * @param $toRemove
142
     * @param $owner
143
     * @param $result
144
     * @throws ORMException
145
     */
146 4
    private function processItemsToRemove($collection, $toRemove, $owner, &$result): void
147
    {
148 4
        $em = $this->managerRegistry->getManagerForClass(Permission::class);
149
        /** @var Permission $permission */
150 4
        foreach ($collection as $permission) {
151 4
            if (in_array($permission->getResource(), $toRemove, true)) {
152 2
                $em->remove($permission);
153 2
                $history = $this->historyManagement->fromPermission($permission);
154 2
                $history->setOwner($owner);
155 2
                $em->persist($history);
156
            } else {
157 2
                $result[] = $permission;
158
            }
159
        }
160 4
    }
161
162
    /**
163
     * @param $toAdd
164
     * @param $user
165
     * @param $owner
166
     * @param $result
167
     * @throws ORMException
168
     */
169 4
    private function processItemsToAdd($toAdd, $user, $owner, &$result): void
170
    {
171 4
        $em = $this->managerRegistry->getManagerForClass(Permission::class);
172 4
        foreach ($toAdd as $resource) {
173 4
            $permission = new Permission();
174 4
            $permission->setResource($resource);
175 4
            $permission->setUser($user);
176 4
            $result[] = $permission;
177 4
            $em->persist($permission);
178 4
            $history = $this->historyManagement->fromPermission($permission);
179 4
            $history->setOwner($owner);
180 4
            $em->persist($history);
181
        }
182 4
    }
183
}
184