AbstractModel::getCreationDate()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
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 209
    public function getId(): ?int
59
    {
60 209
        return $this->id;
61
    }
62
63
    /**
64
     * Set creation date.
65
     */
66 62
    private function setCreationDate(Chronos $creationDate): void
67
    {
68 62
        $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 76
    private function setUpdateDate(Chronos $updateDate): void
83
    {
84 76
        $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 62
    private function setCreator(?User $creator): void
99
    {
100 62
        $this->creator = $creator;
101
    }
102
103
    /**
104
     * Get creator.
105
     */
106 2
    public function getCreator(): ?User
107
    {
108 2
        return $this->creator;
109
    }
110
111
    /**
112
     * Set owner.
113
     */
114 81
    public function setOwner(?User $owner): void
115
    {
116 81
        if ($owner === $this->owner) {
117 30
            return;
118
        }
119
120 76
        $user = User::getCurrent();
121 76
        $isAdmin = $user && $user->getRole() === User::ROLE_ADMINISTRATOR;
122 76
        $isOwner = $user === $this->owner;
123
124 76
        if ($this->owner && !$isAdmin && !$isOwner) {
125 1
            $currentLogin = $user ? $user->getLogin() : '[anonymous]';
126 1
            $currentOwnerLogin = $this->owner->getLogin();
0 ignored issues
show
Bug introduced by
The method getLogin() 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->getLogin();

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