Completed
Push — master ( f05ffa...605762 )
by Vasyl
117:24 queued 115:51
created

SlugMakerTrait::getSlug()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Fomvasss\SlugMaker;
4
5
use Illuminate\Database\Eloquent\Model;
0 ignored issues
show
Bug introduced by
The type Illuminate\Database\Eloquent\Model was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
7
trait SlugMakerTrait
8
{
9
10
    protected $slugOptions;
11
12
    private $slugField = 'name';
13
14
    private $relatedName = 'slugable';
15
16
    private $slugModel = \Fomvasss\SlugMaker\Models\Slug::class;
17
18
19
    /**
20
     * Get the options for generating the slug.
21
     */
22
    abstract public function getSlugMakerOptions(): SlugMakerOptions;
23
24
    /**
25
     * The morph relations (has one) for the model.
26
     *
27
     * @return mixed
28
     */
29
    public function slug()
30
    {
31
        $this->setConfig();
32
        
33
        return $this->morphOne($this->slugModel, $this->relatedName);
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? ( Ignorable by Annotation )

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

33
        return $this->/** @scrutinizer ignore-call */ morphOne($this->slugModel, $this->relatedName);
Loading history...
34
    }
35
36
    /**
37
     * The scope for fet slug name
38
     */
39
    public function scopeGetSlugName()
40
    {
41
        $this->setConfig();
42
43
        if ($this->slug) {
0 ignored issues
show
Bug Best Practice introduced by
The property slug does not exist on Fomvasss\SlugMaker\SlugMakerTrait. Did you maybe forget to declare it?
Loading history...
44
            return $this->slug->{$this->slugField};            
45
        }
46
        return '';
47
    }
48
49
    /**
50
     * The boot trait events in class (model).
51
     */
52
    protected static function bootSlugMakerTrait()
53
    {
54
55
        static::created(function (Model $model) {
56
            $model->generateSlugOnCreate();
57
        });
58
59
        static::updated(function (Model $model) {
60
            $model->generateSlugOnUpdate();
61
        });
62
63
        static::deleted(function (Model $model) {
64
            $model->removeSlugsOnDeleted();
65
        });
66
    }
67
68
    protected function setConfig()
69
    {
70
        $config = config('slugmaker');
0 ignored issues
show
Bug introduced by
The function config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

70
        $config = /** @scrutinizer ignore-call */ config('slugmaker');
Loading history...
71
72
        foreach ($config as $name => $value) {
73
            $name = camel_case($name);
74
            $this->$name = $value;
75
        }
76
    }
77
78
    /**
79
     * Handle adding slug on model creation.
80
     */
81 View Code Duplication
    protected function generateSlugOnCreate()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
82
    {
83
        $this->slugOptions = $this->getSlugMakerOptions();
84
85
        if (! $this->slugOptions->generateSlugsOnCreate) {
86
            return;
87
        }
88
89
        $slug = $this->getSlug();
90
        $this->storeSlug($slug);
91
    }
92
93
    /**
94
     * Handle adding slug on model update.
95
     */
96 View Code Duplication
    protected function generateSlugOnUpdate()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
97
    {
98
        $this->slugOptions = $this->getSlugMakerOptions();
99
100
        if (! $this->slugOptions->generateSlugsOnUpdate) {
101
            return;
102
        }
103
104
        $slug = $this->getSlug();
105
        $this->storeSlug($slug);
106
    }
107
108
    /**
109
     * The store (create or update) slug in database.
110
     *
111
     * @param $slug
112
     */
113
    protected function storeSlug($slug)
114
    {
115
        $this->setConfig();
116
117
        if ($this->slug) {
0 ignored issues
show
Bug Best Practice introduced by
The property slug does not exist on Fomvasss\SlugMaker\SlugMakerTrait. Did you maybe forget to declare it?
Loading history...
118
            //$this->slug()->updateOrCreate(['name' => $this->slug->name], [$this->slugField => $slug]);
119
            $this->slug()->update([$this->slugField => $slug]);
120
        } else {
121
            $this->slug()->create([$this->slugField => $slug]);
122
        }
123
    }
124
125
    /**
126
     * Remove the slug in database. Default migration not using softdelete.
127
     */
128
    protected function removeSlugsOnDeleted()
129
    {
130
        $this->slugOptions = $this->getSlugMakerOptions();
131
132
        if ($this->slug && $this->slugOptions->removeSlugsOnDelete) {
0 ignored issues
show
Bug Best Practice introduced by
The property slug does not exist on Fomvasss\SlugMaker\SlugMakerTrait. Did you maybe forget to declare it?
Loading history...
133
            $this->slug()->delete();
134
        }
135
    }
136
137
    /**
138
     * Get the slug with the model.
139
     */
140
    protected function getSlug()
141
    {
142
        //$this->guardAgainstInvalidSlugOptions();
143
144
        $slug = $this->generateNonUniqueSlug();
145
146
        if ($this->slugOptions->generateUniqueSlugs) {
147
            $slug = $this->makeSlugUnique($slug);
148
        }
149
        return $slug;
150
    }
151
152
    /**
153
     * Generate a non unique slug for this record.
154
     */
155
    protected function generateNonUniqueSlug(): string
156
    {
157
        $this->slugOptions = $this->getSlugMakerOptions();
158
159
        return str_slug($this->getSlugSourceString(), $this->slugOptions->slugSeparator);
160
    }
161
162
    /**
163
     * Get the string that should be used as base for the slug.
164
     */
165
    protected function getSlugSourceString(): string
166
    {
167
        if (is_callable($this->slugOptions->generateSlugFrom)) {
168
            $slugSourceString = call_user_func($this->slugOptions->generateSlugFrom, $this);
169
170
            return substr($slugSourceString, 0, $this->slugOptions->maximumLength);
0 ignored issues
show
Bug Best Practice introduced by
The expression return substr($slugSourc...Options->maximumLength) could return the type false which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
171
        }
172
173
        $slugSourceString = collect($this->slugOptions->generateSlugFrom)
174
            ->map(function (string $fieldName) : string {
175
                return $this->$fieldName ?? '';
176
            })
177
            ->implode('-');
178
179
        return substr($slugSourceString, 0, $this->slugOptions->maximumLength);
0 ignored issues
show
Bug Best Practice introduced by
The expression return substr($slugSourc...Options->maximumLength) could return the type false which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
180
    }
181
182
    /**
183
     * Make the given slug unique.
184
     */
185
    protected function makeSlugUnique(string $slug): string
186
    {
187
        $originalSlug = $slug;
188
        $i = 1;
189
190
        while ($this->otherRecordExistsWithSlug($slug) || $slug === '') {
191
            $slug = $originalSlug.'-'.$i++;
192
        }
193
194
        return $slug;
195
    }
196
197
    /**
198
     * Determine if a record exists with the given slug.
199
     */
200
    protected function otherRecordExistsWithSlug(string $slug): bool
201
    {
202
        return (bool) $this->slugModel::where($this->slugField, $slug)
203
            ->withoutGlobalScopes()
204
            ->first();
205
    }
206
207
    /**
208
     * This function will throw an exception when any of the options is missing or invalid.
209
     */
210
    protected function guardAgainstInvalidSlugOptions()
211
    {
212
        if (! count($this->slugOptions->generateSlugFrom)) {
213
            throw InvalidOption::missingFromField();
214
        }
215
216
        if (! strlen($this->slugField)) {
217
            throw InvalidOption::missingSlugField();
218
        }
219
220
        if ($this->slugOptions->maximumLength <= 0) {
221
            throw InvalidOption::invalidMaximumLength();
222
        }
223
    }
224
}
225