Redirect::scopeWhereOldUrl()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Tofandel\Redirects\Models;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Model;
7
use Tofandel\Redirects\Contracts\RedirectModelContract;
8
use Tofandel\Redirects\Exceptions\RedirectException;
9
10
/**
11
 * @property string $new_url
12
 * @property string $old_url
13
 * @property-write string $new_url_external
14
 * @property int $status
15
 *
16
 * @method static Builder whereNewUrl(string $url)
17
 * @method static Builder whereOldUrl(string $url)
18
 */
19
class Redirect extends Model implements RedirectModelContract
20
{
21
    /**
22
     * The database table.
23
     *
24
     * @var string
25
     */
26
    protected $table = 'redirects';
27
28
    /**
29
     * The attributes that are mass assignable.
30
     *
31
     * @var array
32
     */
33
    protected $fillable = [
34
        'old_url',
35
        'new_url',
36
        'new_url_external',
37
        'status',
38
    ];
39
40
    /**
41
     * Boot the model.
42
     *
43
     * @return void
44
     */
45 8
    public static function boot()
46
    {
47 8
        parent::boot();
48
49 8
        static::saving(function (self $model) {
50 7
            if (trim(mb_strtolower($model->old_url), '/') == trim(mb_strtolower($model->new_url), '/')) {
51 1
                throw RedirectException::sameUrls();
52
            }
53
54 6
            static::whereOldUrl($model->new_url)->whereNewUrl($model->old_url)->delete();
55
56 6
            $model->syncOldRedirects($model, $model->new_url);
57 8
        });
58
    }
59
60
    /**
61
     * The mutator to set the "old_url" attribute.
62
     *
63
     * @param  string  $value
64
     */
65 7
    public function setOldUrlAttribute(string $value)
66
    {
67 7
        $this->attributes['old_url'] = $this->parseRelativeUrl($value, false);
68
    }
69
70 7
    protected function parseRelativeUrl(string $url, $fragment = true): string
71
    {
72 7
        $parsed = parse_url($url);
73 7
        $path = $parsed['path'];
74 7
        if (! empty($parsed['query'])) {
75 1
            $path .= '?'.$parsed['query'];
76
        }
77 7
        if ($fragment && ! empty($parsed['fragment'])) {
78 1
            $path .= '#'.$parsed['fragment'];
79
        }
80
81 7
        return trim($path, '/');
82
    }
83
84
    /**
85
     * The mutator to set the "new_url" attribute.
86
     *
87
     * @param  string  $value
88
     */
89 6
    public function setNewUrlAttribute(string $value)
90
    {
91 6
        $this->attributes['new_url'] = $this->parseRelativeUrl($value);
92
    }
93
94
    /**
95
     * The mutator to set the "new_url" attribute if the new url is external.
96
     *
97
     * @param  string  $value
98
     */
99 1
    public function setNewUrlExternalAttribute(string $value)
100
    {
101 1
        $this->attributes['new_url'] = trim($value, '/');
102
    }
103
104
    /**
105
     * Filter the query by an old url.
106
     *
107
     * @param  Builder  $query
108
     * @param  string  $url
109
     * @return Builder
110
     */
111 7
    public function scopeWhereOldUrl(Builder $query, string $url): Builder
112
    {
113 7
        return $query->where('old_url', $url);
114
    }
115
116
    /**
117
     * Filter the query by a new url.
118
     *
119
     * @param  Builder  $query
120
     * @param  string  $url
121
     * @return Builder
122
     */
123 6
    public function scopeWhereNewUrl(Builder $query, string $url): Builder
124
    {
125 6
        return $query->where('new_url', $url);
126
    }
127
128
    /**
129
     * Get all redirect statuses defined inside the "config/redirects.php" file.
130
     *
131
     * @return array
132
     */
133 5
    public static function getStatuses(): array
134
    {
135 5
        return (array) config('redirects.statuses', []);
136
    }
137
138
    /**
139
     * Sync old redirects to point to the new (final) url.
140
     *
141
     * @param  RedirectModelContract  $model
142
     * @param  string  $finalUrl
143
     * @return void
144
     */
145 6
    public function syncOldRedirects(RedirectModelContract $model, string $finalUrl): void
146
    {
147 6
        $items = static::whereNewUrl($model->old_url)->get();
0 ignored issues
show
Bug introduced by
Accessing old_url on the interface Tofandel\Redirects\Contracts\RedirectModelContract suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
148
149 6
        foreach ($items as $item) {
150 1
            $item->update(['new_url' => $finalUrl]);
151 1
            $item->syncOldRedirects($model, $finalUrl);
152
        }
153
    }
154
155
    /**
156
     * Return a valid redirect entity for a given path (old url).
157
     * A redirect is valid if:
158
     * - it has an url to redirect to (new url)
159
     * - it's status code is one of the statuses defined on this model.
160
     *
161
     * @param  string  $path
162
     * @return Redirect|Model|null
163
     */
164 5
    public static function findValidOrNull(string $path): ?RedirectModelContract
165
    {
166 5
        return static::whereOldUrl($path === '/' ? $path : trim($path, '/'))
167 5
            ->whereNotNull('new_url')
168 5
            ->whereIn('status', array_keys(self::getStatuses()))
169 5
            ->latest()->first();
170
    }
171
}
172