Passed
Push — ft/sitemap ( 686bce...8c914b )
by Ben
07:09
created

UrlRecord::exists()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
c 1
b 0
f 0
dl 0
loc 22
ccs 10
cts 10
cp 1
rs 9.8666
cc 4
nc 8
nop 4
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Thinktomorrow\Chief\Urls;
6
7
use Illuminate\Support\Collection;
8
use Illuminate\Database\Eloquent\Model;
9
use Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl;
10
use Thinktomorrow\Chief\Concerns\Morphable\Morphables;
11
12
class UrlRecord extends Model
13
{
14
    public $table = 'chief_urls';
15
16
    public $guarded = [];
17
18
    /**
19
     * Find matching url record for passed slug and locale. The locale parameter will try
20
     * to match specific given locales first and records without locale as fallback.
21
     *
22 29
     * @param string $slug
23
     * @param string $locale
24
     * @return UrlRecord
25 29
     * @throws UrlRecordNotFound
26 27
     */
27
    public static function findBySlug(string $slug, string $locale): UrlRecord
28
    {
29 29
        // Clear the input from any trailing slashes.
30 29
        if ($slug != '/') {
31 29
            $slug = trim($slug, '/');
32 29
        }
33
34 29
        $record = static::where('slug', $slug)
35 4
            ->where('locale', $locale)
36
            ->orderBy('redirect_id', 'ASC')
37
            ->first();
38 25
39
        if (!$record) {
40
            throw new UrlRecordNotFound('No url record found by slug [' . $slug . '] for locale [' . $locale . '].');
41
        }
42
43
        return $record;
44
    }
45
46
    /**
47
     * Find matching url record for passed slug and locale. The locale parameter will try
48
     * to match specific given locales first and records without locale as fallback.
49
     *
50 7
     * @param Model $model
51
     * @param string $locale
52 7
     * @return UrlRecord
53 7
     * @throws UrlRecordNotFound
54 7
     */
55 7
    public static function findByModel(Model $model, string $locale): UrlRecord
56 7
    {
57
        $record = static::where('model_type', $model->getMorphClass())
58 7
            ->where('model_id', $model->id)
59
            ->where('locale', $locale)
60
            ->orderBy('redirect_id', 'ASC')
61
            ->first();
62 7
63
        if (!$record) {
64
            throw new UrlRecordNotFound('No url record found for model [' . $model->getMorphClass() . '@' . $model->id . '] for locale [' . $locale . '].');
65 93
        }
66
67 93
        return $record;
68 93
    }
69 93
70
    public static function getByModel(Model $model)
71
    {
72 1
        return static::where('model_type', $model->getMorphClass())
73
            ->where('model_id', $model->id)
74 1
            ->get();
75 1
    }
76 1
77 1
    public static function findRecentRedirect(Model $model, string $locale): ?self
78 1
    {
79 1
        return static::where('model_type', $model->getMorphClass())
80
            ->where('model_id', $model->id)
81
            ->where('locale', $locale)
82 19
            ->where('redirect_id', '<>', null)
83
            ->orderBy('updated_at', 'DESC')
84 19
            ->first();
85 19
    }
86 19
87 19
    public function replaceAndRedirect(array $values): UrlRecord
88 19
    {
89
        $newRecord = static::firstOrCreate(array_merge([
90 19
            'locale'     => $this->locale,
91
            'model_type' => $this->model_type,
92 19
            'model_id'   => $this->model_id,
93
        ], $values));
94
95 22
        $this->redirectTo($newRecord);
96
97 22
        return $newRecord;
98 3
    }
99
100
    public function redirectTo(self $record = null): ?UrlRecord
101 22
    {
102 22
        if (!$record) {
103
            return $this->isRedirect() ? static::find($this->redirect_id) : null;
104 22
        }
105
106
        $this->redirect_id = $record->id;
107
        $this->save();
108 1
109
        return null;
110 1
    }
111 1
112
    // Remove all urls that came after this one
113
    public function revert()
114
    {
115 1
        if (!$this->isRedirect()) {
116 1
            return;
117 1
        }
118
119 1
        // Remove this redirect relation so it's no longer cascading when main url is getting deleted.
120 1
        $redirect_id = $this->redirect_id;
121 1
        $this->redirect_id = null;
122
        $this->save();
123 1
124
        if ($record = static::where('id', $redirect_id)->first()) {
125 89
            $record->revert();
126
            $record->delete();
127 89
        }
128
    }
129
130 80
    public function isRedirect(): bool
131
    {
132 80
        return !!($this->redirect_id);
133
    }
134
135 80
    public function isHomepage(): bool
136
    {
137 80
        return $this->slug === '/';
138
    }
139
140 80
    public static function existsIgnoringRedirects($slug, string $locale = null, Model $ignoredModel = null): bool
141
    {
142 80
        return static::exists($slug, $locale, $ignoredModel, false);
143
    }
144 80
145 80
    public static function exists($slug, string $locale = null, Model $ignoredModel = null, bool $includeRedirects = true): bool
146
    {
147
        $builder = static::where('slug', $slug);
148 80
149 80
        if ($locale) {
150
            $builder->where('locale', $locale);
151
        }
152 80
153
        if (!$includeRedirects) {
154 59
            $builder->whereNull('redirect_id');
155 59
        }
156 59
157 59
        if ($ignoredModel) {
158 59
            $builder->whereNotIn('id', function ($query) use ($ignoredModel) {
159
                $query->select('id')
160
                    ->from('chief_urls')
161 80
                    ->where('model_type', '=', $ignoredModel->getMorphClass())
162
                    ->where('model_id', '=', $ignoredModel->id);
163
            });
164
        }
165
166
        return ($builder->count() > 0);
167
    }
168
169
    public static function allOnlineModels(string $locale): Collection
170
    {
171
        $records = static::where('locale', $locale)
172
            ->where('redirect_id', '=', null)
173
            ->orderBy('updated_at', 'DESC')
174
            ->get();
175
176
        // Filter out offline urls... TODO: this should be a state that is owned by the url and not the model.
177
        return $records->map(function(UrlRecord $urlRecord){
178
            return Morphables::instance($urlRecord->model_type)->find($urlRecord->model_id);
179
        })->reject(function(ProvidesUrl $model){
180
            return (method_exists($model, 'isPublished') && !$model->isPublished());
181
        });
182
    }
183
}
184