Passed
Push — 0.3 ( 5a9264...9cb195 )
by Ben
115:24 queued 63:34
created

Page::menuUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Thinktomorrow\Chief\Pages;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Database\Eloquent\Model;
7
use Thinktomorrow\Chief\Urls\MemoizedUrlRecord;
8
use Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl;
9
use Thinktomorrow\Chief\Urls\ProvidesUrl\ResolvingRoute;
10
use Thinktomorrow\Chief\Concerns\Viewable\Viewable;
11
use Thinktomorrow\Chief\Concerns\Viewable\ViewableContract;
12
use Thinktomorrow\Chief\Modules\Module;
13
use Thinktomorrow\Chief\Audit\AuditTrait;
14
use Spatie\MediaLibrary\HasMedia\HasMedia;
15
use Thinktomorrow\Chief\Concerns\Featurable;
16
use Thinktomorrow\Chief\Menu\ActsAsMenuItem;
17
use Illuminate\Database\Eloquent\SoftDeletes;
18
use Thinktomorrow\Chief\Relations\ActsAsChild;
19
use Thinktomorrow\Chief\Snippets\WithSnippets;
20
use Thinktomorrow\Chief\Relations\ActsAsParent;
21
use Thinktomorrow\Chief\Relations\ActingAsChild;
22
use Thinktomorrow\AssetLibrary\Traits\AssetTrait;
23
use Thinktomorrow\Chief\Relations\ActingAsParent;
24
use Thinktomorrow\Chief\Concerns\Morphable\Morphable;
25
use Thinktomorrow\Chief\FlatReferences\FlatReference;
26
use Thinktomorrow\Chief\Concerns\Archivable\Archivable;
27
use Dimsav\Translatable\Translatable as BaseTranslatable;
28
use Thinktomorrow\Chief\Concerns\Publishable\Publishable;
29
use Thinktomorrow\Chief\Concerns\Translatable\Translatable;
30
use Thinktomorrow\Chief\Concerns\Morphable\MorphableContract;
31
use Thinktomorrow\Chief\Concerns\Translatable\TranslatableContract;
32
use Thinktomorrow\Chief\Urls\UrlRecordNotFound;
33
34
class Page extends Model implements TranslatableContract, HasMedia, ActsAsParent, ActsAsChild, ActsAsMenuItem, MorphableContract, ViewableContract, ProvidesUrl
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 159 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
35
{
36
    use BaseTranslatable {
0 ignored issues
show
introduced by
The trait Dimsav\Translatable\Translatable requires some properties which are not provided by Thinktomorrow\Chief\Pages\Page: $translations, $useTranslationFallback, $localeKey
Loading history...
37
        getAttribute as getTranslatableAttribute;
38
    }
39
40
    use Morphable,
0 ignored issues
show
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\Conc...anslatable\Translatable requires the property $translations which is not provided by Thinktomorrow\Chief\Pages\Page.
Loading history...
introduced by
The trait Thinktomorrow\Chief\Concerns\Morphable\Morphable requires some properties which are not provided by Thinktomorrow\Chief\Pages\Page: $translations, $morph_key
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...
41
        AssetTrait,
42
        Translatable,
43
        SoftDeletes,
44
        Publishable,
45
        Featurable,
46
        Archivable,
47
        AuditTrait,
48
        ActingAsParent,
49
        ActingAsChild,
50
        WithSnippets,
51
        ResolvingRoute,
52
        Viewable;
53
54
    // Explicitly mention the translation model so on inheritance the child class uses the proper default translation model
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
55
    protected $translationModel      = PageTranslation::class;
56
    protected $translationForeignKey = 'page_id';
57
    protected $translatedAttributes  = [
58
        'title', 'content', 'short', 'seo_title', 'seo_description', 'seo_keywords', 'seo_image'
59
    ];
60
61
    public $table          = "pages";
62
    protected $guarded     = [];
63
    protected $dates       = ['deleted_at', 'archived_at'];
64
    protected $with        = ['translations'];
65
66
    protected $baseViewPath;
67
    protected static $baseUrlSegment = '/';
68
69 177
    public function __construct(array $attributes = [])
70
    {
71 177
        $this->constructWithSnippets();
72
73 177
        if (!isset($this->baseViewPath)) {
74 177
            $this->baseViewPath = config('thinktomorrow.chief.base-view-paths.pages', 'pages');
75
        }
76
77 177
        parent::__construct($attributes);
78 177
    }
79
80
    /**
81
     * Parse and render any found snippets in custom
82
     * or translatable attribute values.
83
     *
84
     * @param string $value
85
     * @return mixed|null|string|string[]
86
     */
87 152
    public function getAttribute($value)
88
    {
89 152
        $value = $this->getTranslatableAttribute($value);
90
91 152
        if ($this->shouldParseWithSnippets($value)) {
92 1
            $value = $this->parseWithSnippets($value);
93
        }
94
95 152
        return $value;
96
    }
97
98
    /**
99
     * Page specific modules. We exclude text modules since they are modules in pure
100
     * technical terms and not so much as behavioural elements for the admin.
101
     *
102
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
103
     */
104 2
    public function modules()
105
    {
106 2
        return $this->hasMany(Module::class, 'page_id')->where('morph_key', '<>', 'text');
107
    }
108
109 9
    public function flatReference(): FlatReference
110
    {
111 9
        return new FlatReference(static::class, $this->id);
112
    }
113
114 67
    public function flatReferenceLabel(): string
115
    {
116 67
        if ($this->exists) {
117 54
            $status = ! $this->isPublished() ? ' [' . $this->statusAsPlainLabel().']' : null;
118
119 54
            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...
120
        }
121
122 17
        return '';
123
    }
124
125 5
    public function flatReferenceGroup(): string
126
    {
127 5
        $classKey = get_class($this);
128 5
        $labelSingular = property_exists($this, 'labelSingular') ? $this->labelSingular : str_singular($classKey);
0 ignored issues
show
Deprecated Code introduced by
The function str_singular() has been deprecated: Str::singular() should be used directly instead. Will be removed in Laravel 5.9. ( Ignorable by Annotation )

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

128
        $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...
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...
129
130 5
        return $labelSingular;
131
    }
132
133
    public function mediaUrls($type = null): Collection
134
    {
135
        return $this->getAllFiles($type)->map->getFileUrl();
136
    }
137
138
    public function mediaUrl($type = null): ?string
139
    {
140
        return $this->mediaUrls($type)->first();
141
    }
142
143
    public static function findPublished($id)
144
    {
145
        return static::published()->find($id);
146
    }
147
148 1
    public function scopeSortedByCreated($query)
149
    {
150 1
        $query->orderBy('created_at', 'DESC');
151 1
    }
152
153
    /** @inheritdoc */
154 47
    public function url(string $locale = null): string
155
    {
156 47
        if (!$locale) {
157 43
            $locale = app()->getLocale();
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

157
            $locale = app()->/** @scrutinizer ignore-call */ getLocale();
Loading history...
158
        }
159
160
        try {
161 47
            $slug = MemoizedUrlRecord::findByModel($this, $locale)->slug;
162
163 31
            return $this->resolveUrl($locale, [$slug]);
164 18
        } catch (UrlRecordNotFound $e) {
165 18
            return '';
166
        }
167
    }
168
169 57
    public function resolveUrl(string $locale = null, $parameters = null): string
170
    {
171 57
        $routeName = config('thinktomorrow.chief.route.name');
172
173 57
        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

173
        return $this->resolveRoute($routeName, $parameters, /** @scrutinizer ignore-type */ $locale);
Loading history...
174
    }
175
176
    /** @inheritdoc */
177 52
    public function previewUrl(string $locale = null, bool $useFallback = true): string
178
    {
179 52
        return $this->url($locale, $useFallback).'?preview-mode';
0 ignored issues
show
Unused Code introduced by
The call to Thinktomorrow\Chief\Pages\Page::url() has too many arguments starting with $useFallback. ( Ignorable by Annotation )

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

179
        return $this->/** @scrutinizer ignore-call */ url($locale, $useFallback).'?preview-mode';

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
180
    }
181
182
183
    /** @inheritdoc */
184 51
    public static function baseUrlSegment(string $locale = null): string
185
    {
186 51
        if (!isset(static::$baseUrlSegment)) {
187
            return '/';
188
        }
189
190 51
        if (!is_array(static::$baseUrlSegment)) {
0 ignored issues
show
introduced by
The condition is_array(static::baseUrlSegment) is always false.
Loading history...
191 43
            return static::$baseUrlSegment;
192
        }
193
194
        // When an array, we try to locate the expected segment by locale
195 8
        $key = $locale ?? app()->getlocale();
196
197 8
        if (isset(static::$baseUrlSegment[$key])) {
198 8
            return static::$baseUrlSegment[$key];
199
        }
200
201
        // Fall back to first entry in case no match is found
202
        return reset(static::$baseUrlSegment);
203
    }
204
205 7
    public function menuLabel(): string
206
    {
207 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...
208
    }
209
210
    /**
211
     * We override the publishable trait defaults because Page needs
212
     * to be concerned with the archived state as well.
213
     *
214
     * TODO: IMPROVEMENT SHOULD BE TO MANAGE THE PAGE STATES IN ONE LOCATION. eg state machine
215
     */
216 63
    public function isPublished()
217
    {
218 63
        return (!!$this->published && is_null($this->archived_at));
219
    }
220
221 62
    public function isDraft()
222
    {
223 62
        return (!$this->published && is_null($this->archived_at));
224
    }
225
226 6
    public function publish()
227
    {
228 6
        $this->published = 1;
229 6
        $this->archived_at = null;
230
231 6
        $this->save();
232 6
    }
233
234 1
    public function draft()
235
    {
236 1
        $this->published = 0;
237 1
        $this->archived_at = null;
238
239 1
        $this->save();
240 1
    }
241
242
    public function statusAsLabel()
243
    {
244
        if ($this->isPublished()) {
245
            return '<a href="'.$this->url().'" target="_blank"><em>online</em></a>';
246
        }
247
248
        if ($this->isDraft()) {
249
            return '<a href="'.$this->previewUrl().'" target="_blank" class="text-error"><em>offline</em></a>';
250
        }
251
252
        if ($this->isArchived()) {
253
            return '<span><em>gearchiveerd</em></span>';
254
        }
255
256
        return '-';
257
    }
258
259 53
    public function statusAsPlainLabel()
260
    {
261 53
        if ($this->isPublished()) {
262
            return 'online';
263
        }
264
265 53
        if ($this->isDraft()) {
266 51
            return 'offline';
267
        }
268
269 3
        if ($this->isArchived()) {
270 3
            return 'gearchiveerd';
271
        }
272
273
        return '-';
274
    }
275
}
276