Passed
Push — dependabot/npm_and_yarn/string... ( b56eb5...bc569b )
by
unknown
45:46 queued 33s
created

PageManager   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Test Coverage

Coverage 96.72%

Importance

Changes 0
Metric Value
wmc 32
eloc 110
dl 0
loc 238
ccs 118
cts 122
cp 0.9672
rs 9.84
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A delete() 0 7 2
A filters() 0 4 1
A details() 0 11 2
A enforceUniqueSlug() 0 8 1
A saveFields() 0 8 2
A pageBuilderField() 0 7 2
A storeRequest() 0 14 3
A can() 0 9 2
A authorize() 0 14 5
A updateRequest() 0 19 3
A addDefaultShortDescription() 0 7 2
A fields() 0 36 2
A afterUpdate() 0 5 1
A fieldArrangement() 0 13 2
A afterStore() 0 5 1
1
<?php
2
3
namespace Thinktomorrow\Chief\Pages;
4
5
use Illuminate\Http\Request;
6
use Thinktomorrow\Chief\Audit\Audit;
7
use Thinktomorrow\Chief\Fields\Fields;
8
use Thinktomorrow\Chief\Filters\Filters;
9
use Thinktomorrow\Chief\Fields\FieldsTab;
10
use Thinktomorrow\Chief\Management\Manager;
11
use Thinktomorrow\Chief\Fields\Types\TextField;
12
use Thinktomorrow\Chief\Fields\FieldArrangement;
13
use Thinktomorrow\Chief\Fields\Types\InputField;
14
use Thinktomorrow\Chief\Fields\Types\MediaField;
15
use Thinktomorrow\Chief\Management\Registration;
16
use Thinktomorrow\Chief\Fields\RemainingFieldsTab;
17
use Thinktomorrow\Chief\Management\AbstractManager;
18
use Thinktomorrow\Chief\Management\Details\Details;
19
use Thinktomorrow\Chief\Pages\Application\DeletePage;
20
use Thinktomorrow\Chief\Concerns\Sluggable\UniqueSlug;
21
use Thinktomorrow\Chief\Management\Exceptions\DeleteAborted;
22
use Thinktomorrow\Chief\Management\Assistants\ArchiveAssistant;
23
use Thinktomorrow\Chief\Management\Assistants\PublishAssistant;
24
use Thinktomorrow\Chief\Management\Exceptions\NotAllowedManagerRoute;
25
26
class PageManager extends AbstractManager implements Manager
27
{
28
    /** @var \Thinktomorrow\Chief\Concerns\Sluggable\UniqueSlug */
29
    private $uniqueSlug;
30
31
    /** @var PageBuilderField */
0 ignored issues
show
Bug introduced by
The type Thinktomorrow\Chief\Pages\PageBuilderField was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
32
    private $pageBuilderField;
33
34
    protected $assistants = [
35
        'archive' => ArchiveAssistant::class,
36
        'publish' => PublishAssistant::class,
37
    ];
38
39 73
    public function __construct(Registration $registration)
40
    {
41 73
        parent::__construct($registration);
42
43
        $this->uniqueSlug = UniqueSlug::make(new PageTranslation)->slugResolver(function ($value) {
44 43
            return str_slug_slashed($value);
45 73
        });
46 73
    }
47
48 63
    public function can($verb): bool
49
    {
50
        try {
51 63
            $this->authorize($verb);
52 3
        } catch (NotAllowedManagerRoute $e) {
53 3
            return false;
54
        }
55
56 60
        return parent::can($verb);
57
    }
58
59
    /**
60
     * @param $verb
61
     * @throws NotAllowedManagerRoute
62
     */
63 63
    private function authorize($verb)
64
    {
65 63
        $permission = 'update-page';
66
67 63
        if (in_array($verb, ['index','show'])) {
68 17
            $permission = 'view-page';
69 50
        } elseif (in_array($verb, ['create','store'])) {
70 14
            $permission = 'create-page';
71 40
        } elseif (in_array($verb, ['delete'])) {
72 4
            $permission = 'delete-page';
73
        }
74
75 63
        if (! auth()->guard('chief')->user()->hasPermissionTo($permission)) {
0 ignored issues
show
Bug introduced by
The method hasPermissionTo() does not exist on Illuminate\Contracts\Auth\Authenticatable. It seems like you code against a sub-type of Illuminate\Contracts\Auth\Authenticatable such as Illuminate\Foundation\Auth\User. ( Ignorable by Annotation )

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

75
        if (! auth()->guard('chief')->user()->/** @scrutinizer ignore-call */ hasPermissionTo($permission)) {
Loading history...
76 3
            throw NotAllowedManagerRoute::notAllowedPermission($permission, $this);
77
        }
78 60
    }
79
80
    /**
81
     * The set of fields that should be manageable for a certain model.
82
     *
83
     * Additionally, you should:
84
     * 1. Make sure to setup the proper migrations and
85
     * 2. For a translatable field you should add this field to the $translatedAttributes property of the model as well.
86
     *
87
     * @return Fields
88
     */
89 40
    public function fields(): Fields
90
    {
91 40
        return new Fields([
92 40
            $this->pageBuilderField(),
93 40
            InputField::make('title')->translatable($this->model->availableLocales())
0 ignored issues
show
Bug introduced by
The method availableLocales() does not exist on Illuminate\Contracts\Foundation\Application. ( Ignorable by Annotation )

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

93
            InputField::make('title')->translatable($this->model->/** @scrutinizer ignore-call */ availableLocales())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
94 40
                                     ->validation('required-fallback-locale|max:200', [], [
95 40
                                         'trans.'.config('app.fallback_locale', 'nl').'.title' => 'title',
96
                                     ])
97 40
                                     ->label('De titel van je '.$this->model->labelSingular ?? 'pagina')
0 ignored issues
show
Bug introduced by
The method label() does not exist on Thinktomorrow\Chief\Fields\Types\InputField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

97
                                     ->/** @scrutinizer ignore-call */ label('De titel van je '.$this->model->labelSingular ?? 'pagina')
Loading history...
98 40
                                     ->description('Dit is de titel die zal worden getoond in de overzichten en modules.<br> Deze zal gebruikt worden als interne titel en slug van de nieuwe pagina.'),
0 ignored issues
show
Bug introduced by
The method description() does not exist on Thinktomorrow\Chief\Fields\Types\InputField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

98
                                     ->/** @scrutinizer ignore-call */ description('Dit is de titel die zal worden getoond in de overzichten en modules.<br> Deze zal gebruikt worden als interne titel en slug van de nieuwe pagina.'),
Loading history...
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 200 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...
99 40
            InputField::make('slug')
100 40
                ->translatable($this->model->availableLocales())
101 40
                ->validation($this->model->id
102 29
                    ? 'required-fallback-locale|unique:page_translations,slug,' . $this->model->id . ',page_id'
103 40
                    : 'required-fallback-locale|unique:page_translations,slug', [], [
104 40
                    'trans.'.config('app.fallback_locale', 'nl').'.slug' => 'slug'
105
                ])
106 40
                ->label('Link')
107 40
                ->description('De unieke url verwijzing naar deze pagina.')
108
                ->prepend(collect($this->model->availableLocales())->mapWithKeys(function ($locale) {
0 ignored issues
show
Bug introduced by
The method prepend() does not exist on Thinktomorrow\Chief\Fields\Types\InputField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

108
                ->/** @scrutinizer ignore-call */ prepend(collect($this->model->availableLocales())->mapWithKeys(function ($locale) {
Loading history...
109 40
                    return [$locale => url($this->model->baseUrlSegment($locale)).'/'];
0 ignored issues
show
Bug introduced by
Are you sure url($this->model->baseUrlSegment($locale)) of type Illuminate\Contracts\Routing\UrlGenerator|string can be used in concatenation? ( Ignorable by Annotation )

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

109
                    return [$locale => /** @scrutinizer ignore-type */ url($this->model->baseUrlSegment($locale)).'/'];
Loading history...
Bug introduced by
The method baseUrlSegment() does not exist on Illuminate\Contracts\Foundation\Application. ( Ignorable by Annotation )

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

109
                    return [$locale => url($this->model->/** @scrutinizer ignore-call */ baseUrlSegment($locale)).'/'];

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
110 40
                })->all()),
111 40
            InputField::make('seo_title')
112 40
                ->translatable($this->model->availableLocales())
113 40
                ->label('Zoekmachine titel'),
114 40
            TextField::make('seo_description')
115 40
                ->translatable($this->model->availableLocales())
116 40
                ->label('Zoekmachine omschrijving')
0 ignored issues
show
Bug introduced by
The method label() does not exist on Thinktomorrow\Chief\Fields\Types\TextField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

116
                ->/** @scrutinizer ignore-call */ label('Zoekmachine omschrijving')
Loading history...
117 40
                ->description('omschrijving van de pagina zoals in search engines (o.a. google) wordt weergegeven.'),
0 ignored issues
show
Bug introduced by
The method description() does not exist on Thinktomorrow\Chief\Fields\Types\TextField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

117
                ->/** @scrutinizer ignore-call */ description('omschrijving van de pagina zoals in search engines (o.a. google) wordt weergegeven.'),
Loading history...
118 40
            InputField::make('seo_keywords')
119 40
                ->translatable($this->model->availableLocales())
120 40
                ->label('Zoekmachine sleutelwoorden')
121 40
                ->description('sleutelwoorden van de pagina waarop in search engines (o.a google) gezocht kan worden.'),
122 40
            MediaField::make('seo_image')
123 40
                ->label('Zoekmachine foto')
0 ignored issues
show
Bug introduced by
The method label() does not exist on Thinktomorrow\Chief\Fields\Types\MediaField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

123
                ->/** @scrutinizer ignore-call */ label('Zoekmachine foto')
Loading history...
124 40
                ->description('foto die bij het delen van deze pagina getoont word. (afmeting: 1200x627px)')
0 ignored issues
show
Bug introduced by
The method description() does not exist on Thinktomorrow\Chief\Fields\Types\MediaField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

124
                ->/** @scrutinizer ignore-call */ description('foto die bij het delen van deze pagina getoont word. (afmeting: 1200x627px)')
Loading history...
125
        ]);
126
    }
127
128
    public static function filters(): Filters
129
    {
130
        return new Filters([
131
            PublishedFilter::class
132
        ]);
133
    }
134
135 40
    private function pageBuilderField()
136
    {
137 40
        if ($this->pageBuilderField) {
138 36
            return $this->pageBuilderField;
139
        }
140
141 40
        return $this->pageBuilderField = $this->createPagebuilderField();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createPagebuilderField() of type Thinktomorrow\Chief\Fields\Types\PagebuilderField is incompatible with the declared type Thinktomorrow\Chief\Pages\PageBuilderField of property $pageBuilderField.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
142
    }
143
144 2
    public function fieldArrangement($key = null): FieldArrangement
145
    {
146 2
        if ($key == 'create') {
147
            return new FieldArrangement($this->fields()->filterBy(function ($field) {
148 1
                return $field->key == 'title';
149 1
            }));
150
        }
151
152 1
        return new FieldArrangement($this->fields(), [
153 1
            new FieldsTab('pagina', ['sections']),
154 1
            new RemainingFieldsTab('inhoud'),
155 1
            new FieldsTab('eigen modules', [], 'chief::back.pages._partials.modules'),
156 1
            new FieldsTab('seo', ['seo_title', 'seo_description', 'seo_keywords', 'seo_image']),
157
        ]);
158
    }
159
160 64
    public function details(): Details
161
    {
162
        // For existing model
163 64
        if ($this->model->id) {
164 50
            return parent::details()
165 50
                ->set('title', $this->model->title)
166 50
                ->set('intro', 'laatst aangepast op ' . $this->model->updated_at->format('d/m/Y H:i'))
167 50
                ->set('context', '<span class="inline-s">' . $this->assistant('publish')->publicationStatusAsLabel() . '</span>');
0 ignored issues
show
Bug introduced by
The method publicationStatusAsLabel() does not exist on Thinktomorrow\Chief\Mana...nt\Assistants\Assistant. It seems like you code against a sub-type of Thinktomorrow\Chief\Mana...nt\Assistants\Assistant such as Thinktomorrow\Chief\Mana...stants\PublishAssistant. ( Ignorable by Annotation )

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

167
                ->set('context', '<span class="inline-s">' . $this->assistant('publish')->/** @scrutinizer ignore-call */ publicationStatusAsLabel() . '</span>');
Loading history...
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 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...
168
        }
169
170 17
        return parent::details();
171
    }
172
173 42
    public function saveFields(): Manager
174
    {
175
        // Store the morph_key upon creation
176 42
        if (! $this->model->morph_key) {
177 11
            $this->model->morph_key = $this->model->morphKey();
0 ignored issues
show
Bug introduced by
The method morphKey() does not exist on Illuminate\Contracts\Foundation\Application. ( Ignorable by Annotation )

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

177
            /** @scrutinizer ignore-call */ 
178
            $this->model->morph_key = $this->model->morphKey();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
178
        }
179
180 42
        return parent::saveFields();
181
    }
182
183 4
    public function delete()
184
    {
185 4
        if (request()->get('deleteconfirmation') !== 'DELETE') {
186 1
            throw new DeleteAborted();
187
        }
188
189 3
        app(DeletePage::class)->handle($this->model->id);
190 3
    }
191
192 13
    public function storeRequest(Request $request): Request
193
    {
194 13
        $trans = [];
195 13
        foreach ($request->get('trans', []) as $locale => $translation) {
196 12
            if (is_array_empty($translation)) {
197
                continue;
198
            }
199
200 12
            $translation = $this->enforceUniqueSlug($request->get('trans'), $locale, $this->model);
0 ignored issues
show
Bug introduced by
It seems like $this->model can also be of type Illuminate\Contracts\Foundation\Application; however, parameter $page of Thinktomorrow\Chief\Page...er::enforceUniqueSlug() does only seem to accept Thinktomorrow\Chief\Pages\Page, 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

200
            $translation = $this->enforceUniqueSlug($request->get('trans'), $locale, /** @scrutinizer ignore-type */ $this->model);
Loading history...
Bug introduced by
It seems like $request->get('trans') can also be of type null; however, parameter $translations of Thinktomorrow\Chief\Page...er::enforceUniqueSlug() does only seem to accept array, 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

200
            $translation = $this->enforceUniqueSlug(/** @scrutinizer ignore-type */ $request->get('trans'), $locale, $this->model);
Loading history...
201 12
            $trans[$locale] = $this->addDefaultShortDescription($translation);
202
        }
203
204
        // Merge with request...
205 13
        return $request->merge(['trans' => $trans]);
206
    }
207
208 35
    public function updateRequest(Request $request): Request
209
    {
210 35
        $trans = [];
211 35
        foreach ($request->get('trans', []) as $locale => $translation) {
212 34
            if (is_array_empty($translation)) {
213
214
                // Nullify all values
215
                $trans[$locale] = array_map(function ($value) {
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed. ( Ignorable by Annotation )

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

215
                $trans[$locale] = array_map(function (/** @scrutinizer ignore-unused */ $value) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
216 1
                    return null;
217 1
                }, $translation);
218 1
                continue;
219
            }
220
221 34
            $translation = $this->enforceUniqueSlug($request->get('trans'), $locale, $this->model);
0 ignored issues
show
Bug introduced by
It seems like $request->get('trans') can also be of type null; however, parameter $translations of Thinktomorrow\Chief\Page...er::enforceUniqueSlug() does only seem to accept array, 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

221
            $translation = $this->enforceUniqueSlug(/** @scrutinizer ignore-type */ $request->get('trans'), $locale, $this->model);
Loading history...
Bug introduced by
It seems like $this->model can also be of type Illuminate\Contracts\Foundation\Application; however, parameter $page of Thinktomorrow\Chief\Page...er::enforceUniqueSlug() does only seem to accept Thinktomorrow\Chief\Pages\Page, 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

221
            $translation = $this->enforceUniqueSlug($request->get('trans'), $locale, /** @scrutinizer ignore-type */ $this->model);
Loading history...
222 34
            $trans[$locale] = $this->addDefaultShortDescription($translation);
223
        }
224
225
        // Merge with request...
226 35
        return $request->merge(['trans' => $trans]);
227
    }
228
229 11
    public function afterStore($request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

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

229
    public function afterStore(/** @scrutinizer ignore-unused */ $request)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
230
    {
231 11
        Audit::activity()
232 11
            ->performedOn($this->model)
0 ignored issues
show
Bug introduced by
It seems like $this->model can also be of type Illuminate\Contracts\Foundation\Application; however, parameter $model of Spatie\Activitylog\ActivityLogger::performedOn() does only seem to accept Illuminate\Database\Eloquent\Model, 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

232
            ->performedOn(/** @scrutinizer ignore-type */ $this->model)
Loading history...
233 11
            ->log('created');
234 11
    }
235
236 34
    public function afterUpdate($request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

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

236
    public function afterUpdate(/** @scrutinizer ignore-unused */ $request)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
237
    {
238 34
        Audit::activity()
239 34
            ->performedOn($this->model)
0 ignored issues
show
Bug introduced by
It seems like $this->model can also be of type Illuminate\Contracts\Foundation\Application; however, parameter $model of Spatie\Activitylog\ActivityLogger::performedOn() does only seem to accept Illuminate\Database\Eloquent\Model, 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

239
            ->performedOn(/** @scrutinizer ignore-type */ $this->model)
Loading history...
240 34
            ->log('edited');
241 34
    }
242
243 43
    private function enforceUniqueSlug(array $translations, string $locale, Page $page): array
244
    {
245 43
        $translation = $translations[$locale];
246
247 43
        $translation['slug']    = $translation['slug'] ?? $translation['title'];
248 43
        $translation['slug']    = $this->uniqueSlug->get($translation['slug'], $page->getTranslation($locale));
0 ignored issues
show
Bug introduced by
It seems like $page->getTranslation($locale) can also be of type Illuminate\Database\Eloquent\Model; however, parameter $entity of Thinktomorrow\Chief\Conc...gable\UniqueSlug::get() does only seem to accept Thinktomorrow\Chief\Conc...\SluggableContract|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

248
        $translation['slug']    = $this->uniqueSlug->get($translation['slug'], /** @scrutinizer ignore-type */ $page->getTranslation($locale));
Loading history...
249
250 43
        return $translation;
251
    }
252
253
    /**
254
     * @param array $translation
255
     * @return array
256
     */
257 43
    private function addDefaultShortDescription(array $translation): array
258
    {
259 43
        if (isset($translation['content'])) {
260 1
            $translation['short'] = $translation['short'] ?? teaser($translation['content'], 100);
261
        }
262
263 43
        return $translation;
264
    }
265
}
266