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

PageManager   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 225
Duplicated Lines 0 %

Test Coverage

Coverage 99.11%

Importance

Changes 10
Bugs 3 Features 2
Metric Value
wmc 34
eloc 100
c 10
b 3
f 2
dl 0
loc 225
ccs 111
cts 112
cp 0.9911
rs 9.68

15 Methods

Rating   Name   Duplication   Size   Complexity  
A delete() 0 7 2
A details() 0 11 2
A afterUpdate() 0 5 1
A afterStore() 0 5 1
A __construct() 0 3 1
A filters() 0 4 1
A saveFields() 0 8 3
A pageBuilderField() 0 7 2
A can() 0 9 2
A updateRequest() 0 18 3
A authorize() 0 14 5
A addDefaultShortDescription() 0 7 2
A fields() 0 26 1
A fieldArrangement() 0 22 3
A storeRequest() 0 20 5
1
<?php
2
3
namespace Thinktomorrow\Chief\Pages;
4
5
use Illuminate\Support\Str;
6
use Illuminate\Http\Request;
7
use Thinktomorrow\Chief\Audit\Audit;
8
use Thinktomorrow\Chief\Fields\Fields;
9
use Thinktomorrow\Chief\Modules\Module;
10
use Thinktomorrow\Chief\Filters\Filters;
11
use Thinktomorrow\Chief\Fields\FieldsTab;
12
use Thinktomorrow\Chief\Management\Manager;
13
use Thinktomorrow\Chief\Urls\UrlSlugFields;
14
use Thinktomorrow\Chief\Fields\Types\TextField;
15
use Thinktomorrow\Chief\Fields\FieldArrangement;
16
use Thinktomorrow\Chief\Fields\Types\InputField;
17
use Thinktomorrow\Chief\Fields\Types\MediaField;
18
use Thinktomorrow\Chief\Management\Registration;
19
use Thinktomorrow\Chief\Fields\RemainingFieldsTab;
20
use Thinktomorrow\Chief\Management\AbstractManager;
21
use Thinktomorrow\Chief\Management\Details\Details;
22
use Thinktomorrow\Chief\Pages\Application\DeletePage;
23
use Thinktomorrow\Chief\Management\Assistants\UrlAssistant;
24
use Thinktomorrow\Chief\Management\Exceptions\DeleteAborted;
25
use Thinktomorrow\Chief\Concerns\Morphable\MorphableContract;
26
use Thinktomorrow\Chief\Management\Assistants\ArchiveAssistant;
27
use Thinktomorrow\Chief\Management\Assistants\PublishAssistant;
28
use Thinktomorrow\Chief\Management\Exceptions\NotAllowedManagerRoute;
29
30
class PageManager extends AbstractManager implements Manager
31
{
32
    /** @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...
33
    private $pageBuilderField;
34
35
    protected $assistants = [
36
        'url'     => UrlAssistant::class,
37
        'archive' => ArchiveAssistant::class,
38
        'publish' => PublishAssistant::class,
39
    ];
40
41 87
    public function __construct(Registration $registration)
42
    {
43 87
        parent::__construct($registration);
44 87
    }
45
46 79
    public function can($verb): bool
47
    {
48
        try {
49 79
            $this->authorize($verb);
50 1
        } catch (NotAllowedManagerRoute $e) {
51 1
            return false;
52
        }
53
54 78
        return parent::can($verb);
55
    }
56
57
    /**
58
     * @param $verb
59
     * @throws NotAllowedManagerRoute
60
     */
61 79
    private function authorize($verb)
62
    {
63 79
        $permission = 'update-page';
64
65 79
        if (in_array($verb, ['index','show'])) {
66 23
            $permission = 'view-page';
67 61
        } elseif (in_array($verb, ['create','store'])) {
68 19
            $permission = 'create-page';
69 47
        } elseif (in_array($verb, ['delete'])) {
70 6
            $permission = 'delete-page';
71
        }
72
73 79
        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

73
        if (! auth()->guard('chief')->user()->/** @scrutinizer ignore-call */ hasPermissionTo($permission)) {
Loading history...
74 1
            throw NotAllowedManagerRoute::notAllowedPermission($permission, $this);
75
        }
76 78
    }
77
78
    /**
79
     * The set of fields that should be manageable for a certain model.
80
     *
81
     * Additionally, you should:
82
     * 1. Make sure to setup the proper migrations and
83
     * 2. For a translatable field you should add this field to the $translatedAttributes property of the model as well.
84
     *
85
     * @return Fields
86
     */
87 47
    public function fields(): Fields
88
    {
89 47
        return parent::fields()->add(
90 47
            $this->pageBuilderField(),
91 47
            InputField::make('title')->translatable($this->model->availableLocales())
0 ignored issues
show
Bug introduced by
It seems like Thinktomorrow\Chief\Fiel...erzichten en modules.') can also be of type null; however, parameter $fields of Thinktomorrow\Chief\Fields\Fields::add() does only seem to accept Thinktomorrow\Chief\Fields\Types\Field, 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

91
            /** @scrutinizer ignore-type */ InputField::make('title')->translatable($this->model->availableLocales())
Loading history...
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

91
            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...
92 47
                                     ->validation('required-fallback-locale|max:200', [], [
93 47
                                         'trans.'.config('app.fallback_locale', 'nl').'.title' => 'title',
94
                                     ])
95 47
                                     ->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

95
                                     ->/** @scrutinizer ignore-call */ label('De titel van je '.$this->model->labelSingular ?? 'pagina')
Loading history...
96 47
                                     ->description('Dit is de titel die zal worden getoond in de overzichten en modules.'),
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

96
                                     ->/** @scrutinizer ignore-call */ description('Dit is de titel die zal worden getoond in de overzichten en modules.'),
Loading history...
97 47
            InputField::make('seo_title')
98 47
                ->translatable($this->model->availableLocales())
99 47
                ->label('Zoekmachine titel'),
100 47
            TextField::make('seo_description')
101 47
                ->translatable($this->model->availableLocales())
102 47
                ->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

102
                ->/** @scrutinizer ignore-call */ label('Zoekmachine omschrijving')
Loading history...
103 47
                ->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

103
                ->/** @scrutinizer ignore-call */ description('omschrijving van de pagina zoals in search engines (o.a. google) wordt weergegeven.'),
Loading history...
104 47
            InputField::make('seo_keywords')
105 47
                ->validation('max:250')
106 47
                ->translatable($this->model->availableLocales())
107 47
                ->label('Zoekmachine sleutelwoorden')
108 47
                ->description('sleutelwoorden van de pagina waarop in search engines (o.a google) gezocht kan worden.'),
109 47
            MediaField::make('seo_image')
110 47
                ->translatable($this->model->availableLocales())
111 47
                ->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

111
                ->/** @scrutinizer ignore-call */ label('Zoekmachine foto')
Loading history...
112 47
                ->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

112
                ->/** @scrutinizer ignore-call */ description('foto die bij het delen van deze pagina getoont word. (afmeting: 1200x627px)')
Loading history...
113
        );
114
    }
115
116 1
    public static function filters(): Filters
117
    {
118 1
        return new Filters([
119 1
            PublishedFilter::class
120
        ]);
121
    }
122
123 47
    private function pageBuilderField()
124
    {
125 47
        if ($this->pageBuilderField) {
126 40
            return $this->pageBuilderField;
127
        }
128
129 47
        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...
130
    }
131
132 2
    public function fieldArrangement($key = null): FieldArrangement
133
    {
134 2
        if ($key == 'create') {
135
            return new FieldArrangement($this->fieldsWithAssistantFields()->filterBy(function ($field) {
136 1
                return in_array($field->key, ['title']);
137 1
            }));
138
        }
139
140
        $tabs = [
141 1
            new FieldsTab('pagina', ['sections']),
142 1
            new RemainingFieldsTab('algemeen'),
143 1
            new FieldsTab('url', ['url-slugs'], 'chief::back.pages._partials.url', [
144 1
                'redirects' =>  UrlSlugFields::redirectsFromModel($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 Thinktomorrow\Chief\Urls...s::redirectsFromModel() does only seem to accept Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl, 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

144
                'redirects' =>  UrlSlugFields::redirectsFromModel(/** @scrutinizer ignore-type */ $this->model),
Loading history...
145
            ]),
146 1
            new FieldsTab('seo', ['seo_title', 'seo_description', 'seo_keywords', 'seo_image']),
147
        ];
148
149 1
        if (! Module::available()->values()->isEmpty()) {
150
            array_splice($tabs, 1, 0, [new FieldsTab('modules', [], 'chief::back.pages._partials.modules')]);
151
        }
152
153 1
        return new FieldArrangement($this->fieldsWithAssistantFields(), $tabs);
154
    }
155
156 81
    public function details(): Details
157
    {
158
        // For existing model
159 81
        if ($this->model->id) {
160 62
            return parent::details()
161 62
                ->set('title', ucfirst($this->model->title))
162 62
                ->set('intro', 'Aangepast ' . $this->model->updated_at->format('d/m/Y H:i'))
163 62
                ->set('context', '<span class="inline-xs stack-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

163
                ->set('context', '<span class="inline-xs stack-s">' . $this->assistant('publish')->/** @scrutinizer ignore-call */ publicationStatusAsLabel() . '</span>');
Loading history...
164
        }
165
166 23
        return parent::details();
167
    }
168
169 49
    public function saveFields(Request $request)
170
    {
171
        // Store the morph_key upon creation
172 49
        if ($this->model instanceof MorphableContract && ! $this->model->morph_key) {
0 ignored issues
show
Bug introduced by
Accessing morph_key on the interface Thinktomorrow\Chief\Conc...hable\MorphableContract suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
Bug introduced by
Accessing morph_key on the interface Illuminate\Contracts\Foundation\Application suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
173 15
            $this->model->morph_key = $this->model->morphKey();
174
        }
175
176 49
        parent::saveFields($request);
177 49
    }
178
179 6
    public function delete()
180
    {
181 6
        if (request()->get('deleteconfirmation') !== 'DELETE') {
182 1
            throw new DeleteAborted();
183
        }
184
185 5
        app(DeletePage::class)->handle($this->model->id);
186 5
    }
187
188 17
    public function storeRequest(Request $request): Request
189
    {
190 17
        $trans = [];
191 17
        $urls = $request->get('url-slugs', []);
192
193 17
        foreach ($request->get('trans', []) as $locale => $translation) {
194 16
            if (is_array_empty($translation)) {
195 1
                continue;
196
            }
197
198 16
            $trans[$locale] = $this->addDefaultShortDescription($translation);
199
200
            // Automatically add an url for this locale based on the given title
201 16
            if (!isset($urls[$locale]) && isset($translation['title'])) {
202 16
                $urls[$locale] = Str::slug($translation['title']);
203
            }
204
        }
205
206
        // Merge with request...
207 17
        return $request->merge(['trans' => $trans, 'url-slugs' => $urls]);
208
    }
209
210 39
    public function updateRequest(Request $request): Request
211
    {
212 39
        $trans = [];
213 39
        foreach ($request->get('trans', []) as $locale => $translation) {
214 38
            if (is_array_empty($translation)) {
215
216
                // Nullify all values
217
                $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

217
                $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...
218 2
                    return null;
219 2
                }, $translation);
220 2
                continue;
221
            }
222
223 38
            $trans[$locale] = $this->addDefaultShortDescription($translation);
224
        }
225
226
        // Merge with request...
227 39
        return $request->merge(['trans' => $trans]);
228
    }
229
230 15
    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

230
    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...
231
    {
232 15
        Audit::activity()
233 15
            ->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

233
            ->performedOn(/** @scrutinizer ignore-type */ $this->model)
Loading history...
234 15
            ->log('created');
235 15
    }
236
237 37
    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

237
    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...
238
    {
239 37
        Audit::activity()
240 37
            ->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

240
            ->performedOn(/** @scrutinizer ignore-type */ $this->model)
Loading history...
241 37
            ->log('edited');
242 37
    }
243
244
    /**
245
     * @param array $translation
246
     * @return array
247
     */
248 51
    private function addDefaultShortDescription(array $translation): array
249
    {
250 51
        if (isset($translation['content'])) {
251 1
            $translation['short'] = $translation['short'] ?? teaser($translation['content'], 100);
252
        }
253
254 51
        return $translation;
255
    }
256
}
257