Completed
Push — master ( fcb692...e69fbf )
by Freek
37:28 queued 36:25
created

HasSlug   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 4
dl 0
loc 148
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Spatie\Sluggable;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Spatie\Sluggable\SlugOptions;
7
use Illuminate\Support\Str;
8
9
trait HasSlug
10
{
11
    protected SlugOptions $slugOptions;
0 ignored issues
show
Bug introduced by
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...
12
13
    abstract public function getSlugOptions(): SlugOptions;
14
15
    protected static function bootHasSlug()
16
    {
17
        static::creating(function (Model $model) {
18
            $model->generateSlugOnCreate();
19
        });
20
21
        static::updating(function (Model $model) {
22
            $model->generateSlugOnUpdate();
23
        });
24
    }
25
26
    protected function generateSlugOnCreate()
27
    {
28
        $this->slugOptions = $this->getSlugOptions();
29
30
        if (! $this->slugOptions->generateSlugsOnCreate) {
31
            return;
32
        }
33
34
        $this->addSlug();
35
    }
36
37
    protected function generateSlugOnUpdate()
38
    {
39
        $this->slugOptions = $this->getSlugOptions();
40
41
        if (! $this->slugOptions->generateSlugsOnUpdate) {
42
            return;
43
        }
44
45
        $this->addSlug();
46
    }
47
48
    public function generateSlug()
49
    {
50
        $this->slugOptions = $this->getSlugOptions();
51
52
        $this->addSlug();
53
    }
54
55
    protected function addSlug()
56
    {
57
        $this->ensureValidSlugOptions();
58
59
        $slug = $this->generateNonUniqueSlug();
60
61
        if ($this->slugOptions->generateUniqueSlugs) {
62
            $slug = $this->makeSlugUnique($slug);
63
        }
64
65
        $slugField = $this->slugOptions->slugField;
66
67
        $this->$slugField = $slug;
68
    }
69
70
    protected function generateNonUniqueSlug(): string
71
    {
72
        $slugField = $this->slugOptions->slugField;
73
74
        if ($this->hasCustomSlugBeenUsed() && ! empty($this->$slugField)) {
75
            return $this->$slugField;
76
        }
77
78
        return Str::slug($this->getSlugSourceString(), $this->slugOptions->slugSeparator, $this->slugOptions->slugLanguage);
79
    }
80
81
    protected function hasCustomSlugBeenUsed(): bool
82
    {
83
        $slugField = $this->slugOptions->slugField;
84
85
        return $this->getOriginal($slugField) != $this->$slugField;
86
    }
87
88
    protected function getSlugSourceString(): string
89
    {
90
        if (is_callable($this->slugOptions->generateSlugFrom)) {
91
            $slugSourceString = call_user_func($this->slugOptions->generateSlugFrom, $this);
92
93
            return substr($slugSourceString, 0, $this->slugOptions->maximumLength);
94
        }
95
96
        $slugSourceString = collect($this->slugOptions->generateSlugFrom)
97
            ->map(fn(string $fieldName): string => data_get($this, $fieldName, ''))
98
            ->implode($this->slugOptions->slugSeparator);
99
100
        return substr($slugSourceString, 0, $this->slugOptions->maximumLength);
101
    }
102
103
    protected function makeSlugUnique(string $slug): string
104
    {
105
        $originalSlug = $slug;
106
        $i = 1;
107
108
        while ($this->otherRecordExistsWithSlug($slug) || $slug === '') {
109
            $slug = $originalSlug.$this->slugOptions->slugSeparator.$i++;
110
        }
111
112
        return $slug;
113
    }
114
115
    protected function otherRecordExistsWithSlug(string $slug): bool
116
    {
117
        $key = $this->getKey();
118
119
        if ($this->incrementing) {
120
            $key ??= '0';
121
        }
122
123
        $query = static::where($this->slugOptions->slugField, $slug)
124
            ->where($this->getKeyName(), '!=', $key)
125
            ->withoutGlobalScopes();
126
127
        if ($this->usesSoftDeletes()) {
128
            $query->withTrashed();
129
        }
130
131
        return $query->exists();
132
    }
133
134
    protected function usesSoftDeletes(): bool
135
    {
136
        return (bool) in_array('Illuminate\Database\Eloquent\SoftDeletes', class_uses($this));
137
    }
138
139
    protected function ensureValidSlugOptions()
140
    {
141
        if (is_array($this->slugOptions->generateSlugFrom) && ! count($this->slugOptions->generateSlugFrom)) {
142
            throw InvalidOption::missingFromField();
143
        }
144
145
        if (! strlen($this->slugOptions->slugField)) {
146
            throw InvalidOption::missingSlugField();
147
        }
148
149
        if ($this->slugOptions->maximumLength <= 0) {
150
            throw InvalidOption::invalidMaximumLength();
151
        }
152
    }
153
}
154