Completed
Push — master ( 09a99f...0f3793 )
by Sherif
02:40
created

BaseApiController   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 214
Duplicated Lines 22.43 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 3
Bugs 1 Features 1
Metric Value
wmc 48
c 3
b 1
f 1
lcom 1
cbo 3
dl 48
loc 214
rs 8.4864

11 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 13 7
A index() 0 8 4
A find() 8 8 4
A search() 8 8 4
A findby() 8 8 4
A first() 8 8 4
A paginate() 8 8 4
A paginateby() 8 8 4
B save() 0 26 6
A delete() 0 7 2
B checkPermission() 0 12 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like BaseApiController 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 BaseApiController, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace App\Modules\V1\Core\Http\Controllers;
3
4
use App\Http\Controllers\Controller;
5
use Illuminate\Http\Request;
6
7
class BaseApiController extends Controller
8
{
9
    /**
10
     * The model implementation.
11
     * 
12
     * @var model
13
     */
14
    protected $model;
15
16
    /**
17
     * The config implementation.
18
     * 
19
     * @var config
20
     */
21
    protected $config;
22
23
    public function __construct()
24
    {
25
        \Session::set('timeZoneDiff', \Request::header('time-zone-diff') ?: 0);
26
        
27
        $this->config              = \CoreConfig::getConfig();
28
        $this->model               = property_exists($this, 'model') ? $this->model : false;
0 ignored issues
show
Documentation Bug introduced by
It seems like property_exists($this, '... ? $this->model : false can also be of type false. However, the property $model is declared as type object<App\Modules\V1\Co...Http\Controllers\model>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
29
        $this->validationRules     = property_exists($this, 'validationRules') ? $this->validationRules : false;
30
        $this->skipPermissionCheck = property_exists($this, 'skipPermissionCheck') ? $this->skipPermissionCheck : [];
31
        $this->skipLoginCheck      = property_exists($this, 'skipLoginCheck') ? $this->skipLoginCheck : [];
32
        $this->relations           = array_key_exists($this->model, $this->config['relations']) ? $this->config['relations'][$this->model] : false;
33
        $route                     = explode('@',\Route::currentRouteAction())[1];
34
        $this->checkPermission($route);
35
    }
36
37
    /**
38
     * Fetch all records with relations from model repository.
39
     * 
40
     * @return \Illuminate\Http\Response
41
     */
42
    public function index() 
43
    {
44
        if ($this->model)
45
        {
46
            $relations = $this->relations && $this->relations['all'] ? $this->relations['all'] : [];
47
            return \Response::json(call_user_func_array("\Core::{$this->model}", [])->all($relations), 200);
48
        }
49
    }
50
51
    /**
52
     * Fetch the single object with relations from model repository.
53
     * 
54
     * @param  integer $id
55
     * @return \Illuminate\Http\Response
56
     */
57 View Code Duplication
    public function find($id) 
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
58
    {
59
        if ($this->model) 
60
        {
61
            $relations = $this->relations && $this->relations['find'] ? $this->relations['find'] : [];
62
            return \Response::json(call_user_func_array("\Core::{$this->model}", [])->find($id, $relations), 200);
63
        }
64
    }
65
66
    /**
67
     * Paginate all records with relations from model repository
68
     * that matche the given query.
69
     * 
70
     * @param  string  $query
71
     * @param  integer $perPage
72
     * @param  string  $sortBy
73
     * @param  boolean $desc
74
     * @return \Illuminate\Http\Response
75
     */
76 View Code Duplication
    public function search($query = '', $perPage = 15, $sortBy = 'created_at', $desc = 1) 
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
77
    {
78
        if ($this->model) 
79
        {
80
            $relations = $this->relations && $this->relations['paginate'] ? $this->relations['paginate'] : [];
81
            return \Response::json(call_user_func_array("\Core::{$this->model}", [])->search($query, $perPage, $relations, $sortBy, $desc), 200);
82
        }
83
    }
84
85
    /**
86
     * Fetch records from the storage based on the given
87
     * condition.
88
     * 
89
     * @param  \Illuminate\Http\Request  $request
90
     * @param  string  $sortBy
91
     * @param  boolean $desc
92
     * @return \Illuminate\Http\Response
93
     */
94 View Code Duplication
    public function findby(Request $request, $sortBy = 'created_at', $desc = 1) 
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
95
    {
96
        if ($this->model) 
97
        {
98
            $relations = $this->relations && $this->relations['findBy'] ? $this->relations['findBy'] : [];
99
            return \Response::json(call_user_func_array("\Core::{$this->model}", [])->findBy($request->all(), $relations, $sortBy, $desc), 200);
100
        }
101
    }
102
103
    /**
104
     * Fetch the first record from the storage based on the given
105
     * condition.
106
     * 
107
     * @param  \Illuminate\Http\Request  $request
108
     * @return \Illuminate\Http\Response
109
     */
110 View Code Duplication
    public function first(Request $request) 
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
111
    {
112
        if ($this->model) 
113
        {
114
            $relations = $this->relations && $this->relations['first'] ? $this->relations['first'] : [];
115
            return \Response::json(call_user_func_array("\Core::{$this->model}", [])->first($request->all(), $relations), 200);
116
        }
117
    }
118
119
    /**
120
     * Paginate all records with relations from model repository.
121
     * 
122
     * @param  integer $perPage
123
     * @param  string  $sortBy
124
     * @param  boolean $desc
125
     * @return \Illuminate\Http\Response
126
     */
127 View Code Duplication
    public function paginate($perPage = 15, $sortBy = 'created_at', $desc = 1) 
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
128
    {
129
        if ($this->model) 
130
        {
131
            $relations = $this->relations && $this->relations['paginate'] ? $this->relations['paginate'] : [];
132
            return \Response::json(call_user_func_array("\Core::{$this->model}", [])->paginate($perPage, $relations, $sortBy, $desc), 200);
133
        }
134
    }
135
136
    /**
137
     * Fetch all records with relations based on
138
     * the given condition from storage in pages.
139
     * 
140
     * @param  \Illuminate\Http\Request  $request
141
     * @param  integer $perPage
142
     * @param  string  $sortBy
143
     * @param  boolean $desc
144
     * @return \Illuminate\Http\Response
145
     */
146 View Code Duplication
    public function paginateby(Request $request, $perPage = 15, $sortBy = 'created_at', $desc = 1) 
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
147
    {
148
        if ($this->model) 
149
        {
150
            $relations = $this->relations && $this->relations['paginateBy'] ? $this->relations['paginateBy'] : [];
151
            return \Response::json(call_user_func_array("\Core::{$this->model}", [])->paginateBy($request->all(), $perPage, $relations, $sortBy, $desc), 200);
152
        }
153
    }
154
155
    /**
156
     * Save the given model to repository.
157
     * 
158
     * @param  \Illuminate\Http\Request  $request
159
     * @return \Illuminate\Http\Response
160
     */
161
    public function save(Request $request) 
162
    {
163
        foreach ($this->validationRules as &$rule) 
164
        {
165
            if (strpos($rule, 'exists') && ! strpos($rule, 'deleted_at,NULL')) 
166
            {
167
                $rule .= ',deleted_at,NULL';
168
            }
169
170
            if ($request->has('id')) 
171
            {
172
                $rule = str_replace('{id}', $request->get('id'), $rule);
173
            }
174
            else
175
            {
176
                $rule = str_replace(',{id}', '', $rule);
177
            }
178
        }
179
        
180
        $this->validate($request, $this->validationRules);
181
182
        if ($this->model) 
183
        {
184
            return \Response::json(call_user_func_array("\Core::{$this->model}", [])->save($request->all()), 200);
185
        }
186
    }
187
188
    /**
189
     * Delete by the given id from model repository.
190
     * 
191
     * @param  integer  $id
192
     * @return \Illuminate\Http\Response
193
     */
194
    public function delete($id) 
195
    {
196
        if ($this->model) 
197
        {
198
            return \Response::json(call_user_func_array("\Core::{$this->model}", [])->delete($id), 200);
199
        }
200
    }
201
202
    /**
203
     * Check if the logged in user can do the given permission.
204
     * 
205
     * @param  string $permission
206
     * @return void
207
     */
208
    private function checkPermission($permission)
209
    {
210
        $permission = $permission !== 'index' ? $permission : 'list';
211
        if ( ! in_array($permission, $this->skipLoginCheck)) 
212
        {
213
            \JWTAuth::parseToken()->authenticate();
214
            if ( ! in_array($permission, $this->skipPermissionCheck) && ! \Core::users()->can($permission, $this->model))
215
            {
216
                \ErrorHandler::noPermissions();
217
            }
218
        }
219
    }
220
}
221