Completed
Pull Request — master (#274)
by
unknown
63:55 queued 33:13
created

Page::url()   A

Complexity

Conditions 3
Paths 6

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 12
ccs 7
cts 7
cp 1
rs 10
cc 3
nc 6
nop 1
crap 3
1
<?php
2
3
namespace Thinktomorrow\Chief\Pages;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Database\Eloquent\Model;
7
use Thinktomorrow\Chief\Management\ManagedModel;
8
use Thinktomorrow\Chief\Urls\MemoizedUrlRecord;
9
use Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl;
10
use Thinktomorrow\Chief\Urls\ProvidesUrl\ResolvingRoute;
11
use Thinktomorrow\Chief\Concerns\Viewable\Viewable;
12
use Thinktomorrow\Chief\Concerns\Viewable\ViewableContract;
13
use Thinktomorrow\Chief\Modules\Module;
14
use Thinktomorrow\Chief\Audit\AuditTrait;
15
use Spatie\MediaLibrary\HasMedia\HasMedia;
16
use Thinktomorrow\Chief\Concerns\Featurable;
17
use Thinktomorrow\Chief\Menu\ActsAsMenuItem;
18
use Illuminate\Database\Eloquent\SoftDeletes;
19
use Thinktomorrow\Chief\Relations\ActsAsChild;
20
use Thinktomorrow\Chief\Snippets\WithSnippets;
21
use Thinktomorrow\Chief\Relations\ActsAsParent;
22
use Thinktomorrow\Chief\Relations\ActingAsChild;
23
use Thinktomorrow\AssetLibrary\Traits\AssetTrait;
24
use Thinktomorrow\Chief\Relations\ActingAsParent;
25
use Thinktomorrow\Chief\Concerns\Morphable\Morphable;
26
use Thinktomorrow\Chief\FlatReferences\FlatReference;
27
use Thinktomorrow\Chief\Concerns\Archivable\Archivable;
28
use Astrotomic\Translatable\Translatable as BaseTranslatable;
29
use Thinktomorrow\Chief\Concerns\Publishable\Publishable;
30
use Thinktomorrow\Chief\Concerns\Translatable\Translatable;
31
use Thinktomorrow\Chief\Concerns\Morphable\MorphableContract;
32
use Thinktomorrow\Chief\Concerns\Translatable\TranslatableContract;
33
use Thinktomorrow\Chief\Urls\UrlRecordNotFound;
34
35
class Page extends Model implements ManagedModel, TranslatableContract, HasMedia, ActsAsParent, ActsAsChild, ActsAsMenuItem, MorphableContract, ViewableContract, ProvidesUrl
36
{
37
    use BaseTranslatable {
38
        getAttribute as getTranslatableAttribute;
39
    }
40
41
    use Morphable,
0 ignored issues
show
introduced by
The trait Thinktomorrow\Chief\Concerns\Viewable\Viewable requires some properties which are not provided by Thinktomorrow\Chief\Pages\Page: $content, $viewKey
Loading history...
introduced by
The trait Thinktomorrow\AssetLibrary\Traits\AssetTrait requires some properties which are not provided by Thinktomorrow\Chief\Pages\Page: $assets, $pivot, $each, $locale, $mediaConversionRegistrations, $media, $type, $collection_name
Loading history...
Bug introduced by
The trait Thinktomorrow\Chief\Concerns\Morphable\Morphable requires the property $morph_key which is not provided by Thinktomorrow\Chief\Pages\Page.
Loading history...
42
        AssetTrait,
43
        Translatable,
44
        SoftDeletes,
45
        Publishable,
46
        Featurable,
47
        Archivable,
48
        AuditTrait,
49
        ActingAsParent,
50
        ActingAsChild,
51
        WithSnippets,
52
        ResolvingRoute,
53
        Viewable;
54
55
    // Explicitly mention the translation model so on inheritance the child class uses the proper default translation model
56
    protected $translationModel      = PageTranslation::class;
57
    protected $translationForeignKey = 'page_id';
58
    protected $translatedAttributes  = [
59
        'title', 'content', 'short', 'seo_title', 'seo_description', 'seo_keywords', 'seo_image'
60
    ];
61
62
    public $table          = "pages";
63
    protected $guarded     = [];
64
    protected $with        = ['translations'];
65
66
    protected $baseViewPath;
67
    protected static $baseUrlSegment = '/';
68
69 193
    public function __construct(array $attributes = [])
70
    {
71 193
        $this->constructWithSnippets();
72
73 193
        if (!isset($this->baseViewPath)) {
74 193
            $this->baseViewPath = config('thinktomorrow.chief.base-view-paths.pages', 'pages');
75
        }
76
77 193
        parent::__construct($attributes);
78 193
    }
79
80 456
    public static function managedModelKey(): string
81
    {
82 456
        if (isset(static::$managedModelKey)) {
83 456
            return static::$managedModelKey;
0 ignored issues
show
Bug introduced by
The property managedModelKey does not seem to exist on Thinktomorrow\Chief\Pages\Page. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
84
        }
85
86
        throw new \Exception('Missing required static property \'managedModelKey\' on ' . static::class. '.');
87
    }
88
89
    /**
90
     * Parse and render any found snippets in custom
91
     * or translatable attribute values.
92
     *
93
     * @param string $value
94
     * @return mixed|null|string|string[]
95
     */
96 168
    public function getAttribute($value)
97
    {
98 168
        $value = $this->getTranslatableAttribute($value);
99
100 168
        if ($this->shouldParseWithSnippets($value)) {
101 1
            $value = $this->parseWithSnippets($value);
102
        }
103
104 168
        return $value;
105
    }
106
107
    /**
108
     * Page specific modules. We exclude text modules since they are modules in pure
109
     * technical terms and not so much as behavioural elements for the admin.
110
     *
111
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
112
     */
113 2
    public function modules()
114
    {
115 2
        return $this->hasMany(Module::class, 'page_id')->where('morph_key', '<>', 'text');
116
    }
117
118 14
    public function flatReference(): FlatReference
119
    {
120 14
        return new FlatReference(static::class, $this->id);
121
    }
122
123 79
    public function flatReferenceLabel(): string
124
    {
125 79
        if ($this->exists) {
126 62
            $status = ! $this->isPublished() ? ' [' . $this->statusAsPlainLabel().']' : null;
127
128 62
            return $this->title ? $this->title . $status : '';
0 ignored issues
show
Bug introduced by
The property title does not seem to exist on Thinktomorrow\Chief\Pages\Page. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
129
        }
130
131 22
        return '';
132
    }
133
134 1
    public function flatReferenceGroup(): string
135
    {
136 1
        $classKey = get_class($this);
137 1
        $labelSingular = property_exists($this, 'labelSingular') ? $this->labelSingular : str_singular($classKey);
0 ignored issues
show
Bug introduced by
The property labelSingular does not seem to exist on Thinktomorrow\Chief\Pages\Page. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
Deprecated Code introduced by
The function str_singular() has been deprecated: Str::singular() should be used directly instead. Will be removed in Laravel 6.0. ( Ignorable by Annotation )

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

137
        $labelSingular = property_exists($this, 'labelSingular') ? $this->labelSingular : /** @scrutinizer ignore-deprecated */ str_singular($classKey);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
138
139 1
        return $labelSingular;
140
    }
141
142
    public function mediaUrls($type = null): Collection
143
    {
144
        // TODO getallfiles should actually get all files...
145
        // What was the creator of the assetlibrary package thinking. It sure wasn't me... I promise...
146
        $assets = $this->getAllFiles($type, app()->getLocale())->map->getFileUrl();
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

146
        $assets = $this->getAllFiles($type, app()->/** @scrutinizer ignore-call */ getLocale())->map->getFileUrl();
Loading history...
147
148
        if ($assets->first() == null) {
149
            $assets = $this->getAllFiles($type)->map->getFileUrl();
150
        }
151
152
        return $assets;
153
    }
154
155
    public function mediaUrl($type = null): ?string
156
    {
157
        return $this->mediaUrls($type)->first();
158
    }
159
160
    public static function findPublished($id)
161
    {
162
        return static::published()->find($id);
163
    }
164
165 1
    public function scopeSortedByCreated($query)
166
    {
167 1
        $query->orderBy('created_at', 'DESC');
168 1
    }
169
170
    /** @inheritdoc */
171 56
    public function url(string $locale = null): string
172
    {
173 56
        if (!$locale) {
174 52
            $locale = app()->getLocale();
175
        }
176
177
        try {
178 56
            $slug = MemoizedUrlRecord::findByModel($this, $locale)->slug;
179
180 36
            return $this->resolveUrl($locale, [$slug]);
181 22
        } catch (UrlRecordNotFound $e) {
182 22
            return '';
183
        }
184
    }
185
186 62
    public function resolveUrl(string $locale = null, $parameters = null): string
187
    {
188 62
        $routeName = config('thinktomorrow.chief.route.name');
189
190 62
        return $this->resolveRoute($routeName, $parameters, $locale);
0 ignored issues
show
Bug introduced by
It seems like $locale can also be of type string; however, parameter $locale of Thinktomorrow\Chief\Pages\Page::resolveRoute() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

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

190
        return $this->resolveRoute($routeName, $parameters, /** @scrutinizer ignore-type */ $locale);
Loading history...
191
    }
192
193
    /** @inheritdoc */
194 60
    public function previewUrl(string $locale = null): string
195
    {
196 60
        return $this->url($locale).'?preview-mode';
197
    }
198
199
200
    /** @inheritdoc */
201 57
    public static function baseUrlSegment(string $locale = null): string
202
    {
203 57
        if (!isset(static::$baseUrlSegment)) {
204
            return '/';
205
        }
206
207 57
        if (!is_array(static::$baseUrlSegment)) {
0 ignored issues
show
introduced by
The condition is_array(static::baseUrlSegment) is always false.
Loading history...
208 48
            return static::$baseUrlSegment;
209
        }
210
211
        // When an array, we try to locate the expected segment by locale
212 9
        $key = $locale ?? app()->getlocale();
213
214 9
        if (isset(static::$baseUrlSegment[$key])) {
215 9
            return static::$baseUrlSegment[$key];
216
        }
217
218 1
        $fallback_locale = config('app.fallback_locale');
219 1
        if (isset(static::$baseUrlSegment[$fallback_locale])) {
220 1
            return static::$baseUrlSegment[$fallback_locale];
221
        }
222
223
        // Fall back to first entry in case no match is found
224
        return reset(static::$baseUrlSegment);
225
    }
226
227 7
    public function menuLabel(): string
228
    {
229 7
        return $this->title ?? '';
0 ignored issues
show
Bug introduced by
The property title does not seem to exist on Thinktomorrow\Chief\Pages\Page. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
230
    }
231
232
    /**
233
     * We override the publishable trait defaults because Page needs
234
     * to be concerned with the archived state as well.
235
     *
236
     * TODO: IMPROVEMENT SHOULD BE TO MANAGE THE PAGE STATES IN ONE LOCATION. eg state machine
237
     */
238 70
    public function isPublished()
239
    {
240 70
        return (!!$this->published && is_null($this->archived_at));
241
    }
242
243 69
    public function isDraft()
244
    {
245 69
        return (!$this->published && is_null($this->archived_at));
246
    }
247
248 8
    public function publish()
249
    {
250 8
        $this->published = 1;
251 8
        $this->archived_at = null;
252
253 8
        $this->save();
254 8
    }
255
256 4
    public function draft()
257
    {
258 4
        $this->published = 0;
259 4
        $this->archived_at = null;
260
261 4
        $this->save();
262 4
    }
263
264
    public function statusAsLabel()
265
    {
266
        if ($this->isPublished()) {
267
            return '<a href="'.$this->url().'" target="_blank"><em>online</em></a>';
268
        }
269
270
        if ($this->isDraft()) {
271
            return '<a href="'.$this->previewUrl().'" target="_blank" class="text-error"><em>offline</em></a>';
272
        }
273
274
        if ($this->isArchived()) {
275
            return '<span><em>gearchiveerd</em></span>';
276
        }
277
278
        return '-';
279
    }
280
281 61
    public function statusAsPlainLabel()
282
    {
283 61
        if ($this->isPublished()) {
284
            return 'online';
285
        }
286
287 61
        if ($this->isDraft()) {
288 59
            return 'offline';
289
        }
290
291 4
        if ($this->isArchived()) {
292 4
            return 'gearchiveerd';
293
        }
294
295
        return '-';
296
    }
297
}
298