CreateTaskHandler::areTaskAndParentIdsDifferent()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 2
nc 3
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Kreta package.
5
 *
6
 * (c) Beñat Espiña <[email protected]>
7
 * (c) Gorka Laucirica <[email protected]>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
declare(strict_types=1);
14
15
namespace Kreta\TaskManager\Application\Command\Project\Task;
16
17
use Kreta\TaskManager\Domain\Model\Organization\MemberId;
18
use Kreta\TaskManager\Domain\Model\Organization\Organization;
19
use Kreta\TaskManager\Domain\Model\Organization\OrganizationMemberDoesNotExistException;
20
use Kreta\TaskManager\Domain\Model\Organization\OrganizationRepository;
21
use Kreta\TaskManager\Domain\Model\Project\Project;
22
use Kreta\TaskManager\Domain\Model\Project\ProjectDoesNotExistException;
23
use Kreta\TaskManager\Domain\Model\Project\ProjectId;
24
use Kreta\TaskManager\Domain\Model\Project\ProjectRepository;
25
use Kreta\TaskManager\Domain\Model\Project\Task\NumericId;
26
use Kreta\TaskManager\Domain\Model\Project\Task\Task;
27
use Kreta\TaskManager\Domain\Model\Project\Task\TaskAlreadyExistsException;
28
use Kreta\TaskManager\Domain\Model\Project\Task\TaskAndTaskParentCannotBeTheSameException;
29
use Kreta\TaskManager\Domain\Model\Project\Task\TaskId;
30
use Kreta\TaskManager\Domain\Model\Project\Task\TaskParentDoesNotExistException;
31
use Kreta\TaskManager\Domain\Model\Project\Task\TaskPriority;
32
use Kreta\TaskManager\Domain\Model\Project\Task\TaskRepository;
33
use Kreta\TaskManager\Domain\Model\Project\Task\TaskSpecificationFactory;
34
use Kreta\TaskManager\Domain\Model\Project\Task\TaskTitle;
35
use Kreta\TaskManager\Domain\Model\Project\Task\UnauthorizedTaskActionException;
36
use Kreta\TaskManager\Domain\Model\User\UserId;
37
38
class CreateTaskHandler
39
{
40
    private $repository;
41
    private $specificationFactory;
42
    private $projectRepository;
43
    private $organizationRepository;
44
45
    public function __construct(
46
        TaskRepository $repository,
47
        TaskSpecificationFactory $specificationFactory,
48
        ProjectRepository $projectRepository,
49
        OrganizationRepository $organizationRepository
50
    ) {
51
        $this->repository = $repository;
52
        $this->specificationFactory = $specificationFactory;
53
        $this->projectRepository = $projectRepository;
54
        $this->organizationRepository = $organizationRepository;
55
    }
56
57
    public function __invoke(CreateTaskCommand $command)
58
    {
59
        $taskId = $command->taskId();
60
        $parentTaskId = $command->parentId();
61
62
        if (!$this->areTaskAndParentIdsDifferent($taskId, $parentTaskId)) {
63
            throw new TaskAndTaskParentCannotBeTheSameException();
64
        }
65
66
        $task = $this->repository->taskOfId(TaskId::generate($taskId));
67
        if ($this->doesTaskExist($task)) {
68
            throw new TaskAlreadyExistsException();
69
        }
70
71
        $parentTask = $this->repository->taskOfId(TaskId::generate($parentTaskId));
72
        if (!$this->doesParentTaskExist($parentTaskId, $parentTask)) {
73
            throw new TaskParentDoesNotExistException();
74
        }
75
76
        $projectId = $command->projectId();
77
        $project = $this->projectRepository->projectOfId(ProjectId::generate($projectId));
78
        if (!$this->doesProjectExist($project)) {
79
            throw new ProjectDoesNotExistException();
80
        }
81
82
        $organizationId = $project->organizationId();
83
        $reporterId = UserId::generate($command->reporterId());
84
        $assigneeId = UserId::generate($command->assigneeId());
85
86
        $organization = $this->organizationRepository->organizationOfId($organizationId);
87
88
        $this->checkUsersAreOrganizationMembers($organization, $reporterId, $assigneeId);
89
90
        $taskId = TaskId::generate($taskId);
91
        $title = new TaskTitle($command->title());
92
        $description = $command->description();
93
        $reporter = $this->becomeUserIdToDomainMemberId($organization, $reporterId);
94
        $assignee = $this->becomeUserIdToDomainMemberId($organization, $assigneeId);
95
        $priority = new TaskPriority($command->priority());
96
        $projectId = ProjectId::generate($projectId);
97
        $parentTaskId = $this->parentTaskId($parentTaskId);
98
99
        $tasksNumber = $this->repository->count(
100
            $this->specificationFactory->buildByProjectSpecification($projectId)
101
        );
102
        $numericId = NumericId::fromPrevious($tasksNumber);
103
104
        $task = new Task(
105
            $taskId,
106
            $numericId,
107
            $title,
108
            $description,
109
            $reporter,
110
            $assignee,
111
            $priority,
112
            $projectId,
113
            $parentTaskId
114
        );
115
        $this->repository->persist($task);
116
    }
117
118
    private function areTaskAndParentIdsDifferent(?string $taskId, ?string $parentTaskId) : bool
119
    {
120
        return ($taskId === null && $parentTaskId === null) || $parentTaskId !== $taskId;
121
    }
122
123
    private function doesTaskExist(?Task $task) : bool
124
    {
125
        return $task instanceof Task;
126
    }
127
128
    private function doesParentTaskExist(?string $parentTaskId, Task $parentTask = null) : bool
129
    {
130
        return null === $parentTaskId || $parentTask instanceof Task;
131
    }
132
133
    private function doesProjectExist(?Project $project) : bool
134
    {
135
        return $project instanceof Project;
136
    }
137
138
    private function checkUsersAreOrganizationMembers(
139
        Organization $organization,
140
        UserId $reporterId,
141
        UserId $assigneeId
142
    ) : void {
143
        $this->checkReporterIsOrganizationMember($organization, $reporterId);
144
        $this->checkAssigneeIsOrganizationMember($organization, $assigneeId);
145
    }
146
147
    private function checkAssigneeIsOrganizationMember(Organization $organization, UserId $assigneeId) : void
148
    {
149
        if (!$organization->isOrganizationMember($assigneeId)) {
150
            throw new OrganizationMemberDoesNotExistException($assigneeId);
151
        }
152
    }
153
154
    private function checkReporterIsOrganizationMember(Organization $organization, UserId $reporterId) : void
155
    {
156
        if (!$organization->isOrganizationMember($reporterId)) {
157
            throw new UnauthorizedTaskActionException();
158
        }
159
    }
160
161
    private function parentTaskId(?string $parentTaskId) : ?TaskId
162
    {
163
        return null === $parentTaskId ? null : TaskId::generate($parentTaskId);
164
    }
165
166
    private function becomeUserIdToDomainMemberId(Organization $organization, UserId $userId) : MemberId
167
    {
168
        return $organization->organizationMember($userId)->id();
169
    }
170
}
171