Passed
Push — ft/added-admin-pagination ( 8c8774 )
by Philippe
10:19
created

AbstractManager::indexSorting()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 12
rs 10
cc 3
nc 4
nop 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
    protected $registration;
38
39
    protected $pageCount = 20;
40
    protected $paginated = true;
41
42
    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
46
        // Upon instantiation, a general model is set that doesn't point to a persisted record.
47
        $this->manage(app($this->registration->model()));
48
49
        // Check if key and model are present since the model should be set by the manager itself
50
        $this->validateConstraints();
51
    }
52
53
    public function manage($model): Manager
54
    {
55
        $this->model = $model;
56
57
        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
60
    public function findManaged($id): Manager
61
    {
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
        $modelInstance = $model::where('id', $id)->withoutGlobalScopes()->first();
65
66
        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
69
    public function indexCollection()
70
    {
71
        $model = $this->registration->model();
72
73
        $builder = (new $model)->query();
74
75
        $this->filters()->apply($builder);
76
77
        $builder = $this->indexBuilder($builder);
78
79
        $builder = $this->indexSorting($builder);
80
        
81
        if($this->paginated)
82
        {
83
            return $this->indexPagination($builder);
84
        }
85
        
86
        return $builder->get()->map(function ($model) {
87
            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

87
            return (new static(/** @scrutinizer ignore-type */ $this->registration))->manage($model);
Loading history...
88
        });
89
    }
90
91
    protected function indexBuilder(Builder $builder): Builder
92
    {
93
        return $builder;
94
    }
95
96
    protected function indexSorting(Builder $builder): Builder
97
    {
98
        if ($this->isAssistedBy('publish')) {
99
            $builder->orderBy('published', 'DESC');
100
        }
101
102
        // if model has no timestamps, updated_at doesn't exist
103
        if ($this->model()->timestamps) {
104
            $builder->orderBy('updated_at', 'DESC');
105
        }
106
107
        return $builder;
108
    }
109
110
    protected function indexPagination($builder): Paginator
111
    {
112
        $paginator = $builder->paginate($this->pageCount);
113
114
        $modifiedCollection = $builder->paginate($this->pageCount)->getCollection()->transform(function ($model) {
115
            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

115
            return (new static(/** @scrutinizer ignore-type */ $this->registration))->manage($model);
Loading history...
116
        });
117
118
        return $paginator->setCollection($modifiedCollection);
119
    }
120
121
    public function model()
122
    {
123
        return $this->model;
124
    }
125
126
    public function hasExistingModel(): bool
127
    {
128
        return ($this->model && $this->model->exists);
129
    }
130
131
    /**
132
     * If the model exists return it otherwise
133
     * throws a nonExistingRecord exception;
134
     *
135
     * @throws NonExistingRecord
136
     */
137
    protected function existingModel()
138
    {
139
        if (!$this->hasExistingModel()) {
140
            throw new NonExistingRecord('Model does not exist yet but is expected.');
141
        }
142
143
        return $this->model;
144
    }
145
146
    /**
147
     * Determine which actions should be available for this
148
     * manager and their respective routed urls.
149
     *
150
     * @param $verb
151
     * @return null|string
152
     * @throws NonExistingRecord
153
     */
154
    public function route($verb): ?string
155
    {
156
        $routes = [
157
            '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

157
            '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...
158
            'create'  => route('chief.back.managers.create', [$this->registration->key()]),
159
            'store'   => route('chief.back.managers.store', [$this->registration->key()]),
160
        ];
161
162
        if (array_key_exists($verb, $routes)) {
163
            return $routes[$verb] ?? null;
164
        }
165
166
        //These routes expect the model to be persisted in the database
167
        $modelRoutes = [
168
            'edit'    => route('chief.back.managers.edit', [$this->registration->key(), $this->existingModel()->id]),
169
            'update'  => route('chief.back.managers.update', [$this->registration->key(), $this->existingModel()->id]),
170
            'delete'  => route('chief.back.managers.delete', [$this->registration->key(), $this->existingModel()->id]),
171
            'upload'  => route('chief.back.managers.media.upload', [$this->registration->key(), $this->existingModel()->id]),
172
        ];
173
174
        return $modelRoutes[$verb] ?? null;
175
    }
176
177
    public function can($verb): bool
178
    {
179
        return !is_null($this->route($verb));
180
    }
181
182
    public function guard($verb): Manager
183
    {
184
        if (! $this->can($verb)) {
185
            NotAllowedManagerRoute::notAllowedVerb($verb, $this);
186
        }
187
188
        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...
189
    }
190
191
    public function fields(): Fields
192
    {
193
        return new Fields();
194
    }
195
196
    /**
197
     * Enrich the manager fields with any of the assistant specified fields
198
     *
199
     * @return Fields
200
     * @throws \Exception
201
     */
202
    public function fieldsWithAssistantFields(): Fields
203
    {
204
        $fields = $this->fields();
205
206
        foreach ($this->assistants() as $assistant) {
207
            if (! method_exists($assistant, 'fields')) {
208
                continue;
209
            }
210
211
            $fields = $fields->merge($assistant->fields());
212
        }
213
214
        return $fields;
215
    }
216
217
    /**
218
     * This determines the arrangement of the manageable fields
219
     * on the create and edit forms. By default, all fields
220
     * are presented in their order of appearance
221
     *
222
     * @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...
223
     * @return FieldArrangement
224
     * @throws \Exception
225
     */
226
    public function fieldArrangement($key = null): FieldArrangement
227
    {
228
        return new FieldArrangement($this->fieldsWithAssistantFields());
229
    }
230
231
    public function delete()
232
    {
233
        $this->model->delete();
234
    }
235
236
    public static function filters(): Filters
237
    {
238
        return new Filters();
239
    }
240
241
    /**
242
     * This method can be used to manipulate the store request payload
243
     * before being passed to the storing / updating the models.
244
     *
245
     * @param Request $request
246
     * @return Request
247
     */
248
    public function storeRequest(Request $request): Request
249
    {
250
        return $request;
251
    }
252
253
    /**
254
     * This method can be used to manipulate the update request payload
255
     * before being passed to the storing / updating the models.
256
     *
257
     * @param Request $request
258
     * @return Request
259
     */
260
    public function updateRequest(Request $request): Request
261
    {
262
        return $request;
263
    }
264
265
    protected function requestContainsTranslations(Request $request): bool
266
    {
267
        return $request->has('trans');
268
    }
269
270
    protected function validateConstraints()
271
    {
272
        if (!$this->model) {
273
            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.');
274
        }
275
    }
276
}
277