Passed
Push — master ( 46db56...ae0576 )
by Adrien
03:04
created

Redirect::setNewUrlAttribute()   A

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 1
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 whereNewUrl(string $url): Builder
17
 * @method static whereOldUrl(string $url): Builder
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 8
    }
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 7
    }
69
70 7
    protected function parseRelativeUrl(string $url, $fragment = true): string {
71 7
        $parsed = parse_url($url);
72 7
        $path = $parsed['path'];
73 7
        if (!empty($parsed['query'])) {
74 1
            $path .= '?' . $parsed['query'];
75
        }
76 7
        if ($fragment && !empty($parsed['fragment'])) {
77 1
            $path .= '#' . $parsed['fragment'];
78
        }
79 7
        return trim($path, '/');
80
    }
81
82
    /**
83
     * The mutator to set the "new_url" attribute.
84
     *
85
     * @param  string  $value
86
     */
87 6
    public function setNewUrlAttribute(string $value)
88
    {
89 6
        $this->attributes['new_url'] = $this->parseRelativeUrl($value);
90 6
    }
91
92
    /**
93
     * The mutator to set the "new_url" attribute if the new url is external.
94
     *
95
     * @param  string  $value
96
     */
97 1
    public function setNewUrlExternalAttribute(string $value)
98
    {
99 1
        $this->attributes['new_url'] = trim($value, '/');
100 1
    }
101
102
    /**
103
     * Filter the query by an old url.
104
     *
105
     * @param  Builder  $query
106
     * @param  string  $url
107
     * @return Builder
108
     */
109 7
    public function scopeWhereOldUrl(Builder $query, string $url): Builder
110
    {
111 7
        return $query->where('old_url', $url);
112
    }
113
114
    /**
115
     * Filter the query by a new url.
116
     *
117
     * @param  Builder  $query
118
     * @param  string  $url
119
     * @return Builder
120
     */
121 6
    public function scopeWhereNewUrl(Builder $query, string $url): Builder
122
    {
123 6
        return $query->where('new_url', $url);
124
    }
125
126
    /**
127
     * Get all redirect statuses defined inside the "config/redirects.php" file.
128
     *
129
     * @return array
130
     */
131 5
    public static function getStatuses(): array
132
    {
133 5
        return (array) config('redirects.statuses', []);
134
    }
135
136
    /**
137
     * Sync old redirects to point to the new (final) url.
138
     *
139
     * @param  RedirectModelContract  $model
140
     * @param  string  $finalUrl
141
     * @return void
142
     */
143 6
    public function syncOldRedirects(RedirectModelContract $model, string $finalUrl): void
144
    {
145 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...
146
147 6
        foreach ($items as $item) {
148 1
            $item->update(['new_url' => $finalUrl]);
149 1
            $item->syncOldRedirects($model, $finalUrl);
150
        }
151 6
    }
152
153
    /**
154
     * Return a valid redirect entity for a given path (old url).
155
     * A redirect is valid if:
156
     * - it has an url to redirect to (new url)
157
     * - it's status code is one of the statuses defined on this model.
158
     *
159
     * @param  string  $path
160
     * @return Redirect|null
161
     */
162 5
    public static function findValidOrNull(string $path): ?RedirectModelContract
163
    {
164 5
        return static::whereOldUrl($path === '/' ? $path : trim($path, '/'))
165 5
            ->whereNotNull('new_url')
166 5
            ->whereIn('status', array_keys(self::getStatuses()))
167 5
            ->latest()->first();
168
    }
169
}
170