Passed
Push — master ( 2d3a79...fa9158 )
by Carlos
01:06 queued 12s
created

Versionable   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 192
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 1

Test Coverage

Coverage 68.33%

Importance

Changes 0
Metric Value
wmc 27
lcom 3
cbo 1
dl 0
loc 192
ccs 41
cts 60
cp 0.6833
rs 10
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A setVersionable() 0 10 2
A setDontVersionable() 0 10 2
A getDontVersionable() 0 4 2
A bootVersionable() 0 14 2
A createVersionForModel() 0 7 2
A versions() 0 4 1
A lastVersion() 0 4 1
A getVersion() 0 4 1
A revertToVersion() 0 4 1
A removeOldVersions() 0 8 2
A removeAllVersions() 0 4 1
A shouldVersioning() 0 4 1
A getVersionableAttributes() 0 10 2
A getVersionable() 0 4 2
A getVersionModel() 0 4 1
A getKeepVersionsCount() 0 4 1
A versionableFromArray() 0 12 3
1
<?php
2
3
/*
4
 * This file is part of the overtrue/laravel-versionable.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled.
9
 */
10
11
namespace Overtrue\LaravelVersionable;
12
13
use Illuminate\Database\Eloquent\Model;
14
use Illuminate\Database\Eloquent\Relations\MorphMany;
15
use Illuminate\Database\Eloquent\Relations\MorphOne;
16
17
trait Versionable
18
{
19
    // You can add these properties to you versionable model
20
    //protected $versionable = [];
21
    //protected $dontVersionable = ['*'];
22
23 4
    public static function bootVersionable()
24
    {
25
        static::saved(function (Model $model) {
26 4
            self::createVersionForModel($model);
27 4
        });
28
29
        static::deleted(function (Model $model) {
30
            if ($model->forceDeleting) {
31
                $model->removeAllVersions();
32
            } else {
33
                self::createVersionForModel($model);
34
            }
35 4
        });
36 4
    }
37
38 4
    private static function createVersionForModel(Model $model): void
39
    {
40 4
        if ($model->shouldVersioning()) {
41 4
            Version::createForModel($model);
42 4
            $model->removeOldVersions($model->getKeepVersionsCount());
43
        }
44 4
    }
45
46
    /**
47
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
48
     */
49 4
    public function versions(): MorphMany
50
    {
51 4
        return $this->morphMany(\config('versionable.version_model'), 'versionable')->latest('id');
0 ignored issues
show
Bug introduced by
It seems like morphMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
52
    }
53
54
    /**
55
     * @return \Illuminate\Database\Eloquent\Relations\MorphOne
56
     */
57 2
    public function lastVersion(): MorphOne
58
    {
59 2
        return $this->morphOne(\config('versionable.version_model'), 'versionable')->latest('id');
0 ignored issues
show
Bug introduced by
It seems like morphOne() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
60
    }
61
62
    /**
63
     * @param int $id
64
     *
65
     * @return \Illuminate\Database\Eloquent\Model|null
66
     */
67 1
    public function getVersion($id)
68
    {
69 1
        return $this->versions()->find($id);
70
    }
71
72
    /**
73
     * @param int $id
74
     *
75
     * @return mixed
76
     */
77 1
    public function revertToVersion($id)
78
    {
79 1
        return $this->versions()->findOrFail($id)->revert();
80
    }
81
82
    /**
83
     * @param int $keep
84
     */
85 4
    public function removeOldVersions(int $keep): void
86
    {
87 4
        if ($keep <= 0) {
88 3
            return;
89
        }
90
91 1
        $this->versions()->skip($keep)->take($keep)->get()->each->delete();
92 1
    }
93
94 1
    public function removeAllVersions()
95
    {
96 1
        $this->versions->each->delete();
0 ignored issues
show
Bug introduced by
The property versions does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
97 1
    }
98
99
    /**
100
     * @return bool
101
     */
102 4
    public function shouldVersioning(): bool
103
    {
104 4
        return !empty($this->getVersionableAttributes());
105
    }
106
107
    /**
108
     * @return array
109
     */
110 4
    public function getVersionableAttributes(): array
111
    {
112 4
        $changes = $this->getDirty();
0 ignored issues
show
Bug introduced by
It seems like getDirty() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
113
114 4
        if (empty($changes)) {
115
            return [];
116
        }
117
118 4
        return $this->versionableFromArray($changes);
119
    }
120
121
    /**
122
     * @param array $attributes
123
     *
124
     * @return $this
125
     *
126
     * @throws \Exception
127
     */
128
    public function setVersionable(array $attributes)
129
    {
130
        if (!\property_exists($this, 'versionable')) {
131
            throw new \Exception('Property $versionable not exist.');
132
        }
133
134
        $this->versionable = $attributes;
0 ignored issues
show
Bug introduced by
The property versionable does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
135
136
        return $this;
137
    }
138
139
    /**
140
     * @param array $attributes
141
     *
142
     * @return $this
143
     *
144
     * @throws \Exception
145
     */
146
    public function setDontVersionable(array $attributes)
147
    {
148
        if (!\property_exists($this, 'dontVersionable')) {
149
            throw new \Exception('Property $dontVersionable not exist.');
150
        }
151
152
        $this->dontVersionable = $attributes;
0 ignored issues
show
Bug introduced by
The property dontVersionable does not seem to exist. Did you mean versionable?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
153
154
        return $this;
155
    }
156
157
    /**
158
     * @return array
159
     */
160 4
    public function getVersionable(): array
161
    {
162 4
        return \property_exists($this, 'versionable') ? $this->versionable : [];
163
    }
164
165
    /**
166
     * @return array
167
     */
168
    public function getDontVersionable(): array
169
    {
170
        return \property_exists($this, 'dontVersionable') ? $this->dontVersionable : [];
0 ignored issues
show
Bug introduced by
The property dontVersionable does not seem to exist. Did you mean versionable?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
171
    }
172
173
    /**
174
     * @return string
175
     */
176 4
    public function getVersionModel(): string
177
    {
178 4
        return config('versionable.version_model');
179
    }
180
181
    /**
182
     * @return string
183
     */
184 4
    public function getKeepVersionsCount(): string
185
    {
186 4
        return config('versionable.keep_versions', 0);
187
    }
188
189
    /**
190
     * Get the versionable attributes of a given array.
191
     *
192
     * @param array $attributes
193
     *
194
     * @return array
195
     */
196 4
    public function versionableFromArray(array $attributes): array
197
    {
198 4
        if (count($this->getVersionable()) > 0) {
199 4
            return \array_intersect_key($attributes, array_flip($this->getVersionable()));
200
        }
201
202
        if (count($this->getDontVersionable()) > 0) {
203
            return \array_diff_key($attributes, array_flip($this->getDontVersionable()));
204
        }
205
206
        return $attributes;
207
    }
208
}
209