Issues (8)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Versionable.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * CalamandreiLorenzo\LaravelVersionable
4
 *
5
 * This file is part of the overtrue/laravel-versionable.
6
 * ------------------------------------------------------
7
 * (c) overtrue <[email protected]>
8
 * This source file is subject to the MIT license that is bundled.
9
 */
10
11
namespace CalamandreiLorenzo\LaravelVersionable;
12
13
use CalamandreiLorenzo\LaravelVersionable\Exceptions\MissingVersionableProperty;
14
use Exception;
15
use Illuminate\Database\Eloquent\Model;
16
use Illuminate\Database\Eloquent\Relations\MorphMany;
17
use Illuminate\Database\Eloquent\Relations\MorphOne;
18
use Illuminate\Support\Collection;
19
use function array_diff_key;
20
use function array_intersect_key;
21
use function array_keys;
22
use function config;
23
use function property_exists;
24
use function optional;
25
26
/**
27
 * Trait Versionable
28
 * @package CalamandreiLorenzo\LaravelVersionable
29
 * @author 安正超 - overtrue
30
 * @github https://github.com/overtrue
31
 * @property-read Collection|Version[] versions
32
 * @property-read Version lastVersion
33
 */
34
trait Versionable
35
{
36
    /**
37
     * @var bool $versioning
38
     */
39
    protected static bool $versioning = true;
0 ignored issues
show
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_STRING, expecting T_FUNCTION or T_CONST
Loading history...
40
41
    /**
42
     * @var bool $forceDeleteVersion
43
     */
44
    protected bool $forceDeleteVersion = false;
45
46
    // You can add these properties to you versionable model
47
    //protected $versionable = [];
48
    //protected $dontVersionable = ['*'];
49
50
    /**
51
     * bootVersionable
52
     * @noinspection PhpUnused
53
     * @noinspection UnknownInspectionInspection
54
     */
55 8
    public static function bootVersionable(): void
56
    {
57
        static::saved(static function (Model $model) {
58 8
            self::createVersionForModel($model);
59 8
        });
60
61
        static::deleted(static function (Model $model) {
62
            if (property_exists($model, 'forceDeleting') && $model->forceDeleting) {
63
                /**
64
                 * @var Versionable|Model $model
65
                 */
66
                $model->forceRemoveAllVersions();
67
            } else {
68
                self::createVersionForModel($model);
69
            }
70 8
        });
71 8
    }
72
73
    /**
74
     * createVersionForModel
75
     * @param Versionable|Model $model
76
     * @throws Exceptions\NotVersionableModel
77
     */
78 8
    private static function createVersionForModel(Model $model): void
79
    {
80 8
        if (self::$versioning && $model->shouldVersioning()) {
81 8
            Version::createForModel($model);
82 8
            $model->removeOldVersions($model->getKeepVersionsCount());
83
        }
84 8
    }
85
86
    /**
87
     * versions
88
     * @return MorphMany
89
     */
90 8
    public function versions(): MorphMany
91
    {
92 8
        return $this->morphMany(
93 8
            config('versionable.version_model'),
94 8
            'versionable'
95 8
        )->latest('version_number');
96
    }
97
98
99
    /**
100
     * lastVersion
101
     * @return MorphOne
102
     */
103 6
    public function lastVersion(): MorphOne
104
    {
105 6
        return $this->morphOne(
106 6
            config('versionable.version_model'),
107 6
            'versionable'
108 6
        )->latest('version_number');
109
    }
110
111
    /**
112
     * getVersion
113
     * @param $id
114
     * @return Model|null
115
     */
116
    public function getVersion($id): ?Model
117
    {
118
        return $this->versions()->find($id);
119
    }
120
121
    /**
122
     * getVersion
123
     * @param int $id
124
     * @return Model|null
125
     */
126 1
    public function getVersionByVersionNumber(int $id): ?Model
127
    {
128 1
        return $this->versions()->where('version_number', $id)->first();
129
    }
130
131
    /**
132
     * getThrashedVersions
133
     * @return mixed
134
     */
135 1
    public function getThrashedVersions()
136
    {
137
        /** @noinspection PhpUndefinedMethodInspection */
138 1
        return $this->versions()->onlyTrashed()->get();
139
    }
140
141
    /**
142
     * restoreThrashedVersion
143
     * @param $id
144
     * @return mixed
145
     */
146 1
    public function restoreThrashedVersion($id)
147
    {
148
        /** @noinspection PhpUndefinedMethodInspection */
149 1
        return $this->versions()->onlyTrashed()->whereId($id)->restore();
150
    }
151
152
    /**
153
     * revertToVersion
154
     * @param $id
155
     * @return mixed
156
     */
157
    public function revertToVersion($id)
158
    {
159
        return optional($this->versions()->findOrFail($id))->revert();
160
    }
161
162
    /**
163
     * revertToVersionNumber
164
     * @param int $id
165
     * @return mixed
166
     */
167 1
    public function revertToVersionNumber(int $id)
168
    {
169 1
        return optional(
170 1
            $this->versions()->where('version_number', $id)->firstOrFail()
171 1
        )->revert();
172
    }
173
174
    /**
175
     * removeOldVersions
176
     * @param int $keep
177
     */
178 8
    public function removeOldVersions(int $keep): void
179
    {
180 8
        if ($keep <= 0) {
181 7
            return;
182
        }
183
184
        /** @noinspection PhpUndefinedMethodInspection */
185 1
        $this->versions()->skip($keep)->take(PHP_INT_MAX)->get()->each->delete();
186 1
    }
187
188
    /**
189
     * removeVersions
190
     * @param array $ids
191
     * @return mixed
192
     */
193
    public function removeVersions(array $ids)
194
    {
195
        if ($this->forceDeleteVersion) {
196
            return $this->forceRemoveVersions($ids);
197
        }
198
199
        return $this->versions()->find($ids)->each->delete();
200
    }
201
202
    /**
203
     * removeVersion
204
     * @param $id
205
     * @return bool|mixed|null
206
     * @throws Exception
207
     */
208 2
    public function removeVersion($id)
209
    {
210 2
        if ($this->forceDeleteVersion) {
211 1
            return $this->forceRemoveVersion($id);
212
        }
213
214 1
        return optional($this->versions()->findOrFail($id))->delete();
215
    }
216
217
    /**
218
     * removeAllVersions
219
     */
220 1
    public function removeAllVersions(): void
221
    {
222 1
        if ($this->forceDeleteVersion) {
223
            $this->forceRemoveAllVersions();
224
        }
225
226
        /** @noinspection PhpUndefinedMethodInspection */
227 1
        $this->versions->each->delete();
228 1
    }
229
230
    /**
231
     * forceRemoveVersion
232
     * @param $id
233
     * @return mixed
234
     */
235 1
    public function forceRemoveVersion($id)
236
    {
237 1
        return optional($this->versions()->findOrFail($id))->forceDelete();
238
    }
239
240
    /**
241
     * forceRemoveVersions
242
     * @param array $ids
243
     * @return mixed
244
     */
245
    public function forceRemoveVersions(array $ids)
246
    {
247
        return $this->versions()->find($ids)->each->forceDelete();
248
    }
249
250
    /**
251
     * forceRemoveAllVersions
252
     */
253
    public function forceRemoveAllVersions(): void
254
    {
255
        /** @noinspection PhpUndefinedMethodInspection */
256
        $this->versions->each->forceDelete();
257
    }
258
259
    /**
260
     * shouldVersioning
261
     * @return bool
262
     */
263 8
    public function shouldVersioning(): bool
264
    {
265 8
        return !empty($this->getVersionableAttributes());
266
    }
267
268
    /**
269
     * getVersionableAttributes
270
     * @return array
271
     */
272 8
    public function getVersionableAttributes(): array
273
    {
274 8
        $changes = $this->getDirty();
275
276 8
        if (empty($changes)) {
277
            return [];
278
        }
279
280 8
        $contents = $this->attributesToArray();
281
282 8
        if ($this->getVersionStrategy() === VersionStrategy::DIFF) {
283 8
            $contents = $this->only(array_keys($changes));
284
        }
285
286 8
        return $this->versionableFromArray($contents);
287
    }
288
289
    /**
290
     * setVersionable
291
     * @param array $attributes
292
     * @return $this
293
     * @throws Exception
294
     */
295
    public function setVersionable(array $attributes): self
296
    {
297
        if (!property_exists($this, 'versionable')) {
298
            throw new MissingVersionableProperty('Property $versionable not exist.');
299
        }
300
        $this->versionable = $attributes;
301
        return $this;
302
    }
303
304
    /**
305
     * setDontVersionable
306
     * @param array $attributes
307
     * @return $this
308
     * @throws Exception
309
     */
310
    public function setDontVersionable(array $attributes): self
311
    {
312
        if (!property_exists($this, 'dontVersionable')) {
313
            throw new MissingVersionableProperty('Property $dontVersionable not exist.');
314
        }
315
        $this->dontVersionable = $attributes;
316
        return $this;
317
    }
318
319
    /**
320
     * getVersionable
321
     * @return array
322
     */
323 8
    public function getVersionable(): array
324
    {
325 8
        return property_exists($this, 'versionable') ? $this->versionable : [];
326
    }
327
328
    /**
329
     * getDontVersionable
330
     * @return array
331
     */
332
    public function getDontVersionable(): array
333
    {
334
        return property_exists($this, 'dontVersionable') ? $this->dontVersionable : [];
335
    }
336
337
    /**
338
     * getVersionStrategy
339
     * @return string
340
     */
341 8
    public function getVersionStrategy(): string
342
    {
343 8
        return property_exists($this, 'versionStrategy') ? $this->versionStrategy : VersionStrategy::DIFF;
344
    }
345
346
    /**
347
     * setVersionStrategy
348
     * @param string $strategy
349
     * @return $this
350
     * @throws Exception
351
     */
352 1
    public function setVersionStrategy(string $strategy): self
353
    {
354 1
        if (!property_exists($this, 'versionStrategy')) {
355
            throw new MissingVersionableProperty('Property $versionStrategy not exist.');
356
        }
357 1
        $this->versionStrategy = $strategy;
358 1
        return $this;
359
    }
360
361
    /**
362
     * getVersionModel
363
     * @return mixed
364
     */
365 8
    public function getVersionModel(): string
366
    {
367 8
        return config('versionable.version_model');
368
    }
369
370
    /**
371
     * getKeepVersionsCount
372
     * @return string
373
     */
374 8
    public function getKeepVersionsCount(): string
375
    {
376 8
        return config('versionable.keep_versions', 0);
377
    }
378
379
    /**
380
     * versionableFromArray
381
     * Get the versionable attributes of a given array.
382
     * @param array $attributes
383
     * @return array
384
     */
385 8
    public function versionableFromArray(array $attributes): array
386
    {
387 8
        if (count($this->getVersionable()) > 0) {
388 8
            return array_intersect_key($attributes, array_flip($this->getVersionable()));
389
        }
390
391
        if (count($this->getDontVersionable()) > 0) {
392
            return array_diff_key($attributes, array_flip($this->getDontVersionable()));
393
        }
394
395
        return $attributes;
396
    }
397
398
    /**
399
     * withoutVersion
400
     * @param callable $callback
401
     */
402 1
    public static function withoutVersion(callable $callback): void
403
    {
404 1
        self::$versioning = false;
405 1
        $callback();
406 1
        self::$versioning = true;
407 1
    }
408
409
    /**
410
     * enableForceDeleteVersion
411
     */
412 1
    public function enableForceDeleteVersion(): void
413
    {
414 1
        $this->forceDeleteVersion = true;
415 1
    }
416
417
    /**
418
     * disableForceDeleteVersion
419
     */
420
    public function disableForceDeleteVersion(): void
421
    {
422
        $this->forceDeleteVersion = false;
423
    }
424
}
425