Passed
Pull Request — master (#51)
by Michael
01:38
created

GeneratesUuid::scopeWhereUuid()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Dyrynda\Database\Support;
4
5
use Illuminate\Support\Str;
6
use Ramsey\Uuid\Uuid;
7
8
/**
9
 * UUID generation trait.
10
 *
11
 * Include this trait in any Eloquent model where you wish to automatically set
12
 * a UUID field. When saving, if the UUID field has not been set, generate a
13
 * new UUID value, which will be set on the model and saved by Eloquent.
14
 *
15
 * @copyright 2017 Michael Dyrynda
16
 * @author    Michael Dyrynda <[email protected]>
17
 * @license   MIT
18
 *
19
 * @property  string  $uuidVersion
20
 */
21
trait GeneratesUuid
22
{
23
    /**
24
     * The UUID versions.
25
     *
26
     * @var array
27
     */
28
    protected $uuidVersions = [
29
        'uuid1',
30
        'uuid3',
31
        'uuid4',
32
        'uuid5',
33
        'ordered',
34
    ];
35
36
    /**
37
     * Determine whether an attribute should be cast to a native type.
38
     *
39
     * @param  string  $key
40
     * @param  array|string|null  $types
41
     * @return bool
42
     */
43
    abstract public function hasCast($key, $types = null);
44
45
    /**
46
     * Boot the trait, adding a creating observer.
47
     *
48
     * When persisting a new model instance, we resolve the UUID field, then set
49
     * a fresh UUID, taking into account if we need to cast to binary or not.
50
     *
51
     * @return void
52
     */
53 10
    public static function bootGeneratesUuid()
54
    {
55
        static::creating(function ($model) {
56
            /* @var \Illuminate\Database\Eloquent\Model|static $model */
57 10
            $uuid = $model->resolveUuid();
58
59 10
            if (isset($model->attributes[$model->uuidColumn()]) && ! is_null($model->attributes[$model->uuidColumn()])) {
60
                /* @var \Ramsey\Uuid\Uuid $uuid */
61 4
                $uuid = $uuid->fromString(strtolower($model->attributes[$model->uuidColumn()]));
62
            }
63
64 10
            $model->attributes[$model->uuidColumn()] = $model->hasCast($model->uuidColumn(), 'uuid') ? $uuid->getBytes() : $uuid->toString();
0 ignored issues
show
Bug Best Practice introduced by
The property attributes does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
Bug introduced by
It seems like $model->uuidColumn() can also be of type Illuminate\Database\Eloquent\Builder; however, parameter $key of Illuminate\Database\Eloquent\Model::hasCast() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

64
            $model->attributes[$model->uuidColumn()] = $model->hasCast(/** @scrutinizer ignore-type */ $model->uuidColumn(), 'uuid') ? $uuid->getBytes() : $uuid->toString();
Loading history...
Bug introduced by
It seems like $model->uuidColumn() can also be of type Illuminate\Database\Eloquent\Builder; however, parameter $key of Dyrynda\Database\Support\GeneratesUuid::hasCast() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

64
            $model->attributes[$model->uuidColumn()] = $model->hasCast(/** @scrutinizer ignore-type */ $model->uuidColumn(), 'uuid') ? $uuid->getBytes() : $uuid->toString();
Loading history...
65 10
        });
66 6
    }
67
68
    /**
69
     * The name of the column that should be used for the UUID.
70
     *
71
     * @return string
72
     */
73 8
    public function uuidColumn()
74
    {
75 8
        return 'uuid';
76
    }
77
78
    /**
79
     * Resolve a UUID instance for the configured version.
80
     *
81
     * @return \Ramsey\Uuid\Uuid
82
     */
83 10
    public function resolveUuid()
84
    {
85 10
        if (($version = $this->resolveUuidVersion()) == 'ordered') {
86 2
            return Str::orderedUuid();
87
        }
88
89 8
        return call_user_func([Uuid::class, $version]);
90
    }
91
92
    /**
93
     * Resolve the UUID version to use when setting the UUID value. Default to uuid4.
94
     *
95
     * @return string
96
     */
97 16
    public function resolveUuidVersion()
98
    {
99 16
        if (property_exists($this, 'uuidVersion') && in_array($this->uuidVersion, $this->uuidVersions)) {
100 7
            return $this->uuidVersion;
101
        }
102
103 9
        return 'uuid4';
104
    }
105
106
    /**
107
     * Scope queries to find by UUID.
108
     *
109
     * @param  \Illuminate\Database\Eloquent\Builder  $query
110
     * @param  string  $uuid
111
     *
112
     * @return \Illuminate\Database\Eloquent\Builder
113
     */
114 2
    public function scopeWhereUuid($query, $uuid)
115
    {
116 2
        if ($this->hasCast($this->uuidColumn())) {
117 1
            $uuid = $this->resolveUuid()->fromString($uuid)->getBytes();
118
        }
119
120 2
        return $query->where($this->uuidColumn(), $uuid);
121
    }
122
123
    /**
124
     * Cast an attribute to a native PHP type.
125
     *
126
     * @param  string  $key
127
     * @param  mixed  $value
128
     * @return mixed
129
     */
130 5
    protected function castAttribute($key, $value)
131
    {
132 5
        if (is_null($value)) {
133
            return parent::castAttribute($key, $value);
134
        }
135
136 5
        if ($key === $this->uuidColumn()) {
137 5
            return $this->resolveUuid()->fromBytes($value)->toString();
138
        }
139
        
140 1
        if ($this->hasCast($key, 'uuid') && $this->resolveUuidVersion() == 'ordered') {
141 1
            return Uuid::fromBytes($value)->toString();
142
        }
143
    }
144
145
    /**
146
     * Set an attribute value
147
     *
148
     * @param $key
149
     * @param $value
150
     *
151
     * @return mixed
152
     */
153 10
    public function setAttribute($key, $value)
154
    {
155 10
        if (trim($value) !== ''
156 10
            && $this->hasCast($key, 'uuid')
157 10
            && $this->resolveUuidVersion() == 'ordered'
158
        ) {
159 1
            $value = Uuid::fromString($value)->getBytes();
160
        }
161
        
162 10
        return parent::setAttribute($key, $value);
163
    }
164
}
165