| Code Coverage | ||||||||||
| Lines | Functions and Methods | Classes and Traits | ||||||||
| Total |  | 41.46% | 34 / 82 |  | 16.67% | 3 / 18 | CRAP |  | 0.00% | 0 / 1 | 
| BaseController |  | 41.46% | 34 / 82 |  | 16.67% | 3 / 18 | 280.71 |  | 0.00% | 0 / 1 | 
| sendResponse |  | 100.00% | 3 / 3 |  | 100.00% | 1 / 1 | 2 | |||
| sendError |  | 100.00% | 1 / 1 |  | 100.00% | 1 / 1 | 1 | |||
| createUser |  | 0.00% | 0 / 6 |  | 0.00% | 0 / 1 | 6 | |||
| updateUserPassword |  | 0.00% | 0 / 9 |  | 0.00% | 0 / 1 | 12 | |||
| getLoggedInUserId |  | 75.00% | 3 / 4 |  | 0.00% | 0 / 1 | 2.06 | |||
| __validateJson |  | 100.00% | 11 / 11 |  | 100.00% | 1 / 1 | 4 | |||
| __validateContentTypeApplicationJson |  | 0.00% | 0 / 1 |  | 0.00% | 0 / 1 | 2 | |||
| createPaginationFromOrm |  | 83.33% | 10 / 12 |  | 0.00% | 0 / 1 | 3.04 | |||
| saltHash |  | 0.00% | 0 / 1 |  | 0.00% | 0 / 1 | 2 | |||
| __validateSaltHash |  | 0.00% | 0 / 1 |  | 0.00% | 0 / 1 | 2 | |||
| __dateMidnightZeroOne |  | 0.00% | 0 / 3 |  | 0.00% | 0 / 1 | 2 | |||
| __dateMidnightZeroZero |  | 0.00% | 0 / 3 |  | 0.00% | 0 / 1 | 2 | |||
| __dateElevenFiftyNine |  | 0.00% | 0 / 3 |  | 0.00% | 0 / 1 | 2 | |||
| __getAllDates |  | 0.00% | 0 / 9 |  | 0.00% | 0 / 1 | 6 | |||
| __validYYYYMMDDFormat |  | 0.00% | 0 / 3 |  | 0.00% | 0 / 1 | 6 | |||
| __validateDateTime |  | 0.00% | 0 / 2 |  | 0.00% | 0 / 1 | 6 | |||
| __validateAndExtractPaginationData |  | 75.00% | 6 / 8 |  | 0.00% | 0 / 1 | 5.39 | |||
| __getMe |  | 0.00% | 0 / 2 |  | 0.00% | 0 / 1 | 2 | |||
| 1 | <?php | 
| 2 | |
| 3 | namespace App\Http\Controllers\api; | 
| 4 | |
| 5 | use Illuminate\Http\Request; | 
| 6 | use Illuminate\Http\JsonResponse; | 
| 7 | use App\Http\Controllers\Controller as Controller; | 
| 8 | use Validator; | 
| 9 | use App\Models\User; | 
| 10 | use App\Models\Role; | 
| 11 | |
| 12 | class BaseController extends Controller | 
| 13 | { | 
| 14 | /** | 
| 15 | * success response method. | 
| 16 | * | 
| 17 | * @param Int $status The HTTP status code of the response, ie 200 | 
| 18 | * @param Mixed $data The data object to return under 'data' | 
| 19 | * @param Array $hateoas An array of HATEOAS data, optional | 
| 20 | * @return JsonResponse | 
| 21 | */ | 
| 22 | public function sendResponse(int $status, $data, array $hateoas = array()):JsonResponse | 
| 23 | { | 
| 24 | $response = [ | 
| 25 | 'data' => $data, | 
| 26 | ]; | 
| 27 | |
| 28 | if (count($hateoas) > 0) { | 
| 29 | $response['links'] = $hateoas; | 
| 30 | } | 
| 31 | |
| 32 | return response()->json($response, $status); | 
| 33 | } // sendResponse | 
| 34 | |
| 35 | |
| 36 | /** | 
| 37 | * return error response. | 
| 38 | * | 
| 39 | * @param Int $status | 
| 40 | * @param Mixed $error | 
| 41 | * @param Mixed $details | 
| 42 | * @return JsonResponse | 
| 43 | */ | 
| 44 | public function sendError(int $status, $error, $details=null):JsonResponse | 
| 45 | { | 
| 46 | $response = [ | 
| 47 | 'error' => $error, | 
| 48 | 'details' => $details, | 
| 49 | ]; | 
| 50 | |
| 51 | return response()->json($response, $status); | 
| 52 | } // sendError | 
| 53 | |
| 54 | |
| 55 | /** | 
| 56 | * Creates a login user of a given role | 
| 57 | * | 
| 58 | * @param Array $userData ["name", "email", "password", "c_password"] | 
| 59 | * @param Int $roleId | 
| 60 | * @return Int The user id | 
| 61 | */ | 
| 62 | protected function createUser(array $userData, Int $roleId = 2):Int | 
| 63 | { | 
| 64 | $userData['password'] = bcrypt($userData['password']); | 
| 65 | |
| 66 | // did you run php artisan passport:install? | 
| 67 | try { | 
| 68 | $user = User::create($userData); | 
| 69 | //$user->createToken('MyApp')->accessToken; | 
| 70 | //$user->role_id = $roleId; | 
| 71 | $user->save(); | 
| 72 | return $user->id; | 
| 73 | } | 
| 74 | // catch duplicate entry | 
| 75 | catch (\Illuminate\Database\QueryException $e) { | 
| 76 | return -1; | 
| 77 | } | 
| 78 | } // createUser | 
| 79 | |
| 80 | |
| 81 | /** | 
| 82 | * Updates the login password for a user. Used with putCustomersCorporateContact. | 
| 83 | * | 
| 84 | * @param string $password | 
| 85 | * @return Boolean | 
| 86 | */ | 
| 87 | protected function updateUserPassword(string $email, string $password) | 
| 88 | { | 
| 89 | $enc = bcrypt($password); | 
| 90 | |
| 91 | // did you run php artisan passport:install? | 
| 92 | try { | 
| 93 | /** | 
| 94 | * Update user login account | 
| 95 | */ | 
| 96 | $user = User::where('email', $email)->first(); | 
| 97 | if (!$user) { | 
| 98 | return false; | 
| 99 | } | 
| 100 | $user->password = $enc; | 
| 101 | $user->save(); | 
| 102 | return true; | 
| 103 | } | 
| 104 | // catch any errors | 
| 105 | catch (\Illuminate\Database\QueryException $e) { | 
| 106 | return false; | 
| 107 | } | 
| 108 | } // updateUserPassword | 
| 109 | |
| 110 | |
| 111 | /** | 
| 112 | * Tests if the role of the logged-in user is the same as the role passed as arg | 
| 113 | * | 
| 114 | * Modified: also returns true if the user is 'admin' | 
| 115 | * | 
| 116 | * Roles are stored as env constants in .env where they are mapped to the name in the `roles` table. | 
| 117 | * | 
| 118 | * @param String $role The role of the user, ie 'installer', 'lead_manager' or 'admin' | 
| 119 | * @return bool | 
| 120 | * @author gbh | 
| 121 | protected function permissionsEqual(string $role):bool | 
| 122 | { | 
| 123 | $role_id = Role::where('name', config('app.roles.'.$role))->get()->pluck('id')[0]; // @not-phpstan-ignore-line | 
| 124 | $admin_id = Role::where('name', config('app.roles.admin'))->get()->pluck('id')[0]; // @not-phpstan-ignore-line | 
| 125 | return (auth()->guard('api')->user()->role_id == $role_id || auth()->guard('api')->user()->role_id == $admin_id); | 
| 126 | } | 
| 127 | */ | 
| 128 | |
| 129 | |
| 130 | /** | 
| 131 | * Tests if the role of the logged-in user is exactly the same as role arg, excluding admin. | 
| 132 | * | 
| 133 | * Roles are stored as env constants in .env where they are mapped to the name in the `roles` table. | 
| 134 | * | 
| 135 | * @param String $role The role of the user, ie 'installer', 'lead_manager' or 'admin' | 
| 136 | * @return bool | 
| 137 | * @author arn | 
| 138 | protected function permissionsExactly(string $role):bool | 
| 139 | { | 
| 140 | $role_id = Role::where('name', config('app.roles.'.$role))->get()->pluck('id')[0]; // @not-phpstan-ignore-line | 
| 141 | return auth()->guard('api')->user()->role_id == $role_id; | 
| 142 | } | 
| 143 | */ | 
| 144 | |
| 145 | |
| 146 | /** | 
| 147 | * Tests if the role of the logged-in user is the same or greater than the role passed as arg | 
| 148 | * | 
| 149 | * Roles are stored as env constants in .env where they are mapped to the name in the `roles` table. | 
| 150 | * | 
| 151 | * @param String $role The role of the user, ie 'employee', 'support' or 'admin' | 
| 152 | * @return bool | 
| 153 | * @author gbh | 
| 154 | protected function permissionsAtLeast(string $role) | 
| 155 | { | 
| 156 | $role_id = Role::where('name', config('app.roles.'.$role))->get()->pluck('id')[0]; // @not-phpstan-ignore-line | 
| 157 | return (int)auth()->guard('api')->user()->role_id >= $role_id; | 
| 158 | } | 
| 159 | */ | 
| 160 | |
| 161 | /** | 
| 162 | * Get user id of logged-in user. | 
| 163 | * | 
| 164 | * @return Mixed Int user_id or false | 
| 165 | * @author arn | 
| 166 | */ | 
| 167 | protected function getLoggedInUserId() | 
| 168 | { | 
| 169 | $currentUser = auth()->guard('api')->user(); | 
| 170 | |
| 171 | /** | 
| 172 | * If authenticated user is not found, do not authenticate. | 
| 173 | */ | 
| 174 | if (!$currentUser) { | 
| 175 | return false; | 
| 176 | } | 
| 177 | |
| 178 | return $currentUser->id; | 
| 179 | } // getLoggedInUserId | 
| 180 | |
| 181 | |
| 182 | /** | 
| 183 | * Validates a json string against a set of Laravel validation rules. | 
| 184 | * | 
| 185 | * @note Only flat json at this point | 
| 186 | * | 
| 187 | * @param Array $rules The Laravel validator ruleset to validate against | 
| 188 | * @param Request $request The request object laravel injects into the controller | 
| 189 | * @return mixed `boolean` true on success, `Array` on failure | 
| 190 | */ | 
| 191 | protected function __validateJson(array $rules, Request $request) | 
| 192 | { | 
| 193 | $requestContent = $request->getContent(); | 
| 194 | $data = json_decode($requestContent, true); | 
| 195 | $data = $data ? $data : []; | 
| 196 | $validator = Validator::make($data, $rules); | 
| 197 | |
| 198 | if ($validator->passes()) { | 
| 199 | return true; | 
| 200 | } else { | 
| 201 | $errors = $validator->errors(); | 
| 202 | $errorArray = []; | 
| 203 | foreach ($errors->getMessages() as $key => $message) { | 
| 204 | $errorArray[$key] = $message; | 
| 205 | } | 
| 206 | return $errorArray; | 
| 207 | } | 
| 208 | } //validateJson | 
| 209 | |
| 210 | |
| 211 | /** | 
| 212 | * Returns true if the header for Content-Type is 'application/json' | 
| 213 | * | 
| 214 | * @param Request $request | 
| 215 | * @return bool | 
| 216 | */ | 
| 217 | protected function __validateContentTypeApplicationJson(Request $request):bool | 
| 218 | { | 
| 219 | return strtolower($request->headers->get('Content-Type')) == "application/json"; | 
| 220 | } // validateContentTypeApplicationJson | 
| 221 | |
| 222 | |
| 223 | /** | 
| 224 | * Makes a nice hateoas array from LengthAwarePaginator collection | 
| 225 | * | 
| 226 | * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginationCollection The return collection from Model::paginate() | 
| 227 | * @return Array | 
| 228 | */ | 
| 229 | protected function createPaginationFromOrm(\Illuminate\Contracts\Pagination\LengthAwarePaginator $paginationCollection) | 
| 230 | { | 
| 231 | $hateoas = []; | 
| 232 | if ($paginationCollection->hasMorePages()) { | 
| 233 | $hateoas['next_page'] = $paginationCollection->nextPageUrl(). | 
| 234 | "&size=". | 
| 235 | $paginationCollection->count(); | 
| 236 | } | 
| 237 | if ($paginationCollection->previousPageUrl()) { | 
| 238 | $hateoas['previous_page'] = $paginationCollection->previousPageUrl(). | 
| 239 | "&size=". | 
| 240 | $paginationCollection->count(); | 
| 241 | } | 
| 242 | $hateoas['has_more'] = $paginationCollection->hasMorePages(); | 
| 243 | $hateoas['current_page'] = $paginationCollection->currentPage(); | 
| 244 | $hateoas['last_page'] = $paginationCollection->lastPage(); | 
| 245 | $hateoas['current_size'] = $paginationCollection->perPage(); | 
| 246 | |
| 247 | return $hateoas; | 
| 248 | } // createPaginationFromOrm | 
| 249 | |
| 250 | |
| 251 | /** | 
| 252 | * Hashes a value with our configured secret_salt | 
| 253 | * | 
| 254 | * @param String $toHash The value to hash | 
| 255 | * @return String | 
| 256 | */ | 
| 257 | protected function saltHash(String $toHash):String | 
| 258 | { | 
| 259 | return md5($toHash.config('app.secret_salt')); | 
| 260 | } // saltHash | 
| 261 | |
| 262 | |
| 263 | /** | 
| 264 | * Tests if the hash $hash is valid for the value $value | 
| 265 | * | 
| 266 | * @param String $value | 
| 267 | * @param String $hash | 
| 268 | * @return boolean | 
| 269 | */ | 
| 270 | protected function __validateSaltHash(String $value, String $hash):bool | 
| 271 | { | 
| 272 | return md5($value.config('app.secret_salt')) == $hash; | 
| 273 | } // validateSaltHash | 
| 274 | |
| 275 | |
| 276 | |
| 277 | /** | 
| 278 | * Sets the time of a date string to midnight plus one second. | 
| 279 | * | 
| 280 | * eg. '2020-02-23 13:45:23' => '2020-02-23 00:00:01' | 
| 281 | * | 
| 282 | * @param String $date | 
| 283 | * @return String | 
| 284 | */ | 
| 285 | protected function __dateMidnightZeroOne(String $date):String | 
| 286 | { | 
| 287 | $dateObj = new \DateTime($date); | 
| 288 | $dateObj->setTime(00, 00, 01); | 
| 289 | return $dateObj->format('Y-m-d H:i:s'); | 
| 290 | } | 
| 291 | |
| 292 | /** | 
| 293 | * Sets the time of a date string to midnight | 
| 294 | * | 
| 295 | * eg. '2020-02-23 13:45:23' => '2020-02-23 00:00:00' | 
| 296 | * | 
| 297 | * @param String $date | 
| 298 | * @return String | 
| 299 | */ | 
| 300 | protected function __dateMidnightZeroZero(String $date):String | 
| 301 | { | 
| 302 | $dateObj = new \DateTime($date); | 
| 303 | $dateObj->setTime(00, 00, 00); | 
| 304 | return $dateObj->format('Y-m-d H:i:s'); | 
| 305 | } | 
| 306 | |
| 307 | |
| 308 | /** | 
| 309 | * Sets the time of a date string to 11:59:59 | 
| 310 | * | 
| 311 | * eg. '2020-02-23 13:45:23' => '2020-02-23 23:59:59' | 
| 312 | * | 
| 313 | * @param String $date | 
| 314 | * @return String | 
| 315 | */ | 
| 316 | protected function __dateElevenFiftyNine(String $date):String | 
| 317 | { | 
| 318 | $dateObj = new \DateTime($date); | 
| 319 | $dateObj->setTime(23, 59, 59); | 
| 320 | return $dateObj->format('Y-m-d H:i:s'); | 
| 321 | } | 
| 322 | |
| 323 | |
| 324 | /** | 
| 325 | * Get an array of all dates as YYYY-MM-DD between start date and end date | 
| 326 | * | 
| 327 | * @param String $startdate | 
| 328 | * @param String $enddate | 
| 329 | * @return Array | 
| 330 | */ | 
| 331 | protected function __getAllDates(String $startdate, String $enddate):array | 
| 332 | { | 
| 333 | $begin = new \DateTime($startdate); | 
| 334 | $end = new \DateTime($enddate); | 
| 335 | $end = $end->modify('+1 day'); | 
| 336 | $interval = new \DateInterval('P1D'); | 
| 337 | $daterange = new \DatePeriod($begin, $interval, $end); | 
| 338 | |
| 339 | $returnableDateRange = []; | 
| 340 | foreach ($daterange as $d) { | 
| 341 | $returnableDateRange[] = $d->format("Y-m-d"); | 
| 342 | } | 
| 343 | |
| 344 | return $returnableDateRange; | 
| 345 | } // __getAllDates | 
| 346 | |
| 347 | |
| 348 | /** | 
| 349 | * Validates that a string is in yyyy-mm-dd format | 
| 350 | * | 
| 351 | * @param String $date The string to validate | 
| 352 | * @return boolean | 
| 353 | */ | 
| 354 | public function __validYYYYMMDDFormat($date):bool | 
| 355 | { | 
| 356 | $format = 'Y-m-d'; | 
| 357 | $d = \DateTime::createFromFormat($format, $date); | 
| 358 | return $d && $d->format($format) == $date; | 
| 359 | } // __validYYYYMMDDFormat | 
| 360 | |
| 361 | |
| 362 | /** | 
| 363 | * Validates that a string is in yyyy-mm-dd h:i:s format | 
| 364 | */ | 
| 365 | public function __validateDateTime(String $date, String $format = 'Y-m-d H:i:s'):bool | 
| 366 | { | 
| 367 | $d = \DateTime::createFromFormat($format, $date); | 
| 368 | return $d && $d->format($format) == $date; | 
| 369 | } // __validateDateTime | 
| 370 | |
| 371 | |
| 372 | /** | 
| 373 | * Validate pagination query string in a request. | 
| 374 | * This will return the object [ 'page' => A, 'size' => B ] on a valid request, | 
| 375 | * or an error response on failure. | 
| 376 | * | 
| 377 | * @return Mixed | 
| 378 | */ | 
| 379 | protected function __validateAndExtractPaginationData(Request $request):array | 
| 380 | { | 
| 381 | $page = $request->query('page') !== null ? (int)$request->query('page') : config('app.pagination.default_page_number'); | 
| 382 | $size = $request->query('size') !== null ? (int)$request->query('size') : config('app.pagination.default_page_size'); | 
| 383 | |
| 384 | if ($page < 1) { | 
| 385 | $page = 1; | 
| 386 | } | 
| 387 | |
| 388 | if ($size < 1) { | 
| 389 | $size = 1; | 
| 390 | } | 
| 391 | |
| 392 | $request->page = $page; | 
| 393 | |
| 394 | return [ | 
| 395 | 'page' => $page, | 
| 396 | 'size' => $size | 
| 397 | ]; | 
| 398 | } // __validateAndExtractPaginationData | 
| 399 | |
| 400 | |
| 401 | /** | 
| 402 | * Selects and returns the current session user | 
| 403 | * | 
| 404 | * @return User | 
| 405 | */ | 
| 406 | protected function __getMe():User | 
| 407 | { | 
| 408 | $user = User::whereMe()->first(); | 
| 409 | return $user; | 
| 410 | } | 
| 411 | } // BaseController |