Completed
Push — master ( e2d103...eb2586 )
by Sherif
01:46
created

BaseApiController   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 302
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 3
dl 0
loc 302
rs 8.8
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 4
A index() 0 4 1
A find() 0 4 1
A search() 0 4 1
A findby() 0 4 1
A first() 0 4 1
A paginate() 0 4 1
A paginateby() 0 4 1
A save() 0 18 5
A delete() 0 4 1
A deleted() 0 4 1
A restore() 0 4 1
B checkPermission() 0 22 10
A setSessions() 0 27 5
A setRelations() 0 6 4
B updateLocaleAndTimezone() 0 19 7

How to fix   Complexity   

Complex Class

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
3
namespace App\Modules\Core\BaseClasses;
4
5
use App\Http\Controllers\Controller;
6
use Illuminate\Http\Request;
7
use Illuminate\Support\Arr;
8
use App\Modules\Core\Http\Resources\General as GeneralResource;
9
10
class BaseApiController extends Controller
11
{
12
    /**
13
     * The config implementation.
14
     *
15
     * @var array
16
     */
17
    protected $config;
18
19
    /**
20
     * The relations implementation.
21
     *
22
     * @var array
23
     */
24
    protected $relations;
25
26
    /**
27
     * The repo implementation.
28
     *
29
     * @var object
30
     */
31
    protected $repo;
32
33
    /**
34
     * Init new object.
35
     *
36
     * @param   mixed      $repo
37
     * @param   CoreConfig $config
38
     * @param   string     $modelResource
39
     * @return  void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
40
     */
41
    public function __construct($repo, $config, $modelResource)
42
    {
43
        $this->repo = $repo;
44
        $this->modelResource = $modelResource;
45
        $this->config = $config->getConfig();
46
        $this->modelName = explode('\\', get_called_class());
47
        $this->modelName = lcfirst(str_replace('Controller', '', end($this->modelName)));
48
        $this->validationRules = property_exists($this, 'validationRules') ? $this->validationRules : false;
49
        $this->skipPermissionCheck = property_exists($this, 'skipPermissionCheck') ? $this->skipPermissionCheck : [];
50
        $this->skipLoginCheck = property_exists($this, 'skipLoginCheck') ? $this->skipLoginCheck : [];
51
        $route = explode('@', \Route::currentRouteAction())[1];
52
53
        $this->setSessions();
54
        $this->checkPermission($route);
55
        $this->setRelations($route);
56
    }
57
58
    /**
59
     * Fetch all records with relations from storage.
60
     *
61
     * @param  string  $sortBy The name of the column to sort by.
62
     * @param  boolean $desc   Sort ascending or descinding (1: desc, 0: asc).
63
     * @return \Illuminate\Http\Response
64
     */
65
    public function index($sortBy = 'created_at', $desc = 1)
66
    {
67
        return $this->modelResource::collection($this->repo->all($this->relations, $sortBy, $desc));
68
    }
69
70
    /**
71
     * Fetch the single object with relations from storage.
72
     *
73
     * @param  integer $id Id of the requested model.
74
     * @return \Illuminate\Http\Response
75
     */
76
    public function find($id)
77
    {
78
        return new $this->modelResource($this->repo->find($id, $this->relations));
79
    }
80
81
    /**
82
     * Paginate all records with relations from storage
83
     * that matche the given query.
84
     *
85
     * @param  string  $query   The search text.
86
     * @param  integer $perPage Number of rows per page default 15.
87
     * @param  string  $sortBy  The name of the column to sort by.
88
     * @param  boolean $desc    Sort ascending or descinding (1: desc, 0: asc).
89
     * @return \Illuminate\Http\Response
90
     */
91
    public function search($query = '', $perPage = 15, $sortBy = 'created_at', $desc = 1)
92
    {
93
        return $this->modelResource::collection($this->repo->search($query, $perPage, $this->relations, $sortBy, $desc));
94
    }
95
96
    /**
97
     * Fetch records from the storage based on the given
98
     * condition.
99
     *
100
     * @param  \Illuminate\Http\Request  $request
101
     * @param  string  $sortBy The name of the column to sort by.
102
     * @param  boolean $desc   Sort ascending or descinding (1: desc, 0: asc).
103
     * @return \Illuminate\Http\Response
104
     */
105
    public function findby(Request $request, $sortBy = 'created_at', $desc = 1)
106
    {
107
        return $this->modelResource::collection($this->repo->findBy($request->all(), $this->relations, $sortBy, $desc));
108
    }
109
110
    /**
111
     * Fetch the first record from the storage based on the given
112
     * condition.
113
     *
114
     * @param  \Illuminate\Http\Request  $request
115
     * @return \Illuminate\Http\Response
116
     */
117
    public function first(Request $request)
118
    {
119
        return new $this->modelResource($this->repo->first($request->all(), $this->relations));
120
    }
121
122
    /**
123
     * Paginate all records with relations from storage.
124
     *
125
     * @param  integer $perPage Number of rows per page default 15.
126
     * @param  string  $sortBy  The name of the column to sort by.
127
     * @param  boolean $desc    Sort ascending or descinding (1: desc, 0: asc).
128
     * @return \Illuminate\Http\Response
129
     */
130
    public function paginate($perPage = 15, $sortBy = 'created_at', $desc = 1)
131
    {
132
        return $this->modelResource::collection($this->repo->paginate($perPage, $this->relations, $sortBy, $desc));
133
    }
134
135
    /**
136
     * Fetch all records with relations based on
137
     * the given condition from storage in pages.
138
     *
139
     * @param  \Illuminate\Http\Request  $request
140
     * @param  integer $perPage Number of rows per page default 15.
141
     * @param  string  $sortBy  The name of the column to sort by.
142
     * @param  boolean $desc    Sort ascending or descinding (1: desc, 0: asc).
143
     * @return \Illuminate\Http\Response
144
     */
145
    public function paginateby(Request $request, $perPage = 15, $sortBy = 'created_at', $desc = 1)
146
    {
147
        return $this->modelResource::collection($this->repo->paginateBy($request->all(), $perPage, $this->relations, $sortBy, $desc));
148
    }
149
150
    /**
151
     * Save the given model to storage.
152
     *
153
     * @param  \Illuminate\Http\Request  $request
154
     * @return \Illuminate\Http\Response
155
     */
156
    public function save(Request $request)
157
    {
158
        foreach ($this->validationRules as &$rule) {
159
            if (strpos($rule, 'exists') && ! strpos($rule, 'deleted_at,NULL')) {
160
                $rule .= ',deleted_at,NULL';
161
            }
162
163
            if ($request->has('id')) {
164
                $rule = str_replace('{id}', $request->get('id'), $rule);
165
            } else {
166
                $rule = str_replace(',{id}', '', $rule);
167
            }
168
        }
169
        
170
        $this->validate($request, $this->validationRules);
171
172
        return $this->modelResource::collection($this->repo->save($request->all()));
173
    }
174
175
    /**
176
     * Delete by the given id from storage.
177
     *
178
     * @param  integer $id Id of the deleted model.
179
     * @return \Illuminate\Http\Response
180
     */
181
    public function delete($id)
182
    {
183
        return new GeneralResource($this->repo->delete($id));
184
    }
185
186
    /**
187
     * Return the deleted models in pages based on the given conditions.
188
     *
189
     * @param  \Illuminate\Http\Request  $request
190
     * @param  integer $perPage Number of rows per page default 15.
191
     * @param  string  $sortBy  The name of the column to sort by.
192
     * @param  boolean $desc    Sort ascending or descinding (1: desc, 0: asc).
193
     * @return \Illuminate\Http\Response
194
     */
195
    public function deleted(Request $request, $perPage = 15, $sortBy = 'created_at', $desc = 1)
196
    {
197
        return $this->modelResource::collection($this->repo->deleted($request->all(), $perPage, $sortBy, $desc));
198
    }
199
200
    /**
201
     * Restore the deleted model.
202
     *
203
     * @param  integer $id Id of the restored model.
204
     * @return \Illuminate\Http\Response
205
     */
206
    public function restore($id)
207
    {
208
        return new GeneralResource($this->repo->restore($id));
209
    }
210
211
    /**
212
     * Check if the logged in user can do the given permission.
213
     *
214
     * @param  string $permission
215
     * @return void
216
     */
217
    private function checkPermission($permission)
218
    {
219
        \Auth::shouldUse('api');
220
        $this->middleware('auth:api', ['except' => $this->skipLoginCheck]);
221
        
222
        if (! in_array($permission, $this->skipLoginCheck) && $user = \Auth::user()) {
223
            $user             = \Auth::user();
224
            $permission       = $permission !== 'index' ? $permission : 'list';
225
            $isPasswordClient = $user->token()->client->password_client;
226
            $this->updateLocaleAndTimezone($user);
227
228
            if ($user->blocked) {
229
                \ErrorHandler::userIsBlocked();
230
            }
231
232
            if ($isPasswordClient && (in_array($permission, $this->skipPermissionCheck) || \Core::users()->can($permission, $this->modelName))) {
233
            } elseif (! $isPasswordClient && $user->tokenCan($this->modelName.'-'.$permission)) {
234
            } else {
235
                \ErrorHandler::noPermissions();
236
            }
237
        }
238
    }
239
240
    /**
241
     * Set sessions based on the given headers in the request.
242
     *
243
     * @return void
244
     */
245
    private function setSessions()
246
    {
247
        \Session::put('time-zone', \Request::header('time-zone') ?: 0);
248
249
        $locale = \Request::header('locale');
250
        switch ($locale) {
251
            case 'en':
252
                \App::setLocale('en');
253
                \Session::put('locale', 'en');
254
                break;
255
256
            case 'ar':
257
                \App::setLocale('ar');
258
                \Session::put('locale', 'ar');
259
                break;
260
261
            case 'all':
262
                \App::setLocale('en');
263
                \Session::put('locale', 'all');
264
                break;
265
266
            default:
267
                \App::setLocale('en');
268
                \Session::put('locale', 'en');
269
                break;
270
        }
271
    }
272
273
    /**
274
     * Set relation based on the called api.
275
     *
276
     * @param  string $route
277
     * @return void
278
     */
279
    private function setRelations($route)
280
    {
281
        $route           = $route !== 'index' ? $route : 'list';
282
        $relations       = Arr::get($this->config['relations'], $this->modelName, false);
283
        $this->relations = $relations && isset($relations[$route]) ? $relations[$route] : [];
284
    }
285
286
    /**
287
     * Update the logged in user locale and time zone.
288
     *
289
     * @param  object $user
290
     * @return void
291
     */
292
    private function updateLocaleAndTimezone($user)
293
    {
294
        $update   = false;
295
        $locale   = \Session::get('locale');
296
        $timezone = \Session::get('time-zone');
297
        if ($locale && $locale !== 'all' && $locale !== $user->locale) {
298
            $user->locale = $locale;
299
            $update       = true;
300
        }
301
302
        if ($timezone && $timezone !== $user->timezone) {
303
            $user->timezone = $timezone;
304
            $update       = true;
305
        }
306
307
        if ($update) {
308
            $user->save();
309
        }
310
    }
311
}
312