AbstractModel::getId()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Model;
6
7
use Application\Acl\Acl;
8
use Application\Api\Input\Operator\SearchOperatorType;
9
use Application\Api\Input\Sorting\Owner;
10
use Cake\Chronos\Chronos;
11
use Doctrine\ORM\Event\PreUpdateEventArgs;
12
use Doctrine\ORM\Mapping as ORM;
13
use Ecodev\Felix\Api\Exception;
14
use Ecodev\Felix\Api\Output\PermissionsType;
15
use Ecodev\Felix\Model\HasOwner;
16
use Ecodev\Felix\Model\Model;
17
use GraphQL\Doctrine\Attribute as API;
18
19
/**
20
 * Base class for all objects stored in database.
21
 *
22
 * It includes an automatic mechanism to timestamp objects with date and user.
23
 */
24
#[ORM\Index(name: 'creation_date', columns: ['creation_date'])]
25
#[ORM\Index(name: 'update_date', columns: ['update_date'])]
26
#[API\Filter(field: 'custom', operator: SearchOperatorType::class, type: 'string')]
27
#[API\Sorting(Owner::class)]
28
#[ORM\MappedSuperclass]
29
#[ORM\HasLifecycleCallbacks]
30
abstract class AbstractModel implements HasOwner, Model
31
{
32
    #[ORM\Column(type: 'integer')]
33
    #[ORM\Id]
34
    #[ORM\GeneratedValue(strategy: 'IDENTITY')]
35
    private ?int $id = null;
36
37
    #[ORM\Column(type: 'datetime', nullable: true)]
38
    private ?Chronos $creationDate = null;
39
40
    #[ORM\Column(type: 'datetime', nullable: true)]
41
    private ?Chronos $updateDate = null;
42
43
    #[ORM\JoinColumn(onDelete: 'SET NULL')]
44
    #[ORM\ManyToOne(targetEntity: User::class)]
45
    private ?User $creator = null;
46
47
    #[ORM\JoinColumn(onDelete: 'SET NULL')]
48
    #[ORM\ManyToOne(targetEntity: User::class)]
49
    private ?User $owner = null;
50
51
    #[ORM\JoinColumn(onDelete: 'SET NULL')]
52
    #[ORM\ManyToOne(targetEntity: User::class)]
53
    private ?User $updater = null;
54
55
    /**
56
     * Get id.
57
     */
58 55
    public function getId(): ?int
59
    {
60 55
        return $this->id;
61
    }
62
63
    /**
64
     * Set creation date.
65
     */
66 37
    private function setCreationDate(Chronos $creationDate): void
67
    {
68 37
        $this->creationDate = $creationDate;
69
    }
70
71
    /**
72
     * Get creation date.
73
     */
74
    public function getCreationDate(): ?Chronos
75
    {
76
        return $this->creationDate;
77
    }
78
79
    /**
80
     * Set update date.
81
     */
82 46
    private function setUpdateDate(Chronos $updateDate): void
83
    {
84 46
        $this->updateDate = $updateDate;
85
    }
86
87
    /**
88
     * Get update date.
89
     */
90
    public function getUpdateDate(): ?Chronos
91
    {
92
        return $this->updateDate;
93
    }
94
95
    /**
96
     * Set creator.
97
     */
98 37
    private function setCreator(?User $creator): void
99
    {
100 37
        $this->creator = $creator;
101
    }
102
103
    /**
104
     * Get creator.
105
     */
106
    public function getCreator(): ?User
107
    {
108
        return $this->creator;
109
    }
110
111
    /**
112
     * Set owner.
113
     */
114 44
    public function setOwner(?User $owner): void
115
    {
116 44
        if ($owner === $this->owner) {
117 26
            return;
118
        }
119
120 26
        $user = User::getCurrent();
121 26
        $isAdmin = $user && $user->getRole() === User::ROLE_ADMINISTRATOR;
122 26
        $isOwner = $user === $this->owner;
123
124 26
        if ($this->owner && !$isAdmin && !$isOwner) {
125 1
            $currentLogin = $user ? $user->getName() : '[anonymous]';
126 1
            $currentOwnerLogin = $this->owner->getName();
0 ignored issues
show
Bug introduced by
The method getName() 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

126
            /** @scrutinizer ignore-call */ 
127
            $currentOwnerLogin = $this->owner->getName();

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...
127 1
            $futureOwnerLogin = $owner ? $owner->getName() : '[nobody]';
128
129 1
            throw new Exception($currentLogin . ' is not allowed to change owner to ' . $futureOwnerLogin . ' because it belongs to ' . $currentOwnerLogin);
130
        }
131
132 26
        $this->owner = $owner;
133
    }
134
135
    /**
136
     * Get owner.
137
     */
138 46
    public function getOwner(): ?User
139
    {
140 46
        return $this->owner;
141
    }
142
143
    /**
144
     * Set updater.
145
     */
146 46
    private function setUpdater(?User $updater): void
147
    {
148 46
        $this->updater = $updater;
149
    }
150
151
    /**
152
     * Get updater.
153
     */
154
    public function getUpdater(): ?User
155
    {
156
        return $this->updater;
157
    }
158
159
    /**
160
     * Get default owner for creation.
161
     */
162 29
    protected function getOwnerForCreation(): ?User
163
    {
164 29
        return User::getCurrent();
165
    }
166
167
    /**
168
     * Automatically called by Doctrine when the object is saved for the first time.
169
     */
170 37
    #[ORM\PrePersist]
171
    public function timestampCreation(): void
172
    {
173 37
        $now = new Chronos();
174 37
        $user = User::getCurrent();
175 37
        $this->setCreationDate($now);
176 37
        $this->setUpdateDate($now);
177 37
        $this->setCreator($user);
178 37
        $this->setUpdater($user);
179
180 37
        if (!$this->getOwner()) {
181 31
            $this->setOwner($this->getOwnerForCreation());
182
        }
183
    }
184
185
    /**
186
     * Automatically called by Doctrine when the object is updated.
187
     */
188 13
    #[ORM\PreUpdate]
189
    public function timestampUpdate(PreUpdateEventArgs $args): void
190
    {
191
        // Skip stamping if we only recorded a login of a user
192 13
        $changeSet = $args->getEntityChangeSet();
193 13
        unset($changeSet['firstLogin'], $changeSet['lastLogin']);
194 13
        if (!$changeSet) {
195 2
            return;
196
        }
197
198 12
        $this->setUpdateDate(new Chronos());
199 12
        $this->setUpdater(User::getCurrent());
200
    }
201
202
    /**
203
     * Get permissions on this object for the current user.
204
     */
205 2
    #[API\Field(type: PermissionsType::class)]
206
    public function getPermissions(): array
207
    {
208 2
        $acl = new Acl();
209
210 2
        return [
211 2
            'create' => $acl->isCurrentUserAllowed($this, 'create'),
212 2
            'read' => $acl->isCurrentUserAllowed($this, 'read'),
213 2
            'update' => $acl->isCurrentUserAllowed($this, 'update'),
214 2
            'delete' => $acl->isCurrentUserAllowed($this, 'delete'),
215 2
        ];
216
    }
217
}
218