Passed
Push — master ( 3f23ea...c594c9 )
by Jan
05:15 queued 11s
created

AbstractLogEntry::getTargetID()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 7
rs 10
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
6
 *
7
 * Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
22
 */
23
24
namespace App\Entity\LogSystem;
25
26
use App\Entity\Attachments\Attachment;
27
use App\Entity\Base\DBElement;
28
use App\Entity\Devices\Device;
29
use App\Entity\Parts\Category;
30
use App\Entity\Parts\Footprint;
31
use App\Entity\Parts\Manufacturer;
32
use App\Entity\Parts\Part;
33
use App\Entity\Parts\Storelocation;
34
use App\Entity\Parts\Supplier;
35
use App\Entity\UserSystem\Group;
36
use App\Entity\UserSystem\User;
37
use DateTime;
38
use Doctrine\ORM\Mapping as ORM;
39
use App\Entity\Attachments\AttachmentType;
40
use App\Entity\Devices\DevicePart;
41
use Psr\Log\LogLevel;
42
43
/**
44
 * This entity describes a entry in the event log.
45
 * @package App\Entity\LogSystem
46
 * @ORM\Entity(repositoryClass="App\Repository\LogEntryRepository")
47
 * @ORM\Table("log")
48
 * @ORM\InheritanceType("SINGLE_TABLE")
49
 * @ORM\DiscriminatorColumn(name="type", type="smallint")
50
 * @ORM\DiscriminatorMap({
51
 *  1 = "UserLoginLogEntry",
52
 *  2 = "UserLogoutLogEntry",
53
 *  3 = "UserNotAllowedLogEntry",
54
 *  4 = "ExceptionLogEntry",
55
 *  5 = "ElementDeletedLogEntry",
56
 *  6 = "ElementCreatedLogEntry",
57
 *  7 = "ElementEditedLogEntry",
58
 *  8 = "ConfigChangedLogEntry",
59
 *  9 = "InstockChangedLogEntry",
60
 *  10 = "DatabaseUpdatedLogEntry"
61
 * })
62
 */
63
abstract class AbstractLogEntry extends DBElement
64
{
65
    public const LEVEL_EMERGENCY = 0;
66
    public const LEVEL_ALERT = 1;
67
    public const LEVEL_CRITICAL = 2;
68
    public const LEVEL_ERROR = 3;
69
    public const LEVEL_WARNING = 4;
70
    public const LEVEL_NOTICE = 5;
71
    public const LEVEL_INFO = 6;
72
    public const LEVEL_DEBUG = 7;
73
74
    protected const TARGET_TYPE_NONE = 0;
75
    protected const TARGET_TYPE_USER = 1;
76
    protected const TARGET_TYPE_ATTACHEMENT = 2;
77
    protected const TARGET_TYPE_ATTACHEMENTTYPE = 3;
78
    protected const TARGET_TYPE_CATEGORY = 4;
79
    protected const TARGET_TYPE_DEVICE = 5;
80
    protected const TARGET_TYPE_DEVICEPART = 6;
81
    protected const TARGET_TYPE_FOOTPRINT = 7;
82
    protected const TARGET_TYPE_GROUP = 8;
83
    protected const TARGET_TYPE_MANUFACTURER = 9;
84
    protected const TARGET_TYPE_PART = 10;
85
    protected const TARGET_TYPE_STORELOCATION = 11;
86
    protected const TARGET_TYPE_SUPPLIER = 12;
87
88
    /** @var array This const is used to convert the numeric level to a PSR-3 compatible log level */
89
    protected const LEVEL_ID_TO_STRING = [
90
        self::LEVEL_EMERGENCY => LogLevel::EMERGENCY,
91
        self::LEVEL_ALERT => LogLevel::ALERT,
92
        self::LEVEL_CRITICAL => LogLevel::CRITICAL,
93
        self::LEVEL_ERROR => LogLevel::ERROR,
94
        self::LEVEL_WARNING => LogLevel::WARNING,
95
        self::LEVEL_NOTICE => LogLevel::NOTICE,
96
        self::LEVEL_INFO => LogLevel::INFO,
97
        self::LEVEL_DEBUG => LogLevel::DEBUG,
98
    ];
99
100
101
    protected const TARGET_CLASS_MAPPING = [
102
        self::TARGET_TYPE_USER => User::class,
103
        self::TARGET_TYPE_ATTACHEMENT => Attachment::class,
104
        self::TARGET_TYPE_ATTACHEMENTTYPE => AttachmentType::class,
105
        self::TARGET_TYPE_CATEGORY => Category::class,
106
        self::TARGET_TYPE_DEVICE => Device::class,
107
        self::TARGET_TYPE_DEVICEPART => DevicePart::class,
108
        self::TARGET_TYPE_FOOTPRINT => Footprint::class,
109
        self::TARGET_TYPE_GROUP => Group::class,
110
        self::TARGET_TYPE_MANUFACTURER => Manufacturer::class,
111
        self::TARGET_TYPE_PART => Part::class,
112
        self::TARGET_TYPE_STORELOCATION => Storelocation::class,
113
        self::TARGET_TYPE_SUPPLIER => Supplier::class,
114
    ];
115
116
    /** @var User $user The user which has caused this log entry
117
     * @ORM\ManyToOne(targetEntity="App\Entity\UserSystem\User")
118
     * @ORM\JoinColumn(name="id_user", nullable=false)
119
     */
120
    protected $user;
121
122
    /** @var DateTime The datetime the event associated with this log entry has occured.
123
     * @ORM\Column(type="datetime", name="datetime")
124
     */
125
    protected $timestamp;
126
127
    /** @var integer The priority level of the associated level. 0 is highest, 7 lowest
128
     * @ORM\Column(type="integer", name="level", columnDefinition="TINYINT")
129
     */
130
    protected $level;
131
132
    /** @var int $target_id The ID of the element targeted by this event
133
     * @ORM\Column(name="target_id", type="integer", nullable=false)
134
     */
135
    protected $target_id = 0;
136
137
    /** @var int $target_type The Type of the targeted element
138
     * @ORM\Column(name="target_type", type="smallint", nullable=false)
139
     */
140
    protected $target_type = 0;
141
142
    /** @var string The type of this log entry, aka the description what has happened.
143
     * The mapping between the log entry class and the discriminator column is done by doctrine.
144
     * Each subclass should override this string to specify a better string.
145
     */
146
    protected $typeString = "unknown";
147
148
    /** @var array The extra data in raw (short form) saved in the DB
149
     * @ORM\Column(name="extra", type="json")
150
     */
151
    protected $extra = [];
152
153
    public function __construct()
154
    {
155
        $this->timestamp = new DateTime();
156
        $this->level = self::LEVEL_WARNING;
157
    }
158
159
    /**
160
     * Get the user that caused the event associated with this log entry.
161
     * @return User
162
     */
163
    public function getUser(): ?User
164
    {
165
        return $this->user;
166
    }
167
168
    /**
169
     * Sets the user that caused the event.
170
     * @param  User  $user
171
     * @return $this
172
     */
173
    public function setUser(User $user): self
174
    {
175
        $this->user = $user;
176
        return $this;
177
    }
178
179
    /**
180
     * Returns the timestamp when the event that caused this log entry happened
181
     * @return DateTime
182
     */
183
    public function getTimestamp(): DateTime
184
    {
185
        return $this->timestamp;
186
    }
187
188
    /**
189
     * Sets the timestamp when the event happened.
190
     * @param  DateTime  $timestamp
191
     * @return $this
192
     */
193
    public function setTimestamp(DateTime $timestamp): AbstractLogEntry
194
    {
195
        $this->timestamp = $timestamp;
196
        return $this;
197
    }
198
199
    /**
200
     * Get the priority level of this log entry. 0 is highest and 7 lowest level.
201
     * See LEVEL_* consts in this class for more info
202
     * @return int
203
     */
204
    public function getLevel(): int
205
    {
206
        //It is always alerting when a wrong int is saved in DB...
207
        if ($this->level < 0 || $this->level > 7) {
208
            return self::LEVEL_ALERT;
209
        }
210
        return $this->level;
211
    }
212
213
    /**
214
     * Sets the new level of this log entry.
215
     * @param  int  $level
216
     * @return $this
217
     */
218
    public function setLevel(int $level): AbstractLogEntry
219
    {
220
        if ($level < 0 || $this->level > 7) {
221
            throw new \InvalidArgumentException(sprintf('$level must be between 0 and 7! %d given!', $level));
222
        }
223
        $this->level = $level;
224
        return $this;
225
    }
226
227
    /**
228
     * Get the priority level of this log entry as PSR3 compatible string
229
     * @return string
230
     */
231
    public function getLevelString(): string
232
    {
233
        return self::levelIntToString($this->getLevel());
234
    }
235
236
    /**
237
     * Sets the priority level of this log entry as PSR3 compatible string
238
     * @param string $level
239
     * @return $this
240
     */
241
    public function setLevelString(string $level): AbstractLogEntry
242
    {
243
        $this->setLevel(self::levelStringToInt($level));
244
        return $this;
245
    }
246
247
    /**
248
     * Returns the type of the event this log entry is associated with.
249
     * @return string
250
     */
251
    public function getType(): string
252
    {
253
        return $this->typeString;
254
    }
255
256
    /**
257
     * @inheritDoc
258
     */
259
    public function getIDString(): string
260
    {
261
        return "LOG".$this->getID();
262
    }
263
264
    /**
265
     * Returns the class name of the target element associated with this log entry.
266
     * Returns null, if this log entry is not associated with an log entry.
267
     * @return string|null The class name of the target class.
268
     */
269
    public function getTargetClass(): ?string
270
    {
271
        if ($this->target_type === self::TARGET_TYPE_NONE) {
272
            return null;
273
        }
274
275
        return self::targetTypeIdToClass($this->target_type);
276
    }
277
278
    /**
279
     * Returns the ID of the target element associated with this log entry.
280
     * Returns null, if this log entry is not associated with an log entry.
281
     * @return int|null The ID of the associated element.
282
     */
283
    public function getTargetID(): ?int
284
    {
285
        if ($this->target_id === 0) {
286
            return null;
287
        }
288
289
        return $this->target_id;
290
    }
291
292
    /**
293
     * Checks if this log entry is associated with an element
294
     * @return bool True if this log entry is associated with an element, false otherwise.
295
     */
296
    public function hasTarget(): bool
297
    {
298
        return $this->getTargetID() !== null && $this->getTargetClass() !== null;
299
    }
300
301
    /**
302
     * Sets the target element associated with this element
303
     * @param  DBElement  $element The element that should be associated with this element.
304
     * @return $this
305
     */
306
    public function setTargetElement(?DBElement $element): self
307
    {
308
        if ($element === null) {
309
            $this->target_id = 0;
310
            $this->target_type = self::TARGET_TYPE_NONE;
311
            return $this;
312
        }
313
314
        $this->target_type = static::targetTypeClassToID(get_class($element));
315
        $this->target_id = $element->getID();
316
317
        return $this;
318
    }
319
320
    public function getExtraData(): array
321
    {
322
        return $this->extra;
323
    }
324
325
    /**
326
     * This function converts the internal numeric log level into an PSR3 compatible level string.
327
     * @param  int  $level The numerical log level
328
     * @return string The PSR3 compatible level string
329
     */
330
    final public static function levelIntToString(int $level): string
331
    {
332
        if (!isset(self::LEVEL_ID_TO_STRING[$level])) {
333
            throw new \InvalidArgumentException('No level with this int is existing!');
334
        }
335
336
        return self::LEVEL_ID_TO_STRING[$level];
337
    }
338
339
    /**
340
     * This function converts a PSR3 compatible string to the internal numeric level string.
341
     * @param string $level the PSR3 compatible string that should be converted
342
     * @return int The internal int representation.
343
     */
344
    final public static function levelStringToInt(string $level): int
345
    {
346
        $tmp = array_flip(self::LEVEL_ID_TO_STRING);
347
        if (!isset($tmp[$level])) {
348
            throw new \InvalidArgumentException('No level with this string is existing!');
349
        }
350
351
        return $tmp[$level];
352
    }
353
354
    /**
355
     * Converts an target type id to an full qualified class name.
356
     * @param  int  $type_id The target type ID
357
     * @return string
358
     */
359
    final public static function targetTypeIdToClass(int $type_id): string
360
    {
361
        if (!isset(self::TARGET_CLASS_MAPPING[$type_id])) {
362
            throw new \InvalidArgumentException('No target type with this ID is existing!');
363
        }
364
365
        return self::TARGET_CLASS_MAPPING[$type_id];
366
    }
367
368
    /**
369
     * Convert a class name to a target type ID.
370
     * @param  string  $class The name of the class (FQN) that should be converted to id
371
     * @return int The ID of the associated target type ID.
372
     */
373
    final public static function targetTypeClassToID(string $class): int
374
    {
375
        $tmp = array_flip(self::TARGET_CLASS_MAPPING);
376
        //Check if we can use a key directly
377
        if (isset($tmp[$class])) {
378
            return $tmp[$class];
379
        }
380
381
        //Otherwise we have to iterate over everything and check for inheritance
382
        foreach ($tmp as $compare_class => $class_id) {
0 ignored issues
show
Bug introduced by
The expression $tmp of type null is not traversable.
Loading history...
383
            if (is_a($class, $compare_class, true)) {
384
                return $class_id;
385
            }
386
        }
387
388
        throw new \InvalidArgumentException('No target ID for this class is existing!');
389
    }
390
391
392
}