Passed
Pull Request — master (#324)
by Philippe
54:56 queued 21:29
created

Page::previewUrl()   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 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Thinktomorrow\Chief\Pages;
4
5
use Illuminate\Support\Str;
6
use Illuminate\Support\Collection;
7
use Illuminate\Database\Eloquent\Model;
8
use Thinktomorrow\Chief\Modules\Module;
9
use Thinktomorrow\Chief\Audit\AuditTrait;
10
use Spatie\MediaLibrary\HasMedia\HasMedia;
11
use Thinktomorrow\Chief\Concerns\Featurable;
12
use Thinktomorrow\Chief\Menu\ActsAsMenuItem;
13
use Illuminate\Database\Eloquent\SoftDeletes;
14
use Thinktomorrow\Chief\Relations\ActsAsChild;
15
use Thinktomorrow\Chief\Snippets\WithSnippets;
16
use Thinktomorrow\Chief\Relations\ActsAsParent;
17
use Thinktomorrow\Chief\Urls\MemoizedUrlRecord;
18
use Thinktomorrow\Chief\Urls\UrlRecordNotFound;
19
use Thinktomorrow\Chief\Management\ManagedModel;
20
use Thinktomorrow\Chief\Relations\ActingAsChild;
21
use Thinktomorrow\AssetLibrary\Traits\AssetTrait;
22
use Thinktomorrow\Chief\Relations\ActingAsParent;
23
use Thinktomorrow\Chief\Concerns\Viewable\Viewable;
24
use Thinktomorrow\Chief\Concerns\Morphable\Morphable;
25
use Thinktomorrow\Chief\FlatReferences\FlatReference;
26
use Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl;
27
use Thinktomorrow\Chief\Concerns\Archivable\Archivable;
28
use Thinktomorrow\Chief\Urls\ProvidesUrl\ResolvingRoute;
29
use Thinktomorrow\Chief\Concerns\Publishable\Publishable;
30
use Thinktomorrow\Chief\Concerns\Translatable\Translatable;
31
use Thinktomorrow\Chief\Concerns\Viewable\ViewableContract;
32
use Astrotomic\Translatable\Translatable as BaseTranslatable;
33
use Thinktomorrow\Chief\Concerns\Morphable\MorphableContract;
34
use Thinktomorrow\Chief\Concerns\Translatable\TranslatableContract;
35
36
class Page extends Model implements ManagedModel, TranslatableContract, HasMedia, ActsAsParent, ActsAsChild, ActsAsMenuItem, MorphableContract, ViewableContract, ProvidesUrl
37
{
38
    use BaseTranslatable {
39
        getAttribute as getTranslatableAttribute;
40
    }
41
42
    use Morphable,
0 ignored issues
show
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...
introduced by
The trait Thinktomorrow\AssetLibrary\Traits\AssetTrait requires some properties which are not provided by Thinktomorrow\Chief\Pages\Page: $assets, $pivot, $fallbackPath, $each, $locale, $mediaConversionRegistrations, $fallbackUrl, $media, $type, $collection_name
Loading history...
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...
43
        AssetTrait,
44
        Translatable,
45
        SoftDeletes,
46
        Publishable,
47
        Featurable,
48
        Archivable,
49
        AuditTrait,
50
        ActingAsParent,
51
        ActingAsChild,
52
        WithSnippets,
53
        ResolvingRoute,
54
        Viewable;
55
56
    // Explicitly mention the translation model so on inheritance the child class uses the proper default translation model
57
    protected $translationModel      = PageTranslation::class;
58
    protected $translationForeignKey = 'page_id';
59
    protected $translatedAttributes  = [
60
        'title', 'content', 'short', 'seo_title', 'seo_description', 'seo_keywords', 'seo_image'
61
    ];
62
63
    public $table          = "pages";
64
    protected $guarded     = [];
65
    protected $with        = ['translations'];
66
67
    protected $baseViewPath;
68
    protected static $baseUrlSegment = '/';
69
70 203
    public function __construct(array $attributes = [])
71
    {
72 203
        $this->constructWithSnippets();
73
74 203
        if (!isset($this->baseViewPath)) {
75 203
            $this->baseViewPath = config('thinktomorrow.chief.base-view-paths.pages', 'pages');
76
        }
77
78 203
        parent::__construct($attributes);
79 203
    }
80
81 468
    public static function managedModelKey(): string
82
    {
83 468
        if (isset(static::$managedModelKey)) {
84 468
            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...
85
        }
86
87
        throw new \Exception('Missing required static property \'managedModelKey\' on ' . static::class. '.');
88
    }
89
90
    /**
91
     * Parse and render any found snippets in custom
92
     * or translatable attribute values.
93
     *
94
     * @param string $value
95
     * @return mixed|null|string|string[]
96
     */
97 177
    public function getAttribute($value)
98
    {
99 177
        $value = $this->getTranslatableAttribute($value);
100
101 177
        if ($this->shouldParseWithSnippets($value)) {
102 1
            $value = $this->parseWithSnippets($value);
103
        }
104
105 177
        return $value;
106
    }
107
108
    /**
109
     * Page specific modules. We exclude text modules since they are modules in pure
110
     * technical terms and not so much as behavioural elements for the admin.
111
     *
112
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
113
     */
114 1
    public function modules()
115
    {
116 1
        return $this->hasMany(Module::class, 'page_id')->where('morph_key', '<>', 'text');
117
    }
118
119 14
    public function flatReference(): FlatReference
120
    {
121 14
        return new FlatReference(static::class, $this->id);
122
    }
123
124 82
    public function flatReferenceLabel(): string
125
    {
126 82
        if ($this->exists) {
127 64
            $status = ! $this->isPublished() ? ' [' . $this->statusAsPlainLabel().']' : null;
128
129 64
            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...
130
        }
131
132 23
        return '';
133
    }
134
135 2
    public function flatReferenceGroup(): string
136
    {
137 2
        $classKey = get_class($this);
138 2
        if (property_exists($this, 'labelSingular')) {
139 1
            $labelSingular =  $this->labelSingular;
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...
140
        } else {
141 1
            $labelSingular = Str::singular($classKey);
142
        }
143
144 2
        return $labelSingular;
145
    }
146
147
    public function mediaUrls($type = null): Collection
148
    {
149
        // TODO getallfiles should actually get all files...
150
        // What was the creator of the assetlibrary package thinking. It sure wasn't me... I promise...
151
        $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

151
        $assets = $this->getAllFiles($type, app()->/** @scrutinizer ignore-call */ getLocale())->map->getFileUrl();
Loading history...
152
153
        if ($assets->first() == null) {
154
            $assets = $this->getAllFiles($type)->map->getFileUrl();
155
        }
156
157
        return $assets;
158
    }
159
160
    public function mediaUrl($type = null): ?string
161
    {
162
        return $this->mediaUrls($type)->first();
163
    }
164
165
    public static function findPublished($id)
166
    {
167
        return static::published()->find($id);
168
    }
169
170 1
    public function scopeSortedByCreated($query)
171
    {
172 1
        $query->orderBy('created_at', 'DESC');
173 1
    }
174
175
    /** @inheritdoc */
176 58
    public function url(string $locale = null): string
177
    {
178 58
        if (!$locale) {
179 54
            $locale = app()->getLocale();
180
        }
181
182
        try {
183 58
            $slug = MemoizedUrlRecord::findByModel($this, $locale)->slug;
184
185 36
            return $this->resolveUrl($locale, [$slug]);
186 24
        } catch (UrlRecordNotFound $e) {
187 24
            return '';
188
        }
189
    }
190
191 62
    public function resolveUrl(string $locale = null, $parameters = null): string
192
    {
193 62
        $routeName = config('thinktomorrow.chief.route.name');
194
195 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

195
        return $this->resolveRoute($routeName, $parameters, /** @scrutinizer ignore-type */ $locale);
Loading history...
196
    }
197
198
    /** @inheritdoc */
199 62
    public function previewUrl(string $locale = null): string
200
    {
201 62
        return $this->url($locale).'?preview-mode';
202
    }
203
204
205
    /** @inheritdoc */
206 57
    public static function baseUrlSegment(string $locale = null): string
207
    {
208 57
        if (!isset(static::$baseUrlSegment)) {
209
            return '/';
210
        }
211
212 57
        if (!is_array(static::$baseUrlSegment)) {
0 ignored issues
show
introduced by
The condition is_array(static::baseUrlSegment) is always false.
Loading history...
213 48
            return static::$baseUrlSegment;
214
        }
215
216
        // When an array, we try to locate the expected segment by locale
217 9
        $key = $locale ?? app()->getlocale();
218
219 9
        if (isset(static::$baseUrlSegment[$key])) {
220 9
            return static::$baseUrlSegment[$key];
221
        }
222
223 1
        $fallback_locale = config('app.fallback_locale');
224 1
        if (isset(static::$baseUrlSegment[$fallback_locale])) {
225 1
            return static::$baseUrlSegment[$fallback_locale];
226
        }
227
228
        // Fall back to first entry in case no match is found
229
        return reset(static::$baseUrlSegment);
230
    }
231
232 7
    public function menuLabel(): string
233
    {
234 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...
235
    }
236
237
    /**
238
     * We override the publishable trait defaults because Page needs
239
     * to be concerned with the archived state as well.
240
     *
241
     * TODO: IMPROVEMENT SHOULD BE TO MANAGE THE PAGE STATES IN ONE LOCATION. eg state machine
242
     */
243 72
    public function isPublished()
244
    {
245 72
        return (!!$this->published && is_null($this->archived_at));
246
    }
247
248 71
    public function isDraft()
249
    {
250 71
        return (!$this->published && is_null($this->archived_at));
251
    }
252
253 8
    public function publish()
254
    {
255 8
        $this->published = 1;
256 8
        $this->archived_at = null;
257
258 8
        $this->save();
259 8
    }
260
261 4
    public function draft()
262
    {
263 4
        $this->published = 0;
264 4
        $this->archived_at = null;
265
266 4
        $this->save();
267 4
    }
268
269
    public function statusAsLabel()
270
    {
271
        if ($this->isPublished()) {
272
            return '<a href="'.$this->url().'" target="_blank"><em>online</em></a>';
273
        }
274
275
        if ($this->isDraft()) {
276
            return '<a href="'.$this->previewUrl().'" target="_blank" class="text-error"><em>offline</em></a>';
277
        }
278
279
        if ($this->isArchived()) {
280
            return '<span><em>gearchiveerd</em></span>';
281
        }
282
283
        return '-';
284
    }
285
286 63
    public function statusAsPlainLabel()
287
    {
288 63
        if ($this->isPublished()) {
289
            return 'online';
290
        }
291
292 63
        if ($this->isDraft()) {
293 61
            return 'offline';
294
        }
295
296 4
        if ($this->isArchived()) {
297 4
            return 'gearchiveerd';
298
        }
299
300
        return '-';
301
    }
302
}
303