Completed
Pull Request — master (#79)
by Sebastian
05:27 queued 58s
created

ModuleController   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 169
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 10

Importance

Changes 0
Metric Value
dl 0
loc 169
rs 10
c 0
b 0
f 0
wmc 21
lcom 2
cbo 10

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A index() 0 6 1
A create() 0 6 1
A show() 0 4 1
A edit() 0 14 2
A update() 0 20 2
A destroy() 0 14 1
A changeOrder() 0 4 1
A find() 0 4 1
A all() 0 10 2
A determineModelClass() 0 6 1
A determineModuleName() 0 4 1
A determineUpdateRequestClass() 0 8 1
A updateModel() 0 10 1
A updatedEventDescriptionFor() 0 12 2
A deletedEventDescriptionFor() 0 6 1
A action() 0 4 1
1
<?php
2
3
namespace App\Http\Controllers\Back;
4
5
use Cache;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Foundation\Http\FormRequest;
8
use Illuminate\Support\Collection;
9
use ReflectionClass;
10
use Spatie\EloquentSortable\SortableInterface;
11
12
abstract class ModuleController
13
{
14
    use Updaters\UpdateMedia;
15
    use Updaters\UpdateOnlineToggle;
16
    use Updaters\UpdatePublishDate;
17
    use Updaters\UpdateSeoValues;
18
    use Updaters\UpdateTags;
19
    use Updaters\UpdateTranslations;
20
21
    /** @var string */
22
    protected $modelClass, $moduleName;
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
23
24
    /** @var bool */
25
    protected $redirectToIndex = false;
26
27
    public function __construct()
28
    {
29
        $this->modelClass = $this->determineModelClass();
30
        $this->moduleName = $this->determineModuleName();
31
    }
32
33
    public function index()
34
    {
35
        $models = $this->all();
36
37
        return view("back.{$this->moduleName}.index")->with('models', $models);
0 ignored issues
show
Bug introduced by
The method with does only exist in Illuminate\View\View, but not in Illuminate\Contracts\View\Factory.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
38
    }
39
40
    public function create()
41
    {
42
        $model = $this->make();
43
44
        return redirect()->to($this->action('edit', $model->id));
45
    }
46
47
    public function show($id)
48
    {
49
        return redirect()->to($this->action('edit', $id));
50
    }
51
52
    public function edit(int $id)
53
    {
54
        $model = $this->find($id);
55
56
        if (request()->has('revert')) {
57
            $model->clearTemporaryMedia();
58
59
            return redirect()->to($this->action('edit', $id));
0 ignored issues
show
Documentation introduced by
$id is of type integer, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
60
        }
61
62
        return view("back.{$this->moduleName}.edit")
0 ignored issues
show
Bug introduced by
The method with does only exist in Illuminate\View\View, but not in Illuminate\Contracts\View\Factory.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
63
            ->with('model', $model)
64
            ->with('module', $this->moduleName);
65
    }
66
67
    public function update(int $id)
68
    {
69
        $formRequest = $this->determineUpdateRequestClass();
70
71
        $request = app()->make($formRequest);
72
73
        $model = $this->find($id);
74
75
        $this->updateFromRequest($model, $request);
0 ignored issues
show
Bug introduced by
The method updateFromRequest() does not exist on App\Http\Controllers\Back\ModuleController. Did you maybe mean update()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
76
77
        Cache::flush();
78
79
        $eventDescription = $this->updatedEventDescriptionFor($model);
80
        activity()->on($model)->log($eventDescription);
81
        flash()->success(strip_tags($eventDescription));
82
83
        return redirect()->to(
84
            $this->redirectToIndex ? $this->action('index') : $this->action('edit', $model->id)
85
        );
86
    }
87
88
    public function destroy($id)
89
    {
90
        $model = $this->query()->find($id);
0 ignored issues
show
Bug introduced by
The method query() does not seem to exist on object<App\Http\Controll...\Back\ModuleController>.

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...
91
92
        $eventDescription = $this->deletedEventDescriptionFor($model);
93
        activity()->log($eventDescription);
94
        flash()->success(strip_tags($eventDescription));
95
96
        $model->delete();
97
98
        Cache::flush();
99
100
        return redirect()->to($this->action('index'));
101
    }
102
103
    public function changeOrder(Request $request)
104
    {
105
        call_user_func([$this->modelClass, 'setNewOrder'], $request->get('ids'));
106
    }
107
108
    protected function find(int $id): Model
109
    {
110
        return call_user_func("{$this->modelClass}::findOrFail", $id);
111
    }
112
113
    protected function all(): Collection
114
    {
115
        $query = call_user_func("{$this->modelClass}::query")->nonDraft();
116
117
        if (array_key_exists(SortableInterface::class, class_implements($this->modelClass))) {
118
            $query->orderBy('order_column', 'asc');
119
        }
120
121
        return $query->get();
122
    }
123
124
    protected function determineModelClass(): string
125
    {
126
        return (new ReflectionClass($this))
127
            ->getMethod('make')
128
            ->getReturnType();
129
    }
130
131
    protected function determineModuleName(): string
132
    {
133
        return explode('_', snake_case(short_class_name($this), '_'), 2)[0];
134
    }
135
136
    protected function determineUpdateRequestClass(): string
137
    {
138
        return (new ReflectionClass($this))
139
            ->getMethod('updateFromRequest')
140
            ->getParameters()[1]
141
            ->getClass()
142
            ->getName();
143
    }
144
145
    protected function updateModel(Model $model, FormRequest $request)
146
    {
147
        $this->updateTranslations($model, $request);
148
        $this->updateMedia($model, $request);
149
        $this->updateOnlineToggle($model, $request);
150
        $this->updatePublishDate($model, $request);
151
        $this->updateSeoValues($model, $request);
152
153
        $model->save();
154
    }
155
156
    protected function updatedEventDescriptionFor($model): string
157
    {
158
        $modelName = fragment("back.{$this->moduleName}.singular");
159
160
        $linkToModel = el('a', ['href' => $this->action('edit', $model->id)], $model->name);
161
162
        if ($model->wasDraft) {
163
            return fragment('back.events.created', ['model' => $modelName, 'name' => $linkToModel]);
164
        }
165
166
        return fragment('back.events.updated', ['model' => $modelName, 'name' => $linkToModel]);
167
    }
168
169
    protected function deletedEventDescriptionFor($model): string
170
    {
171
        $modelName = fragment("back.{$this->moduleName}.singular");
172
173
        return fragment('back.events.deleted', ['model' => $modelName, 'name' => $model->name]);
174
    }
175
176
    protected function action(string $action, $parameters = []): string
177
    {
178
        return action('\\'.static::class.'@'.$action, $parameters);
179
    }
180
}
181