Passed
Push — master ( 56d5e3...34af01 )
by Philippe
08:29
created

AbstractManager   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Test Coverage

Coverage 95.95%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
wmc 32
eloc 77
c 3
b 1
f 0
dl 0
loc 252
ccs 71
cts 74
cp 0.9595
rs 9.84

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A findManaged() 0 7 1
A manage() 0 5 1
A can() 0 3 1
A delete() 0 3 1
A model() 0 3 1
A filters() 0 3 1
A indexCollection() 0 18 2
A fieldArrangement() 0 3 1
A indexBuilder() 0 3 1
A hasExistingModel() 0 3 2
A fieldsWithAssistantFields() 0 13 3
A guard() 0 7 2
A route() 0 21 2
A storeRequest() 0 3 1
A validateConstraints() 0 4 2
A indexSorting() 0 12 3
A updateRequest() 0 3 1
A indexPagination() 0 9 1
A fields() 0 3 1
A existingModel() 0 7 2
A requestContainsTranslations() 0 3 1
1
<?php
2
3
namespace Thinktomorrow\Chief\Management;
4
5
use Illuminate\Contracts\Pagination\Paginator;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Http\Request;
8
use Illuminate\Support\Collection;
9
use Thinktomorrow\Chief\Concerns\Translatable\TranslatableCommand;
10
use Thinktomorrow\Chief\Fields\FieldArrangement;
11
use Thinktomorrow\Chief\Fields\Fields;
12
use Thinktomorrow\Chief\Fields\RenderingFields;
13
use Thinktomorrow\Chief\Fields\SavingFields;
14
use Thinktomorrow\Chief\Filters\Filters;
15
use Thinktomorrow\Chief\Management\Assistants\AssistedManager;
16
use Thinktomorrow\Chief\Management\Details\HasDetails;
17
use Thinktomorrow\Chief\Management\Details\HasSections;
18
use Thinktomorrow\Chief\Management\Exceptions\NonExistingRecord;
19
use Thinktomorrow\Chief\Management\Exceptions\NotAllowedManagerRoute;
20
21
abstract class AbstractManager
22
{
23
    use RenderingFields,
0 ignored issues
show
Bug introduced by
The trait Thinktomorrow\Chief\Fields\SavingFields requires the property $key which is not provided by Thinktomorrow\Chief\Management\AbstractManager.
Loading history...
introduced by
The trait Thinktomorrow\Chief\Management\ManagesPagebuilder requires some properties which are not provided by Thinktomorrow\Chief\Management\AbstractManager: $trans, $slug, $page_id, $id
Loading history...
introduced by
The trait Thinktomorrow\Chief\Management\Details\HasDetails requires some properties which are not provided by Thinktomorrow\Chief\Management\AbstractManager: $labelPlural, $id, $labelSingular, $title
Loading history...
24
        SavingFields,
25
        HasDetails,
26
        HasSections,
27
        ManagesMedia,
28
        ManagesPagebuilder,
29
        TranslatableCommand,
30
        AssistedManager;
31
32
    protected $translation_columns = [];
33
34
    protected $model;
35
36
    /** @var Register */
37 149
    protected $registration;
38
39 149
    protected $pageCount = 20;
40
    protected $paginated = true;
41
42 149
    public function __construct(Registration $registration)
43
    {
44
        $this->registration = $registration;
0 ignored issues
show
Documentation Bug introduced by
It seems like $registration of type Thinktomorrow\Chief\Management\Registration is incompatible with the declared type Thinktomorrow\Chief\Management\Register of property $registration.

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...
45 149
46 149
        // Upon instantiation, a general model is set that doesn't point to a persisted record.
47
        $this->manage(app($this->registration->model()));
48 149
49
        // Check if key and model are present since the model should be set by the manager itself
50 149
        $this->validateConstraints();
51
    }
52 149
53
    public function manage($model): Manager
54
    {
55 85
        $this->model = $model;
56
57 85
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Thinktomorrow\Chief\Management\AbstractManager which is incompatible with the type-hinted return Thinktomorrow\Chief\Management\Manager.
Loading history...
58
    }
59 85
60
    public function findManaged($id): Manager
61 85
    {
62
        $model = $this->registration->model();
0 ignored issues
show
Bug introduced by
The method model() does not exist on Thinktomorrow\Chief\Management\Register. ( Ignorable by Annotation )

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

62
        /** @scrutinizer ignore-call */ 
63
        $model = $this->registration->model();

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...
63
64 1
        $modelInstance = $model::where('id', $id)->withoutGlobalScopes()->first();
65
66 1
        return (new static($this->registration))->manage($modelInstance);
0 ignored issues
show
Bug introduced by
$this->registration of type Thinktomorrow\Chief\Management\Register is incompatible with the type Thinktomorrow\Chief\Management\Registration expected by parameter $registration of Thinktomorrow\Chief\Mana...tManager::__construct(). ( Ignorable by Annotation )

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

66
        return (new static(/** @scrutinizer ignore-type */ $this->registration))->manage($modelInstance);
Loading history...
67
    }
68 1
69
    public function indexCollection()
70 1
    {
71 1
        $model = $this->registration->model();
72
73
        $builder = (new $model)->query();
74 1
75 1
        $this->filters()->apply($builder);
76
77
        $builder = $this->indexBuilder($builder);
78
79 1
        $builder = $this->indexSorting($builder);
80 1
        
81
        if ($this->paginated) {
82
            return $this->indexPagination($builder);
83
        }
84 1
        
85 1
        return $builder->get()->map(function ($model) {
86
            return (new static($this->registration))->manage($model);
0 ignored issues
show
Bug introduced by
$this->registration of type Thinktomorrow\Chief\Management\Register is incompatible with the type Thinktomorrow\Chief\Management\Registration expected by parameter $registration of Thinktomorrow\Chief\Mana...tManager::__construct(). ( Ignorable by Annotation )

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

86
            return (new static(/** @scrutinizer ignore-type */ $this->registration))->manage($model);
Loading history...
87
        });
88 90
    }
89
90 90
    protected function indexBuilder(Builder $builder): Builder
91
    {
92
        return $builder;
93 94
    }
94
95 94
    protected function indexSorting(Builder $builder): Builder
96
    {
97
        if ($this->isAssistedBy('publish')) {
98
            $builder->orderBy('published', 'DESC');
99
        }
100
101
        // if model has no timestamps, updated_at doesn't exist
102
        if ($this->model()->timestamps) {
103
            $builder->orderBy('updated_at', 'DESC');
104 94
        }
105
106 94
        return $builder;
107 1
    }
108
109
    protected function indexPagination($builder): Paginator
110 93
    {
111
        $paginator = $builder->paginate($this->pageCount);
112
113
        $modifiedCollection = $builder->paginate($this->pageCount)->getCollection()->transform(function ($model) {
114
            return (new static($this->registration))->manage($model);
0 ignored issues
show
Bug introduced by
$this->registration of type Thinktomorrow\Chief\Management\Register is incompatible with the type Thinktomorrow\Chief\Management\Registration expected by parameter $registration of Thinktomorrow\Chief\Mana...tManager::__construct(). ( Ignorable by Annotation )

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

114
            return (new static(/** @scrutinizer ignore-type */ $this->registration))->manage($model);
Loading history...
115
        });
116
117
        return $paginator->setCollection($modifiedCollection);
118
    }
119
120
    public function model()
121 117
    {
122
        return $this->model;
123
    }
124 117
125 117
    public function hasExistingModel(): bool
126 117
    {
127
        return ($this->model && $this->model->exists);
128
    }
129 117
130 68
    /**
131
     * If the model exists return it otherwise
132
     * throws a nonExistingRecord exception;
133
     *
134
     * @throws NonExistingRecord
135 94
     */
136 93
    protected function existingModel()
137 93
    {
138 93
        if (!$this->hasExistingModel()) {
139
            throw new NonExistingRecord('Model does not exist yet but is expected.');
140
        }
141 93
142
        return $this->model;
143
    }
144 121
145
    /**
146 121
     * Determine which actions should be available for this
147
     * manager and their respective routed urls.
148
     *
149 107
     * @param $verb
150
     * @return null|string
151 107
     * @throws NonExistingRecord
152 1
     */
153
    public function route($verb): ?string
154
    {
155 106
        $routes = [
156
            'index'   => route('chief.back.managers.index', [$this->registration->key()]),
0 ignored issues
show
Bug introduced by
The method key() does not exist on Thinktomorrow\Chief\Management\Register. ( Ignorable by Annotation )

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

156
            'index'   => route('chief.back.managers.index', [$this->registration->/** @scrutinizer ignore-call */ key()]),

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...
157
            'create'  => route('chief.back.managers.create', [$this->registration->key()]),
158 83
            'store'   => route('chief.back.managers.store', [$this->registration->key()]),
159
        ];
160 83
161
        if (array_key_exists($verb, $routes)) {
162
            return $routes[$verb] ?? null;
163
        }
164
165
        //These routes expect the model to be persisted in the database
166
        $modelRoutes = [
167
            'edit'    => route('chief.back.managers.edit', [$this->registration->key(), $this->existingModel()->id]),
168
            'update'  => route('chief.back.managers.update', [$this->registration->key(), $this->existingModel()->id]),
169 101
            'delete'  => route('chief.back.managers.delete', [$this->registration->key(), $this->existingModel()->id]),
170
            'upload'  => route('chief.back.managers.media.upload', [$this->registration->key(), $this->existingModel()->id]),
171 101
        ];
172
173 101
        return $modelRoutes[$verb] ?? null;
174 77
    }
175 75
176
    public function can($verb): bool
177
    {
178 77
        return !is_null($this->route($verb));
179
    }
180
181 101
    public function guard($verb): Manager
182
    {
183
        if (! $this->can($verb)) {
184
            NotAllowedManagerRoute::notAllowedVerb($verb, $this);
185
        }
186
187
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Thinktomorrow\Chief\Management\AbstractManager which is incompatible with the type-hinted return Thinktomorrow\Chief\Management\Manager.
Loading history...
188
    }
189
190
    public function fields(): Fields
191
    {
192
        return new Fields();
193 3
    }
194
195 3
    /**
196
     * Enrich the manager fields with any of the assistant specified fields
197
     *
198 1
     * @return Fields
199
     * @throws \Exception
200 1
     */
201 1
    public function fieldsWithAssistantFields(): Fields
202
    {
203
        $fields = $this->fields();
204
205
        foreach ($this->assistants() as $assistant) {
206
            if (! method_exists($assistant, 'fields')) {
207
                continue;
208
            }
209
210
            $fields = $fields->merge($assistant->fields());
211
        }
212
213
        return $fields;
214
    }
215 24
216
    /**
217 24
     * This determines the arrangement of the manageable fields
218
     * on the create and edit forms. By default, all fields
219
     * are presented in their order of appearance
220
     *
221
     * @param null $key pinpoint to a specific field arrangement e.g. for create page.
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $key is correct as it would always require null to be passed?
Loading history...
222
     * @return FieldArrangement
223
     * @throws \Exception
224
     */
225
    public function fieldArrangement($key = null): FieldArrangement
226
    {
227 22
        return new FieldArrangement($this->fieldsWithAssistantFields());
228
    }
229 22
230
    public function delete()
231
    {
232 77
        $this->model->delete();
233
    }
234 77
235
    public static function filters(): Filters
236
    {
237 149
        return new Filters();
238
    }
239 149
240
    /**
241
     * This method can be used to manipulate the store request payload
242 149
     * before being passed to the storing / updating the models.
243
     *
244
     * @param Request $request
245
     * @return Request
246
     */
247
    public function storeRequest(Request $request): Request
248
    {
249
        return $request;
250
    }
251
252
    /**
253
     * This method can be used to manipulate the update request payload
254
     * before being passed to the storing / updating the models.
255
     *
256
     * @param Request $request
257
     * @return Request
258
     */
259
    public function updateRequest(Request $request): Request
260
    {
261
        return $request;
262
    }
263
264
    protected function requestContainsTranslations(Request $request): bool
265
    {
266
        return $request->has('trans');
267
    }
268
269
    protected function validateConstraints()
270
    {
271
        if (!$this->model) {
272
            throw new \DomainException('Model class should be set for this manager. Please set the model property default via the constructor or by extending the setupDefaults method.');
273
        }
274
    }
275
}
276