Completed
Pull Request — master (#61)
by
unknown
01:43
created

GeneratesUuid::bytesFromUuid()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 4.125

Importance

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

65
            $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

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