Completed
Push — master ( 442119...4a1793 )
by wen
02:50
created

Component   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 284
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 7
dl 0
loc 284
rs 8.3673
c 0
b 0
f 0

27 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 2
A setDefaultName() 0 4 1
A getModelClassName() 0 4 1
A getName() 0 4 1
A getTitle() 0 4 1
A getModel() 0 4 1
A getRepository() 0 4 1
A get() 0 10 1
A getConfigs() 0 10 1
A fireView() 0 9 2
A fireCreate() 0 12 2
A store() 0 6 1
A update() 0 5 1
A fireEdit() 0 14 2
A bootIfNotBooted() 0 12 2
A boot() 0 4 1
A isView() 0 4 2
A isCreate() 0 4 2
A isEdit() 0 4 2
A isDelete() 0 4 1
A isDestroy() 0 4 2
A isRestore() 0 4 2
A isRestorableModel() 0 4 1
B registerObserver() 0 17 5
A registerPermission() 0 4 1
A can() 0 7 3
A getPermissions() 0 13 3

How to fix   Complexity   

Complex Class

Complex classes like Component often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Component, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Sco\Admin\Component;
4
5
use Illuminate\Foundation\Application;
6
use Illuminate\Http\Request;
7
use Sco\Admin\Component\Concerns\HasEvents;
8
use Sco\Admin\Component\Concerns\HasNavigation;
9
use Sco\Admin\Contracts\ComponentInterface;
10
use Sco\Admin\Contracts\RepositoryInterface;
11
use Sco\Admin\Exceptions\BadMethodCallException;
12
13
abstract class Component implements ComponentInterface
14
{
15
    use HasEvents,
16
        HasNavigation;
17
18
    /**
19
     * @var
20
     */
21
    protected $name;
22
23
    /**
24
     * @var \Illuminate\Foundation\Application
25
     */
26
    protected $app;
27
28
    protected $title;
29
30
    /**
31
     * @var mixed|\Sco\Admin\Contracts\RepositoryInterface
32
     */
33
    protected $repository;
34
35
    /**
36
     * @var \Illuminate\Database\Eloquent\Model
37
     */
38
    protected $model;
39
40
    protected static $booted = [];
41
42
    /**
43
     * @var \Illuminate\Contracts\Events\Dispatcher
44
     */
45
    protected static $dispatcher;
46
47
    /**
48
     * @var string
49
     */
50
    protected $permissionObserver;
51
52
    protected $permissions;
53
54
    protected $permissionMethods = [
55
        'view', 'create', 'edit',
56
        'delete', 'destroy', 'restore',
57
    ];
58
59
    public function __construct(Application $app, $modelClass)
60
    {
61
        $this->app = $app;
62
63
        $this->repository = $this->app->make(RepositoryInterface::class);
64
        $this->repository->setClass($modelClass);
65
66
        $this->model = $this->repository->getModel();
67
        if (!$this->name) {
68
            $this->setDefaultName();
69
        }
70
71
        $this->registerObserver($this->permissionObserver);
72
73
        $this->bootIfNotBooted();
74
    }
75
76
    protected function setDefaultName()
77
    {
78
        $this->name = $this->getModelClassName();
79
    }
80
81
    protected function getModelClassName()
82
    {
83
        return snake_case(str_plural(class_basename(get_class($this->getModel()))));
84
    }
85
86
    public function getName()
87
    {
88
        return $this->name;
89
    }
90
91
    public function getTitle()
92
    {
93
        return $this->title;
94
    }
95
96
    public function getModel()
97
    {
98
        return $this->model;
99
    }
100
101
    public function getRepository()
102
    {
103
        return $this->repository;
104
    }
105
106
    public function get()
107
    {
108
        $view = $this->fireView();
109
110
        $this->getRepository();
0 ignored issues
show
Unused Code introduced by
The call to the method Sco\Admin\Component\Component::getRepository() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
111
112
        $view->setRepository($this->getRepository());
113
114
        return $view->get();
115
    }
116
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function getConfigs()
122
    {
123
        return collect([
124
            'primaryKey'  => $this->getModel()->getKeyName(),
125
            'title'       => $this->getTitle(),
126
            'permissions' => $this->getPermissions(),
127
            'view'        => $this->fireView(),
128
            //'elements'    => $this->getElements()->values(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
129
        ]);
130
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135
    public function fireView()
136
    {
137
        if (!method_exists($this, 'callView')) {
138
            throw new BadMethodCallException('Not Found Method "callView"');
139
        }
140
141
        $view = $this->app->call([$this, 'callView']);
142
        return $view;
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    public function fireCreate()
149
    {
150
        if (!method_exists($this, 'callCreate')) {
151
            return;
152
        }
153
154
        $form = $this->app->call([$this, 'callCreate']);
155
156
        $form->setModel($this->getModel());
157
158
        return $form;
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     */
164
    public function store()
165
    {
166
        $form = $this->fireCreate();
167
168
        $form->validate()->save();
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174
    public function update($id)
175
    {
176
        $form = $this->fireEdit($id);
177
        $form->validate()->save();
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183
    public function fireEdit($id)
184
    {
185
        if (!method_exists($this, 'callEdit')) {
186
            return;
187
        }
188
189
        $form = $this->app->call([$this, 'callEdit'], ['id' => $id]);
190
191
        $model = $this->getRepository()->findOrFail($id);
192
193
        $form->setModel($model);
194
195
        return $form;
196
    }
197
198
199
    protected function bootIfNotBooted()
200
    {
201
        if (!isset(static::$booted[static::class])) {
202
            static::$booted[static::class] = true;
203
204
            $this->fireEvent('booting', false);
205
206
            $this->boot();
0 ignored issues
show
Unused Code introduced by
The call to the method Sco\Admin\Component\Component::boot() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
207
208
            $this->fireEvent('booted', false);
209
        }
210
    }
211
212
    public function boot()
213
    {
214
        return true;
215
    }
216
217
    public function isView()
218
    {
219
        return method_exists($this, 'callView') && $this->can('view');
220
    }
221
222
    public function isCreate()
223
    {
224
        return method_exists($this, 'callCreate') && $this->can('create');
225
    }
226
227
    public function isEdit()
228
    {
229
        return method_exists($this, 'callEdit') && $this->can('edit');
230
    }
231
232
    public function isDelete()
233
    {
234
        return $this->can('delete');
235
    }
236
237
    public function isDestroy()
238
    {
239
        return $this->isRestorableModel() && $this->can('destroy');
240
    }
241
242
    public function isRestore()
243
    {
244
        return $this->isRestorableModel() && $this->can('restore');
245
    }
246
247
    protected function isRestorableModel()
248
    {
249
        return $this->getRepository()->isRestorable();
250
    }
251
252
    public function registerObserver($class = null)
253
    {
254
        if (!$class) {
255
            return;
256
        }
257
258
        $className = is_string($class) ? $class : get_class($class);
259
260
        foreach ($this->permissionMethods as $method) {
261
            if (method_exists($class, $method)) {
262
                $this->registerPermission(
263
                    $method,
264
                    [$this->app->make($className), $method]
265
                );
266
            }
267
        }
268
    }
269
270
    public function registerPermission($permission, $callback)
271
    {
272
        $this->permissions[$permission] = $callback;
273
    }
274
275
    public function can($permission)
276
    {
277
        if (is_callable($this->permissions[$permission])) {
278
            return call_user_func_array($this->permissions[$permission], [$this]);
279
        }
280
        return $this->permissions[$permission] ? true : false;
281
    }
282
283
    public function getPermissions()
284
    {
285
        $data = collect();
286
        foreach ($this->permissionMethods as $perm) {
287
            $method = 'is' . ucfirst($perm);
288
            if (!method_exists($this, $method)) {
289
                $method = 'can';
290
            }
291
292
            $data->put($perm, $this->{$method}($perm));
293
        }
294
        return $data;
295
    }
296
}
297