Completed
Push — master ( 251911...ba69b6 )
by Lorenzo
01:58
created

HasSlug::getSlugFrom()   C

Complexity

Conditions 16
Paths 9

Size

Total Lines 38
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 38
rs 5.0151
c 0
b 0
f 0
cc 16
eloc 23
nc 9
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Padosoft\Sluggable;
4
5
use Illuminate\Database\Eloquent\Model;
6
7
trait HasSlug
8
{
9
    /** @var \Padosoft\Sluggable\SlugOptions */
10
    protected $slugOptions;
11
12
    /**
13
     * Boot the trait.
14
     */
15
    protected static function bootHasSlug()
16
    {
17
        static::creating(function (Model $model) {
18
            $model->addSlug();
19
        });
20
21
        static::updating(function (Model $model) {
22
            $model->addSlug();
23
        });
24
    }
25
26
    /**
27
     * Add the slug to the model.
28
     */
29
    protected function addSlug()
30
    {
31
        $this->slugOptions = $this->getSlugOptionsOrDefault();
32
33
        $this->guardAgainstInvalidSlugOptions();
34
35
        $slug = $this->generateNonUniqueSlug();
36
37
        if ($this->slugOptions->generateUniqueSlugs) {
38
            $slug = $this->makeSlugUnique($slug);
39
        }
40
41
        $slugField = $this->slugOptions->slugField;
42
43
        $this->$slugField = $slug;
44
    }
45
46
    /**
47
     * Retrive a specifice SlugOptions for this model, or return default SlugOptions
48
     */
49
    protected function getSlugOptionsOrDefault()
50
    {
51
        if (method_exists($this, 'getSlugOptions')) {
52
            return $this->getSlugOptions();
53
        } else {
54
            return SlugOptions::create()->getSlugOptionsDefault();
55
        }
56
    }
57
58
    /**
59
     * Generate a non unique slug for this record.
60
     * @return string
61
     * @throws InvalidOption
62
     */
63
    protected function generateNonUniqueSlug(): string
64
    {
65
        if ($this->hasCustomSlugBeenUsed()) {
66
            $slugField = $this->slugOptions->slugField;
67
            return $this->$slugField ?? '';
68
        }
69
        return str_slug($this->getSlugSourceString(), $this->slugOptions->separator);
70
    }
71
72
    /**
73
     * Determine if a custom slug has been saved.
74
     * @return bool
75
     */
76
    protected function hasCustomSlugBeenUsed(): bool
77
    {
78
        $slugField = $this->slugOptions->slugField;
79
80
        if(!$this->$slugField || trim($this->$slugField)==''){
81
            return false;
82
        }
83
        return $this->getOriginal($slugField) != $this->$slugField;
84
    }
85
86
    /**
87
     * Get the string that should be used as base for the slug.
88
     * @return string
89
     * @throws InvalidOption
90
     */
91
    protected function getSlugSourceString(): string
92
    {
93
        if (is_callable($this->slugOptions->generateSlugFrom)) {
94
            $slugSourceString = call_user_func($this->slugOptions->generateSlugFrom, $this);
95
            return substr($slugSourceString, 0, $this->slugOptions->maximumLength);
96
        }
97
98
        $slugFrom = $this->getSlugFrom($this->slugOptions->generateSlugFrom);
99
100
        if(is_null($slugFrom) || (!is_array($slugFrom) && trim($slugFrom)=='')){
101
            if(!$this->slugOptions->generateSlugIfAllSourceFieldsEmpty){
102
                throw InvalidOption::missingFromField();
103
            }
104
105
            return str_random($this->slugOptions->maximumLength > $this->slugOptions->randomUrlLen ? $this->slugOptions->randomUrlLen : $this->slugOptions->maximumLength);
106
        }
107
108
        $slugSourceString = $this->getImplodeSourceString($slugFrom, $this->slugOptions->separator);
109
110
        return substr($slugSourceString, 0, $this->slugOptions->maximumLength);
111
    }
112
113
    /**
114
     * Get the correct field(s) from to generate slug
115
     * @param string|array|callable $fieldName
116
     * @return string|array
117
     */
118
    protected function getSlugFrom($fieldName)
119
    {
120
        if(!is_callable($fieldName) && !is_array($fieldName) && trim($fieldName)==''){
121
            return '';
122
        }
123
124
        if(!is_callable($fieldName) && !is_array($fieldName) && (!data_get($this, $fieldName))){
125
            return '';
126
        }elseif (!is_array($fieldName)){
127
            return $fieldName;
128
        }
129
130
        $slugSourceString = '';
131
        $countFieldName = count($fieldName);
132
        for($i=0;$i<$countFieldName;$i++){
133
134
            $currFieldName = $fieldName[$i];
135
            if(!is_array($currFieldName) && trim($currFieldName)==''){
136
                continue;
137
            }
138
            if (!is_array($currFieldName) && (!data_get($this, $currFieldName))){
139
                continue;
140
            }
141
            if (!is_array($currFieldName) && data_get($this, $currFieldName)){
142
                $slugSourceString = $currFieldName;
143
                break;
144
            }
145
146
            $slugSourceString = $this->getImplodeSourceString($currFieldName, '');
147
148
            if($slugSourceString!=''){
149
                $slugSourceString = $currFieldName;
150
                break;
151
            }
152
        }
153
154
        return $slugSourceString;
155
    }
156
157
    /**
158
     * Make the given slug unique.
159
     * @param string $slug
160
     * @return string
161
     */
162
    protected function makeSlugUnique(string $slug): string
163
    {
164
        $originalSlug = $slug;
165
        $i = 1;
166
167
        while ($this->otherRecordExistsWithSlug($slug) || $slug === '') {
168
            $slug = $originalSlug.$this->slugOptions->separator.$i++;
169
        }
170
171
        return $slug;
172
    }
173
174
    /**
175
     * Determine if a record exists with the given slug.
176
     * @param string $slug
177
     * @return bool
178
     */
179
    protected function otherRecordExistsWithSlug(string $slug): bool
180
    {
181
        return (bool) static::where($this->slugOptions->slugField, $slug)
182
            ->where($this->getKeyName(), '!=', $this->getKey() ?? '0')
183
            ->first();
184
    }
185
186
    /**
187
     * This function will throw an exception when any of the options is missing or invalid.
188
     * @throws InvalidOption
189
     */
190
    protected function guardAgainstInvalidSlugOptions()
191
    {
192
        if (!count($this->slugOptions->generateSlugFrom)) {
193
            throw InvalidOption::missingFromField();
194
        }
195
196
        if (!strlen($this->slugOptions->slugField)) {
197
            throw InvalidOption::missingSlugField();
198
        }
199
200
        if ($this->slugOptions->maximumLength <= 0) {
201
            throw InvalidOption::invalidMaximumLength();
202
        }
203
    }
204
205
    /**
206
     * @param $slugFrom
207
     * @param string $separator
208
     * @return string
209
     */
210
    protected function getImplodeSourceString($slugFrom, string $separator) : string
211
    {
212
        $slugSourceString = collect($slugFrom)
213
            ->map(function (string $fieldName) : string {
214
                if ($fieldName == '') {
215
                    return '';
216
                }
217
                return data_get($this, $fieldName) ?? '';
218
            })
219
            ->implode($separator);
220
        return $slugSourceString;
221
    }
222
}
223