HasSlug::getSlugParams()   C
last analyzed

Complexity

Conditions 14
Paths 27

Size

Total Lines 44
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 38.5

Importance

Changes 0
Metric Value
cc 14
eloc 25
c 0
b 0
f 0
nc 27
nop 1
dl 0
loc 44
ccs 6
cts 12
cp 0.5
crap 38.5
rs 6.2666

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 A17\Twill\Models\Behaviors;
4
5
use Illuminate\Support\Str;
6
7
trait HasSlug
8
{
9
    private $nb_variation_slug = 3;
10
11
    protected static function bootHasSlug()
12
    {
13 33
        static::created(function ($model) {
14
            $model->setSlugs();
15 33
        });
16 21
17 33
        static::updated(function ($model) {
18
            $model->setSlugs();
19 33
        });
20 13
21 33
        static::restored(function ($model) {
22
            $model->setSlugs($restoring = true);
23 33
        });
24 1
    }
25 33
26 33
    /**
27
     * Defines the one-to-many relationship for slug objects.
28 4
     *
29
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
30 4
     */
31 4
    public function slugs()
32
    {
33
        return $this->hasMany($this->getSlugModelClass());
0 ignored issues
show
Bug introduced by
It seems like hasMany() 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 */ hasMany($this->getSlugModelClass());
Loading history...
34
    }
35
36
    /**
37
     * Returns an instance of the slug class for this model.
38
     *
39
     * @return object
40
     */
41 4
    public function getSlugClass()
42
    {
43 4
        return new $this->getSlugModelClass();
44
    }
45
46
    /**
47
     * Returns the fully qualified slug class name for this model.
48
     *
49
     * @return string|null
50
     */
51
    public function getSlugModelClass()
52
    {
53
        $slug = $this->getNamespace() . "\Slugs\\" . $this->getSlugClassName();
54
55
        if (@class_exists($slug)) {
56
            return $slug;
57
        }
58
59
        return $this->getCapsuleSlugClass(class_basename($this));
0 ignored issues
show
Bug introduced by
It seems like getCapsuleSlugClass() 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

59
        return $this->/** @scrutinizer ignore-call */ getCapsuleSlugClass(class_basename($this));
Loading history...
60
    }
61
62
    protected function getSlugClassName()
63
    {
64
        return class_basename($this) . "Slug";
65
    }
66
67
    /**
68
     * @param \Illuminate\Database\Eloquent\Builder $query
69
     * @param string $slug
70
     * @return \Illuminate\Database\Eloquent\Builder
71
     */
72 21
    public function scopeForSlug($query, $slug)
73
    {
74 21
        return $query->whereHas('slugs', function ($query) use ($slug) {
75 21
            $query->whereSlug($slug);
76
            $query->whereActive(true);
77 21
            $query->whereLocale(app()->getLocale());
0 ignored issues
show
introduced by
The method getLocale() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

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

77
            $query->whereLocale(app()->/** @scrutinizer ignore-call */ getLocale());
Loading history...
78
        })->with(['slugs']);
79 21
    }
80
81 21
    /**
82
     * @param \Illuminate\Database\Eloquent\Builder $query
83
     * @param string $slug
84 21
     * @return \Illuminate\Database\Eloquent\Builder
85
     */
86
    public function scopeForInactiveSlug($query, $slug)
87
    {
88 21
        return $query->whereHas('slugs', function ($query) use ($slug) {
89 21
            $query->whereSlug($slug);
90 21
            $query->whereLocale(app()->getLocale());
91 21
        })->with(['slugs']);
92 21
    }
93
94
    /**
95
     * @param \Illuminate\Database\Eloquent\Builder $query
96 21
     * @param string $slug
97
     * @return \Illuminate\Database\Eloquent\Builder
98 21
     */
99
    public function scopeForFallbackLocaleSlug($query, $slug)
100 21
    {
101
        return $query->whereHas('slugs', function ($query) use ($slug) {
102 21
            $query->whereSlug($slug);
103 21
            $query->whereActive(true);
104
            $query->whereLocale(config('translatable.fallback_locale'));
105 21
        })->with(['slugs']);
106
    }
107 21
108 21
    /**
109 21
     * @param bool $restoring
110 21
     * @return void
111 21
     */
112 21
    public function setSlugs($restoring = false)
113
    {
114 21
        foreach ($this->getSlugParams() as $slugParams) {
115
            $this->updateOrNewSlug($slugParams, $restoring);
116 21
        }
117
    }
118
119
    /**
120 21
     * @param array $slugParams
121
     * @param bool $restoring
122
     * @return void
123 21
     */
124
    public function updateOrNewSlug($slugParams, $restoring = false)
125 21
    {
126 21
        if (in_array($slugParams['locale'], config('twill.slug_utf8_languages', []))) {
127 21
            $slugParams['slug'] = $this->getUtf8Slug($slugParams['slug']);
128
        } else {
129
            $slugParams['slug'] = Str::slug($slugParams['slug']);
130 21
        }
131
132 21
        //active old slug if already existing or create a new one
133
        if (
134 21
            (($oldSlug = $this->getExistingSlug($slugParams)) != null)
135
            && ($restoring ? $slugParams['slug'] === $this->suffixSlugIfExisting($slugParams) : true)
136 21
        ) {
137 21
            if (!$oldSlug->active && ($slugParams['active'] ?? false)) {
138
                $this->getSlugModelClass()::where('id', $oldSlug->id)->update(['active' => 1]);
139 21
                $this->disableLocaleSlugs($oldSlug->locale, $oldSlug->id);
140
            }
141 21
        } else {
142 21
            $this->addOneSlug($slugParams);
143 21
        }
144 21
    }
145 21
146
    /**
147 21
     * @param array $slugParams
148
     * @return object|null
149 21
     */
150
    public function getExistingSlug($slugParams)
151 21
    {
152 21
        unset($slugParams['active']);
153
154 21
        $query = $this->slugs();
155
156 21
        foreach ($slugParams as $key => $value) {
157 21
            //check variations of the slug
158 21
            if ($key == 'slug') {
159 21
                $query->where(function ($query) use ($value) {
160 21
                    $query->orWhere('slug', $value);
161
                    $query->orWhere('slug', $value . '-' . $this->getSuffixSlug());
162
                    for ($i = 2; $i <= $this->nb_variation_slug; $i++) {
163 21
                        $query->orWhere('slug', $value . '-' . $i);
164 21
                    }
165
                });
166
            } else {
167
                $query->where($key, $value);
168
            }
169
        }
170
171
        return $query->first();
172 21
    }
173
174
    protected function addOneSlug($slugParams)
175
    {
176
        $datas = [];
177
        foreach ($slugParams as $key => $value) {
178
            $datas[$key] = $value;
179
        }
180
181
        $datas['slug'] = $this->suffixSlugIfExisting($slugParams);
182
183
        $datas[$this->getForeignKey()] = $this->id;
184
185
        $id = $this->getSlugModelClass()::insertGetId($datas);
186
187
        $this->disableLocaleSlugs($slugParams['locale'], $id);
188
    }
189
190
    /**
191
     * @param string $locale
192
     * @param int $except_slug_id
193
     * @return void
194
     */
195
    public function disableLocaleSlugs($locale, $except_slug_id = 0)
196
    {
197
        $this->getSlugModelClass()::where($this->getForeignKey(), $this->id)
198
            ->where('id', '<>', $except_slug_id)
199
            ->where('locale', $locale)
200
            ->update(['active' => 0]);
201
    }
202
203
    private function suffixSlugIfExisting($slugParams)
204
    {
205
        $slugBackup = $slugParams['slug'];
206
207 21
        unset($slugParams['active']);
208
209 21
        for ($i = 2; $i <= $this->nb_variation_slug + 1; $i++) {
210
            $qCheck = $this->getSlugModelClass()::query();
211
            $qCheck->whereNull($this->getDeletedAtColumn());
0 ignored issues
show
Bug introduced by
It seems like getDeletedAtColumn() 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

211
            $qCheck->whereNull($this->/** @scrutinizer ignore-call */ getDeletedAtColumn());
Loading history...
212
            foreach ($slugParams as $key => $value) {
213
                $qCheck->where($key, '=', $value);
214
            }
215
216 21
            if ($qCheck->first() == null) {
217 21
                break;
218 21
            }
219 21
220
            if (!empty($slugParams['slug'])) {
221 21
                $slugParams['slug'] = $slugBackup . (($i > $this->nb_variation_slug) ? "-" . $this->getSuffixSlug() : "-{$i}");
222
            }
223 21
        }
224 21
225
        return $slugParams['slug'];
226
    }
227
228
    /**
229
     * Returns the active slug object for this model.
230
     *
231
     * @param string|null $locale Locale of the slug if your site has multiple languages.
232 21
     * @return object|null
233
     */
234
    public function getActiveSlug($locale = null)
235
    {
236
        return $this->slugs->first(function ($slug) use ($locale) {
237 21
            return ($slug->locale === ($locale ?? app()->getLocale())) && $slug->active;
238 21
        }) ?? null;
239 21
    }
240 21
241
    /**
242 21
     * Returns the fallback active slug object for this model.
243 21
     *
244
     * @return object|null
245
     */
246 21
    public function getFallbackActiveSlug()
247
    {
248
        return $this->slugs->first(function ($slug) {
249
            return $slug->locale === config('translatable.fallback_locale') && $slug->active;
250 21
        }) ?? null;
251
    }
252
253
    /**
254
     * Returns the active slug string for this model.
255
     *
256
     * @param string|null $locale Locale of the slug if your site has multiple languages.
257
     * @return string
258
     */
259
    public function getSlug($locale = null)
260
    {
261
        if (($slug = $this->getActiveSlug($locale)) != null) {
262
            return $slug->slug;
263
        }
264
265
        if (config('translatable.use_property_fallback', false) && (($slug = $this->getFallbackActiveSlug()) != null)) {
266
            return $slug->slug;
267
        }
268
269
        return "";
270
    }
271
272
    /**
273
     * @return string
274
     */
275
    public function getSlugAttribute()
276
    {
277
        return $this->getSlug();
278
    }
279
280
    /**
281
     * @param string|null $locale
282
     * @return array|null
283
     */
284
    public function getSlugParams($locale = null)
285
    {
286
        if (count(getLocales()) === 1 || !isset($this->translations)) {
287
            $slugParams = $this->getSingleSlugParams($locale);
288
            if ($slugParams != null && !empty($slugParams)) {
289
                return $slugParams;
290 21
            }
291
        }
292 21
293
        $slugParams = [];
294
        foreach ($this->translations as $translation) {
295 32
            if ($translation->locale == $locale || $locale == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $locale of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
296
                $attributes = $this->slugAttributes;
297 32
298
                $slugAttribute = array_shift($attributes);
299
300 21
                $slugDependenciesAttributes = [];
301
                foreach ($attributes as $attribute) {
302 21
                    if (!isset($this->$attribute)) {
303
                        throw new \Exception("You must define the field {$attribute} in your model");
304
                    }
305
306
                    $slugDependenciesAttributes[$attribute] = $this->$attribute;
307
                }
308
309
                if (!isset($translation->$slugAttribute) && !isset($this->$slugAttribute)) {
310
                    throw new \Exception("You must define the field {$slugAttribute} in your model");
311
                }
312
313
                $slugParam = [
314
                    'active' => $translation->active,
315
                    'slug' => $translation->$slugAttribute ?? $this->$slugAttribute,
316
                    'locale' => $translation->locale,
317
                ] + $slugDependenciesAttributes;
318
319
                if ($locale != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $locale of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
320
                    return $slugParam;
321
                }
322
323
                $slugParams[] = $slugParam;
324
            }
325
        }
326
327
        return $locale == null ? $slugParams : null;
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $locale of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
328
    }
329
330
    /**
331
     * @param string|null $locale
332
     * @return array|null
333
     */
334
    public function getSingleSlugParams($locale = null)
335
    {
336
        $slugParams = [];
337
        foreach (getLocales() as $appLocale) {
338
            if ($appLocale == $locale || $locale == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $locale of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
339
                $attributes = $this->slugAttributes;
340
                $slugAttribute = array_shift($attributes);
341
                $slugDependenciesAttributes = [];
342
                foreach ($attributes as $attribute) {
343
                    if (!isset($this->$attribute)) {
344
                        throw new \Exception("You must define the field {$attribute} in your model");
345
                    }
346
347
                    $slugDependenciesAttributes[$attribute] = $this->$attribute;
348
                }
349
350
                if (!isset($this->$slugAttribute)) {
351
                    throw new \Exception("You must define the field {$slugAttribute} in your model");
352
                }
353
354
                $slugParam = [
355
                    'active' => 1,
356
                    'slug' => $this->$slugAttribute,
357
                    'locale' => $appLocale,
358
                ] + $slugDependenciesAttributes;
359
360
                if ($locale != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $locale of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
361
                    return $slugParam;
362
                }
363
364
                $slugParams[] = $slugParam;
365
            }
366
        }
367
368
        return $locale == null ? $slugParams : null;
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $locale of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
369
    }
370
371
    /**
372
     * Returns the database table name for this model's slugs.
373
     *
374
     * @return string
375
     */
376
    public function getSlugsTable()
377
    {
378
        return $this->slugs()->getRelated()->getTable();
379
    }
380
381
    /**
382
     * Returns the database foreign key column name for this model.
383
     *
384
     * @return string
385
     */
386
    public function getForeignKey()
387
    {
388
        return Str::snake(class_basename(get_class($this))) . "_id";
389
    }
390
391
    protected function getSuffixSlug()
392
    {
393
        return $this->id;
394
    }
395
396
    /**
397
     * Generate a URL friendly slug from a UTF-8 string.
398
     *
399
     * @param string $str
400
     * @param array $options
401
     * @return string
402
     */
403
    public function getUtf8Slug($str, $options = [])
404
    {
405
        // Make sure string is in UTF-8 and strip invalid UTF-8 characters
406
        $str = mb_convert_encoding((string) $str, 'UTF-8', mb_list_encodings());
407
408
        $defaults = array(
409
            'delimiter' => '-',
410
            'limit' => null,
411
            'lowercase' => true,
412
            'replacements' => array(),
413
            'transliterate' => true,
414
        );
415
416
        // Merge options
417
        $options = array_merge($defaults, $options);
418
419
        $char_map = array(
420
            // Latin
421
            'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A', 'Æ' => 'AE', 'Ç' => 'C',
422
            'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I',
423
            'Ð' => 'D', 'Ñ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' => 'O', 'Ő' => 'O',
424
            'Ø' => 'O', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ű' => 'U', 'Ý' => 'Y', 'Þ' => 'TH',
425
            'ß' => 'ss',
426
            'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a', 'å' => 'a', 'æ' => 'ae', 'ç' => 'c',
427
            'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e', 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i',
428
            'ð' => 'd', 'ñ' => 'n', 'ò' => 'o', 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ő' => 'o',
429
            'ø' => 'o', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ü' => 'u', 'ű' => 'u', 'ý' => 'y', 'þ' => 'th',
430
            'ÿ' => 'y',
431
432
            // Latin symbols
433
            '©' => '(c)',
434
435
            // Greek
436
            'Α' => 'A', 'Β' => 'B', 'Γ' => 'G', 'Δ' => 'D', 'Ε' => 'E', 'Ζ' => 'Z', 'Η' => 'H', 'Θ' => '8',
437
            'Ι' => 'I', 'Κ' => 'K', 'Λ' => 'L', 'Μ' => 'M', 'Ν' => 'N', 'Ξ' => '3', 'Ο' => 'O', 'Π' => 'P',
438
            'Ρ' => 'R', 'Σ' => 'S', 'Τ' => 'T', 'Υ' => 'Y', 'Φ' => 'F', 'Χ' => 'X', 'Ψ' => 'PS', 'Ω' => 'W',
439
            'Ά' => 'A', 'Έ' => 'E', 'Ί' => 'I', 'Ό' => 'O', 'Ύ' => 'Y', 'Ή' => 'H', 'Ώ' => 'W', 'Ϊ' => 'I',
440
            'Ϋ' => 'Y',
441
            'α' => 'a', 'β' => 'b', 'γ' => 'g', 'δ' => 'd', 'ε' => 'e', 'ζ' => 'z', 'η' => 'h', 'θ' => '8',
442
            'ι' => 'i', 'κ' => 'k', 'λ' => 'l', 'μ' => 'm', 'ν' => 'n', 'ξ' => '3', 'ο' => 'o', 'π' => 'p',
443
            'ρ' => 'r', 'σ' => 's', 'τ' => 't', 'υ' => 'y', 'φ' => 'f', 'χ' => 'x', 'ψ' => 'ps', 'ω' => 'w',
444
            'ά' => 'a', 'έ' => 'e', 'ί' => 'i', 'ό' => 'o', 'ύ' => 'y', 'ή' => 'h', 'ώ' => 'w', 'ς' => 's',
445
            'ϊ' => 'i', 'ΰ' => 'y', 'ϋ' => 'y', 'ΐ' => 'i',
446
447
            // Turkish
448
            'Ş' => 'S', 'İ' => 'I', 'Ç' => 'C', 'Ü' => 'U', 'Ö' => 'O', 'Ğ' => 'G',
449
            'ş' => 's', 'ı' => 'i', 'ç' => 'c', 'ü' => 'u', 'ö' => 'o', 'ğ' => 'g',
450
451
            // Russian
452
            'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D', 'Е' => 'E', 'Ё' => 'Yo', 'Ж' => 'Zh',
453
            'З' => 'Z', 'И' => 'I', 'Й' => 'J', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N', 'О' => 'O',
454
            'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T', 'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'C',
455
            'Ч' => 'Ch', 'Ш' => 'Sh', 'Щ' => 'Sh', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '', 'Э' => 'E', 'Ю' => 'Yu',
456
            'Я' => 'Ya',
457
            'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'yo', 'ж' => 'zh',
458
            'з' => 'z', 'и' => 'i', 'й' => 'j', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o',
459
            'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c',
460
            'ч' => 'ch', 'ш' => 'sh', 'щ' => 'sh', 'ъ' => '', 'ы' => 'y', 'ь' => '', 'э' => 'e', 'ю' => 'yu',
461
            'я' => 'ya',
462
463
            // Ukrainian
464
            'Є' => 'Ye', 'І' => 'I', 'Ї' => 'Yi', 'Ґ' => 'G',
465
            'є' => 'ye', 'і' => 'i', 'ї' => 'yi', 'ґ' => 'g',
466
467
            // Kazakh
468
            'Ә' => 'A', 'Ғ' => 'G', 'Қ' => 'Q', 'Ң' => 'N', 'Ө' => 'O', 'Ұ' => 'U',
469
            'ә' => 'a', 'ғ' => 'g', 'қ' => 'q', 'ң' => 'n', 'ө' => 'o', 'ұ' => 'u',
470
471
            // Czech
472
            'Č' => 'C', 'Ď' => 'D', 'Ě' => 'E', 'Ň' => 'N', 'Ř' => 'R', 'Š' => 'S', 'Ť' => 'T', 'Ů' => 'U',
473
            'Ž' => 'Z',
474
            'č' => 'c', 'ď' => 'd', 'ě' => 'e', 'ň' => 'n', 'ř' => 'r', 'š' => 's', 'ť' => 't', 'ů' => 'u',
475
            'ž' => 'z',
476
477
            // Polish
478
            'Ą' => 'A', 'Ć' => 'C', 'Ę' => 'e', 'Ł' => 'L', 'Ń' => 'N', 'Ó' => 'o', 'Ś' => 'S', 'Ź' => 'Z',
479
            'Ż' => 'Z',
480
            'ą' => 'a', 'ć' => 'c', 'ę' => 'e', 'ł' => 'l', 'ń' => 'n', 'ó' => 'o', 'ś' => 's', 'ź' => 'z',
481
            'ż' => 'z',
482
483
            // Latvian
484
            'Ā' => 'A', 'Č' => 'C', 'Ē' => 'E', 'Ģ' => 'G', 'Ī' => 'i', 'Ķ' => 'k', 'Ļ' => 'L', 'Ņ' => 'N',
485
            'Š' => 'S', 'Ū' => 'u', 'Ž' => 'Z',
486
            'ā' => 'a', 'č' => 'c', 'ē' => 'e', 'ģ' => 'g', 'ī' => 'i', 'ķ' => 'k', 'ļ' => 'l', 'ņ' => 'n',
487
            'š' => 's', 'ū' => 'u', 'ž' => 'z',
488
489
            // Romanian
490
            'Ă' => 'A', 'Â' => 'A', 'Î' => 'I', 'Ș' => 'S', 'Ț' => 'T',
491
            'ă' => 'a', 'â' => 'a', 'î' => 'i', 'ș' => 's', 'ț' => 't',
492
        );
493
494
        // Make custom replacements
495
        $str = preg_replace(array_keys($options['replacements']), $options['replacements'], $str);
496
497
        // Transliterate characters to ASCII
498
        if ($options['transliterate']) {
499
            $str = str_replace(array_keys($char_map), $char_map, $str);
500
        }
501
502
        // Replace non-alphanumeric characters with our delimiter
503
        $str = preg_replace('/[^\p{L}\p{Nd}]+/u', $options['delimiter'], $str);
504
505
        // Remove duplicate delimiters
506
        $str = preg_replace('/(' . preg_quote($options['delimiter'], '/') . '){2,}/', '$1', $str);
507
508
        // Truncate slug to max. characters
509
        $str = mb_substr($str, 0, ($options['limit'] ? $options['limit'] : mb_strlen($str, 'UTF-8')), 'UTF-8');
510
511
        // Remove delimiter from ends
512
        $str = trim($str, $options['delimiter']);
513
514
        return $options['lowercase'] ? mb_strtolower($str, 'UTF-8') : $str;
515
    }
516
517
    /**
518
     * Generate a URL friendly slug from a given string.
519
     *
520
     * @param string $string
521
     * @return string
522
     */
523
    public function urlSlugShorter($string)
524
    {
525
        return strtolower(trim(preg_replace('~[^0-9a-z]+~i', '-', html_entity_decode(preg_replace('~&([a-z]{1,2})(?:acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', htmlentities($string, ENT_QUOTES, 'UTF-8')), ENT_QUOTES, 'UTF-8')), '-'));
526
    }
527
528
    /**
529
     * Returns the fully qualified namespace for this model.
530
     *
531
     * @return string
532
     */
533
    public function getNamespace()
534
    {
535
        $pos = mb_strrpos(self::class, '\\');
536
537
        if ($pos === false) {
538
            return self::class;
539
        }
540
541
        return Str::substr(self::class, 0, $pos);
542
    }
543
}
544