From 66e6935e4215d88f3ca733f74f66dc4592cf1646 Mon Sep 17 00:00:00 2001 From: Alexis Gousseau Date: Tue, 30 Jan 2024 10:43:25 +0100 Subject: [PATCH] add phpstan and fix all errors --- .../issue_templates}/bug.md | 0 .../issue_templates}/feature.md | 0 app/Console/Commands/UserCreate.php | 12 +- .../ActivityLogs/ActivityLogsEventEnum.php | 2 + app/Enums/Country.php | 2 + app/Enums/InputType.php | 9 +- app/Enums/StaticPageType.php | 2 + app/Enums/Theme/BootstrapThemeEnum.php | 2 + app/Enums/Users/RoleEnum.php | 2 + .../Controllers/Bo/ActivityLogController.php | 2 +- .../Bo/Auth/ResetPasswordController.php | 3 +- .../Controllers/Bo/DashboardController.php | 3 +- .../Controllers/Bo/StaticPageController.php | 2 +- app/Http/Controllers/Bo/UserController.php | 2 +- app/Http/Controllers/Controller.php | 35 ++- .../StaticPages/UpdateStaticPageRequest.php | 2 +- .../Requests/Bo/UpdateChangeOrderRequest.php | 2 +- .../Requests/Bo/UpdateMiniCrudRequest.php | 2 +- .../Requests/Bo/Users/StoreUserRequest.php | 1 + .../Requests/Bo/Users/UpdateUserRequest.php | 6 +- app/Lib/Helpers/ExceptionsHelper.php | 2 +- app/Lib/Helpers/FileStorageHelper.php | 5 +- app/Lib/Helpers/ToolboxHelper.php | 71 ++--- app/Models/ActivityLog.php | 27 +- app/Models/StaticPage.php | 4 +- app/Models/User.php | 4 +- app/Providers/RouteServiceProvider.php | 6 +- app/Providers/TranslationServiceProvider.php | 31 ++- app/Traits/Controllers/ChangesModelOrder.php | 10 +- .../Controllers/UpdateModelPublished.php | 3 +- app/Traits/Enums/BaseEnum.php | 6 +- app/Traits/Models/IsCachedAsCollection.php | 3 +- app/Traits/Requests/HasPicture.php | 4 +- composer.json | 1 + composer.lock | 253 +++++++++++++++++- phpstan.neon | 10 + 36 files changed, 412 insertions(+), 119 deletions(-) rename {issue_templates => .gitlab/issue_templates}/bug.md (100%) rename {issue_templates => .gitlab/issue_templates}/feature.md (100%) create mode 100644 phpstan.neon diff --git a/issue_templates/bug.md b/.gitlab/issue_templates/bug.md similarity index 100% rename from issue_templates/bug.md rename to .gitlab/issue_templates/bug.md diff --git a/issue_templates/feature.md b/.gitlab/issue_templates/feature.md similarity index 100% rename from issue_templates/feature.md rename to .gitlab/issue_templates/feature.md diff --git a/app/Console/Commands/UserCreate.php b/app/Console/Commands/UserCreate.php index 2bf8d407..cedc7733 100644 --- a/app/Console/Commands/UserCreate.php +++ b/app/Console/Commands/UserCreate.php @@ -29,35 +29,35 @@ class UserCreate extends Command /** * The first name of the new user. * - * @var string + * @var string|null */ protected $first_name; /** * The last name of the new user. * - * @var string + * @var string|null */ protected $last_name; /** * The email of the new user. * - * @var string + * @var string|null */ protected $email; /** * The password of the new user. * - * @var string + * @var string|null */ protected $password; /** * The role of the new user. * - * @var string + * @var string|null */ protected $role; @@ -226,7 +226,7 @@ class UserCreate extends Command $this->role = $tmp; } catch (ValidationException $e) { $this->error(sprintf( - 'Please choose from the selection', + 'Please choose from the selection %s', \implode(',', collect($e->errors())->flatten()->all()) )); continue; diff --git a/app/Enums/ActivityLogs/ActivityLogsEventEnum.php b/app/Enums/ActivityLogs/ActivityLogsEventEnum.php index ebb098c0..df947592 100644 --- a/app/Enums/ActivityLogs/ActivityLogsEventEnum.php +++ b/app/Enums/ActivityLogs/ActivityLogsEventEnum.php @@ -15,6 +15,8 @@ enum ActivityLogsEventEnum: int /** * Optionnal labels definition + * + * @phpstan-ignore-next-line */ private const LABELS = [ self::created->name => 'Création', diff --git a/app/Enums/Country.php b/app/Enums/Country.php index 7d0c40b2..4a092956 100644 --- a/app/Enums/Country.php +++ b/app/Enums/Country.php @@ -260,6 +260,8 @@ enum Country: int /** * Optionnal labels definition + * + * @phpstan-ignore-next-line */ private const LABELS = [ self::afghanistan->name => 'Afghanistan', diff --git a/app/Enums/InputType.php b/app/Enums/InputType.php index 0b59d298..ad7c44bc 100644 --- a/app/Enums/InputType.php +++ b/app/Enums/InputType.php @@ -21,10 +21,7 @@ enum InputType: int case string = 11; case text = 12; case url = 13; - /** Vimeo only */ - case videoVimeo = 14; - /** Youtube only */ - case videoYoutube = 15; - /** Youtube or Vimeo. */ - case video = 16; + case videoVimeo = 14; + case videoYoutube = 15; + case video = 16; } diff --git a/app/Enums/StaticPageType.php b/app/Enums/StaticPageType.php index 060203be..89fec570 100644 --- a/app/Enums/StaticPageType.php +++ b/app/Enums/StaticPageType.php @@ -14,6 +14,8 @@ enum StaticPageType: int /** * Optionnal labels definition. + * + * @phpstan-ignore-next-line */ private const LABELS = [ self::contact->name => 'Contact', diff --git a/app/Enums/Theme/BootstrapThemeEnum.php b/app/Enums/Theme/BootstrapThemeEnum.php index 7e61f3c2..2ae46d21 100644 --- a/app/Enums/Theme/BootstrapThemeEnum.php +++ b/app/Enums/Theme/BootstrapThemeEnum.php @@ -14,6 +14,8 @@ enum BootstrapThemeEnum: int /** * Optionnal labels definition + * + * @phpstan-ignore-next-line */ private const LABELS = [ self::light->name => 'enums.bootstrap-theme.light', diff --git a/app/Enums/Users/RoleEnum.php b/app/Enums/Users/RoleEnum.php index 03a4af09..999bb6ad 100644 --- a/app/Enums/Users/RoleEnum.php +++ b/app/Enums/Users/RoleEnum.php @@ -14,6 +14,8 @@ enum RoleEnum: int /** * Optionnal labels definition. + * + * @phpstan-ignore-next-line */ private const LABELS = [ self::conceptor->name => 'enums.user-role.conceptor', diff --git a/app/Http/Controllers/Bo/ActivityLogController.php b/app/Http/Controllers/Bo/ActivityLogController.php index ba7b3758..97d66050 100644 --- a/app/Http/Controllers/Bo/ActivityLogController.php +++ b/app/Http/Controllers/Bo/ActivityLogController.php @@ -51,7 +51,7 @@ class ActivityLogController extends Controller /** * Show the form for editing the specified resource. * - * @param App\Models\ActivityLog $activity_log + * @param \App\Models\ActivityLog $activity_log * @return \Illuminate\Contracts\View\View */ public function show(ActivityLog $activity_log): \Illuminate\Contracts\View\View diff --git a/app/Http/Controllers/Bo/Auth/ResetPasswordController.php b/app/Http/Controllers/Bo/Auth/ResetPasswordController.php index 03340fc6..8d6793d3 100644 --- a/app/Http/Controllers/Bo/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Bo/Auth/ResetPasswordController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\Bo\Auth; use App\Http\Controllers\Controller; -use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Support\Facades\Auth; @@ -16,7 +15,7 @@ class ResetPasswordController extends Controller * * @return \Illuminate\Contracts\Auth\StatefulGuard */ - protected function guard(): StatefulGuard + protected function guard(): \Illuminate\Contracts\Auth\StatefulGuard { return Auth::guard('backend'); } diff --git a/app/Http/Controllers/Bo/DashboardController.php b/app/Http/Controllers/Bo/DashboardController.php index 960a9c18..e28be1ba 100644 --- a/app/Http/Controllers/Bo/DashboardController.php +++ b/app/Http/Controllers/Bo/DashboardController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\Bo; use App\Http\Controllers\Controller; -use Illuminate\Contracts\View\View; class DashboardController extends Controller { @@ -12,7 +11,7 @@ class DashboardController extends Controller * * @return \Illuminate\Contracts\View\View */ - public function index(): View + public function index(): \Illuminate\Contracts\View\View { return view('bo.pages.dashboard'); } diff --git a/app/Http/Controllers/Bo/StaticPageController.php b/app/Http/Controllers/Bo/StaticPageController.php index 55775dcc..9b92073d 100644 --- a/app/Http/Controllers/Bo/StaticPageController.php +++ b/app/Http/Controllers/Bo/StaticPageController.php @@ -56,7 +56,7 @@ class StaticPageController extends Controller /** * Show the form for editing the specified resource. * - * @param App\Models\StaticPage $static_page + * @param \App\Models\StaticPage $static_page * @return \Illuminate\Contracts\View\View */ public function edit(StaticPage $static_page): \Illuminate\Contracts\View\View diff --git a/app/Http/Controllers/Bo/UserController.php b/app/Http/Controllers/Bo/UserController.php index a723403e..2055644d 100644 --- a/app/Http/Controllers/Bo/UserController.php +++ b/app/Http/Controllers/Bo/UserController.php @@ -102,7 +102,7 @@ class UserController extends Controller /** * Show the form for editing the specified resource. * - * @param App\Models\User $user + * @param \App\Models\User $user * @return \Illuminate\Contracts\View\View */ public function edit(User $user): \Illuminate\Contracts\View\View diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 768c25f8..2ae462dd 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -94,7 +94,7 @@ class Controller extends BaseController return $query; } // Get models with relation's name/label. - if (Str::endsWith($field, '_id') && $query->getModel()->has(Str::remove('_id', $field))) { + if (Str::endsWith($field, '_id')) { $query->orWhereHas(Str::remove('_id', $field), function ($queryRelation) use ($field, $search) { if (Schema::hasColumn(Str::remove('_id', $field) . 's', 'name')) { $queryRelation->where('name', 'like', '%' . $search . '%'); @@ -122,12 +122,15 @@ class Controller extends BaseController */ protected function getSearchValue(Builder $query, string $search, string $field): string|array { + $cast = $query->getModel()->getCasts()[$field] ?? null; if ( count($query->getModel()->getCasts()) and // Check if the model has casts. - isset($query->getModel()->getCasts()[$field]) and // Check if there is cast about specific field. - enum_exists($query->getModel()->getCasts()[$field]) // Check if the cast is an enum. + $cast and // Check if there is cast about specific field. + enum_exists($cast) // Check if the cast is an enum. ) { - $cases = collect($query->getModel()->getCasts()[$field]::toArray()); + /** @var \App\Traits\Enums $cast */ + // @phpstan-ignore-next-line + $cases = collect($cast::toArray()); $enum = $cases->filter(function ($item) use ($search) { return preg_match('/' . Str::lower($search) . '/', Str::lower($item->label)); }); @@ -148,12 +151,12 @@ class Controller extends BaseController { $rName = request()->route()->getName(); $table = $query->getModel()->getTable(); - if (request()->sort_col) { - Session::put("$rName.sort_col", request()->sort_col); + if (request()->input('sort_col')) { + Session::put("$rName.sort_col", request()->input('sort_col')); Session::put("$rName.sorted", true); } - if (request()->sort_way) { - Session::put("$rName.sort_way", request()->sort_way); + if (request()->input('sort_way')) { + Session::put("$rName.sort_way", request()->input('sort_way')); Session::put("$rName.sorted", true); } if (request()->rst) { @@ -161,12 +164,16 @@ class Controller extends BaseController Session::remove("$rName.sort_col"); Session::remove("$rName.sort_way"); } - if (request()->sort_col and request()->sort_way and Schema::hasColumn($table, request()->sort_col)) { - if ( - !isset($ignore) or - (isset($ignore) and !in_array(request()->sort_col, $ignore)) - ) { - $query = $query->orderBy(\sprintf("$table.%s", request()->sort_col), request()->sort_way); + if ( + request()->input('sort_col') and + request()->input('sort_way') and + Schema::hasColumn($table, request()->input('sort_col')) + ) { + if (!in_array(request()->input('sort_col'), $ignore)) { + $query = $query->orderBy( + \sprintf("$table.%s", request()->input('sort_col')), + request()->input('sort_way') + ); } } elseif (Schema::hasColumn($table, 'order')) { $query = $query->orderBy('order', 'ASC'); diff --git a/app/Http/Requests/Bo/StaticPages/UpdateStaticPageRequest.php b/app/Http/Requests/Bo/StaticPages/UpdateStaticPageRequest.php index a309bc42..ebb0746b 100644 --- a/app/Http/Requests/Bo/StaticPages/UpdateStaticPageRequest.php +++ b/app/Http/Requests/Bo/StaticPages/UpdateStaticPageRequest.php @@ -26,7 +26,7 @@ class UpdateStaticPageRequest extends FormRequest public function prepareForValidation(): void { $this->merge([ - 'content' => (string)Str::of($this->input('content')) + 'content' => Str::of($this->input('content'))->value() ]); } diff --git a/app/Http/Requests/Bo/UpdateChangeOrderRequest.php b/app/Http/Requests/Bo/UpdateChangeOrderRequest.php index 48f10c3b..d6be7271 100644 --- a/app/Http/Requests/Bo/UpdateChangeOrderRequest.php +++ b/app/Http/Requests/Bo/UpdateChangeOrderRequest.php @@ -24,7 +24,7 @@ class UpdateChangeOrderRequest extends FormRequest protected function prepareForValidation(): void { $this->merge([ - 'direction' => $this->string('direction') === 'up' ? true : false + 'direction' => $this->route('direction') === 'up' ? true : false ]); } diff --git a/app/Http/Requests/Bo/UpdateMiniCrudRequest.php b/app/Http/Requests/Bo/UpdateMiniCrudRequest.php index 6f0351d0..4b3419d0 100644 --- a/app/Http/Requests/Bo/UpdateMiniCrudRequest.php +++ b/app/Http/Requests/Bo/UpdateMiniCrudRequest.php @@ -108,7 +108,7 @@ abstract class UpdateMiniCrudRequest extends FormRequest $rules = array_merge($rules, [ "data.$iptName.value" => [ function (string $attribute, $value, callable $fail) use ($sizes) { - return ToolboxHelper::validatePicture($attribute, $value, $fail, $sizes); + ToolboxHelper::validatePicture($attribute, $value, $fail, $sizes); } ], $this->compileValidate( diff --git a/app/Http/Requests/Bo/Users/StoreUserRequest.php b/app/Http/Requests/Bo/Users/StoreUserRequest.php index 3253b459..0a9b3235 100644 --- a/app/Http/Requests/Bo/Users/StoreUserRequest.php +++ b/app/Http/Requests/Bo/Users/StoreUserRequest.php @@ -3,6 +3,7 @@ namespace App\Http\Requests\Bo\Users; use App\Enums\Users\RoleEnum; +use App\Models\User; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Facades\Gate; use Illuminate\Validation\Rules\Enum; diff --git a/app/Http/Requests/Bo/Users/UpdateUserRequest.php b/app/Http/Requests/Bo/Users/UpdateUserRequest.php index bdd24894..6c587c91 100644 --- a/app/Http/Requests/Bo/Users/UpdateUserRequest.php +++ b/app/Http/Requests/Bo/Users/UpdateUserRequest.php @@ -28,9 +28,9 @@ class UpdateUserRequest extends StoreUserRequest $this->merge([ 'published' => $this->boolean('published'), 'password' => $this->input('password') ?? - $this->route('user')->password, + \optional($this->route('user'))->password, 'password_confirmation' => $this->input('password_confirmation') ?? - $this->route('user')->password + \optional($this->route('user'))->password ]); } @@ -45,7 +45,7 @@ class UpdateUserRequest extends StoreUserRequest 'email' => [ 'required', 'email:rfc,strict,dns,spoof,filter', - Rule::unique('users', 'email')->ignore($this->route('user')->getRouteKey()) + Rule::unique('users', 'email')->ignore(\optional($this->route('user'))->getRouteKey()) ], 'password' => [ 'required', 'required_with:password_confirmation', 'confirmed', 'max:255', Password::min(8) diff --git a/app/Lib/Helpers/ExceptionsHelper.php b/app/Lib/Helpers/ExceptionsHelper.php index 4813275a..30deb548 100644 --- a/app/Lib/Helpers/ExceptionsHelper.php +++ b/app/Lib/Helpers/ExceptionsHelper.php @@ -145,7 +145,7 @@ class ExceptionsHelper $traceStr .= self::handleArgs($stack); } $traceStr .= ")\n"; - } elseif (isset($stack['function'])) { + } else { $traceStr .= "{$stack['function']}("; if (isset($stack['args'])) { $traceStr .= self::handleArgs($stack); diff --git a/app/Lib/Helpers/FileStorageHelper.php b/app/Lib/Helpers/FileStorageHelper.php index 08a9f8c7..1254ec36 100644 --- a/app/Lib/Helpers/FileStorageHelper.php +++ b/app/Lib/Helpers/FileStorageHelper.php @@ -322,8 +322,7 @@ class FileStorageHelper $folderPath = self::getStoragePath( $private ? 'app/private/modelfiles' : 'app/public/modelfiles', $tableName, - $filename, - $private + $filename ); $filename = self::getFileUniqueName($folderPath, $filename); return "{$folderPath}/{$filename}"; @@ -418,7 +417,7 @@ class FileStorageHelper $filename = Str::of($filename)->ltrim('.-'); // * Optional beautification if ($beautify) { - $filename = static::beautifyFilename($filename); + $filename = self::beautifyFilename($filename); } // * Maximize filename length to 255 bytes http://serverfault.com/a/9548/44086 /** @var string */ diff --git a/app/Lib/Helpers/ToolboxHelper.php b/app/Lib/Helpers/ToolboxHelper.php index 29e25c69..71dcd4f1 100644 --- a/app/Lib/Helpers/ToolboxHelper.php +++ b/app/Lib/Helpers/ToolboxHelper.php @@ -205,11 +205,10 @@ class ToolboxHelper $url = $match; try { $request = Request::create($url); - // If a route is match then it do not throws exception. - if ( - \parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) && - $routes->match($request) - ) { + // Assert route matches existing routes. + $routes->match($request); + // ? Is url internal ? + if (\parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST)) { // Removes the matched url. throw ValidationException::withMessages([ $field => trans( @@ -235,14 +234,14 @@ class ToolboxHelper * @param array|string $replace * @param array|string $subject * @param integer $count - * @return array|string + * @return array|string|false */ public static function mbReplace( array|string $search, array|string $replace, array|string $subject, int &$count = 0 - ): array|string { + ): array|string|false { if (!is_array($search) && is_array($replace)) { return false; } @@ -318,10 +317,17 @@ class ToolboxHelper */ public static function getOriginal(Model $model, string $attribute): mixed { - if (\in_array('Spatie\Translatable\HasTranslations', \class_uses_recursive($model))) { + if ( + \in_array('Spatie\Translatable\HasTranslations', \class_uses_recursive($model)) and + // @phpstan-ignore-next-line + $model->isTranslatableAttribute($attribute) + ) { + // @phpstan-ignore-next-line return $model->getTranslation( $attribute, + // @phpstan-ignore-next-line $model->getLocale(), + // @phpstan-ignore-next-line $model->useFallbackLocale() ); } @@ -391,47 +397,45 @@ class ToolboxHelper /** * Convert deeply an object to array * - * @param array|object $input + * @param mixed $input * @return array * @throws \RuntimeException If $input var is a scalar value. */ - public static function objectToArray($input): array + public static function objectToArray(mixed $input): array { // Only process if it's an object or array being passed to the function. - if (is_object($input) or is_array($input)) { - $ret = (array)$input; - foreach ($ret as &$item) { - // Recursively process EACH element only if not scalar. - $item = (is_object($item) or is_array($item)) ? - self::objectToArray($item) : $item; - } - return $ret; - } else { + if (!(is_object($input) or is_array($input))) { throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input)); } + $ret = (array)$input; + foreach ($ret as &$item) { + // Recursively process EACH element only if not scalar. + $item = (is_object($item) or is_array($item)) ? + self::objectToArray($item) : $item; + } + return $ret; } /** * Convert deeply an array to object * - * @param array|object $input + * @param mixed $input * @return object * @throws \RuntimeException If $input var is a scalar value. */ - public static function arrayToObject($input): object + public static function arrayToObject(mixed $input): object { // Only process if it's an object or array being passed to the function. - if (is_object($input) or is_array($input)) { - $ret = (object)$input; - foreach ($ret as &$item) { - // Recursively process EACH element only if not scalar. - $item = (is_object($item) or is_array($item)) ? - self::arrayToObject($item) : $item; - } - return $ret; - } else { + if (!(is_object($input) or is_array($input))) { throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input)); } + $ret = (object)$input; + foreach ($ret as &$item) { + // Recursively process EACH element only if not scalar. + $item = (is_object($item) or is_array($item)) ? + self::arrayToObject($item) : $item; + } + return $ret; } /** @@ -439,11 +443,11 @@ class ToolboxHelper * * @param string $attribute * @param string|null $value - * @param callback $fail + * @param callable $fail * @param object $sizes * @return void */ - public static function validatePicture(string $attribute, string|null $value, callable $fail, object $sizes) + public static function validatePicture(string $attribute, string|null $value, callable $fail, object $sizes): void { if (!($useStorage = Storage::exists($value)) and !File::exists($value)) { $fail(trans(':attribute n\'existe pas dans le système de fichier', [ @@ -451,7 +455,6 @@ class ToolboxHelper ])); return; } - /** @var string */ $fileFullPath = self::getUploadedFileFullPath($value, $useStorage); if ( !\in_array(self::getUploadedFileMimeType($value, $useStorage), [ @@ -462,7 +465,7 @@ class ToolboxHelper 'attribute' => $attribute ])); } - if (!($dimensions = \getimagesize($fileFullPath)) or !isset($dimensions[0]) or !isset($dimensions[1])) { + if (!($dimensions = \getimagesize($fileFullPath))) { $fail(trans(':attribute impossible de valider les dimensions', [ 'attribute' => $attribute ])); diff --git a/app/Models/ActivityLog.php b/app/Models/ActivityLog.php index cdc78cbf..c17f6322 100644 --- a/app/Models/ActivityLog.php +++ b/app/Models/ActivityLog.php @@ -3,18 +3,17 @@ namespace App\Models; use App\Enums\ActivityLogs\ActivityLogsEventEnum; -use Carbon\Carbon; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Facades\Schema; /** - * @property string $model Target model. - * @property string $model_id Id of the target model. - * @property string $event Event of this activity (ActivityLogsEventEnum). - * @property string $data Changes. - * @property-read \Illuminate\Support\Carbon $created_at Created date. + * @property string $model Target model. + * @property string $model_id Id of the target model. + * @property \App\Enums\ActivityLogs\ActivityLogsEventEnum $event Event of this activity (ActivityLogsEventEnum). + * @property array $data Changes. + * @property-read \Illuminate\Support\Carbon $created_at Created date. * * @property-read \App\Models\User $user User BelongsTo relation. */ @@ -82,19 +81,20 @@ class ActivityLog extends Model $activity->model_id = $model->getKey(); $activity->event = $eventEnum; $activity->data = static::getChangedColumns($activity, $model, $eventEnum); - $activity->created_at = Carbon::now(); + // @phpstan-ignore-next-line + $activity->created_at = now(); $activity->saveOrFail(); } /** * Get old, new columns that has changed. * - * @param \self $activity + * @param self $activity * @param \Illuminate\Database\Eloquent\Model $model * @param \App\Enums\ActivityLogs\ActivityLogsEventEnum $eventEnum - * @return array|null + * @return array */ - public static function getChangedColumns(self $activity, Model $model, ActivityLogsEventEnum $eventEnum): array|null + public static function getChangedColumns(self $activity, Model $model, ActivityLogsEventEnum $eventEnum): array { $modelClassName = $activity->model_class; /** Get type of each fields of the target model */ @@ -109,10 +109,11 @@ class ActivityLog extends Model return Schema::getColumnType($targetModel->getTable(), $fieldIndex); })->toArray(); // phpcs:enable + /** Return old, new and type of values changed */ + return ($eventEnum === ActivityLogsEventEnum::updated) ? + array_intersect_key($targetModelTypes, $model->getChanges()) : []; } - /** Return old, new and type of values changed */ - return ($eventEnum === ActivityLogsEventEnum::updated) ? - array_intersect_key($targetModelTypes, $model->getChanges()) : null; + return []; } // * RELATIONS diff --git a/app/Models/StaticPage.php b/app/Models/StaticPage.php index 16390797..204758ec 100644 --- a/app/Models/StaticPage.php +++ b/app/Models/StaticPage.php @@ -54,14 +54,14 @@ class StaticPage extends Model { static::creating(function (self $model) { // * ASSERTIONS - static::assertTitleIsUnique($model->title); + self::assertTitleIsUnique($model->title); // * CHANGES $model->slug = Str::slug($model->title); }); static::updating(function (self $model) { // * ASSERTIONS - static::assertTitleIsUnique($model->title, $model->id); + self::assertTitleIsUnique($model->title, $model->id); // * CHANGES $model->slug = Str::slug($model->title); diff --git a/app/Models/User.php b/app/Models/User.php index d4d87639..8dc7ebd7 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -74,7 +74,7 @@ class User extends Authenticatable protected static function booted(): void { static::creating(function (self $model) { - static::updatePassword($model); + self::updatePassword($model); // * Prevent user elevation privileges throw_if( auth('backend')->user() and auth('backend')->user()->role->value() > $model->role->value(), @@ -82,7 +82,7 @@ class User extends Authenticatable ); }); static::updating(function (self $model) { - static::updatePassword($model); + self::updatePassword($model); if (optional(auth('backend')->user())->getKey() === $model->getKey()) { \validator( ['published' => $model->published], diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 3b6f2ff2..e2e41297 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -80,9 +80,9 @@ class RouteServiceProvider extends ServiceProvider } // * Flatten if needed $cspReport = collect(request()->json('csp-report')) - ->flatMap(function ($v, $k) { - return [$k => is_array($v) ? collect($v)->flatten()->implode(', ') : $v]; - })->all(); + ->flatMap(function ($v, $k) { + return [$k => is_array($v) ? collect($v)->flatten()->implode(', ') : $v]; + })->all(); // * Filter array keys $cspReport = collect(array_intersect_key($cspReport, [ 'blocked-uri' => '', 'document-uri' => '', 'original-policy' => '', diff --git a/app/Providers/TranslationServiceProvider.php b/app/Providers/TranslationServiceProvider.php index b3e3f4ba..9b3029f9 100644 --- a/app/Providers/TranslationServiceProvider.php +++ b/app/Providers/TranslationServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Lib\Helpers\ToolboxHelper; use Illuminate\Support\Collection; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Cache; @@ -20,9 +21,19 @@ class TranslationServiceProvider extends ServiceProvider foreach ($this->collectLocalesStrings() as $locale) { // * Suported locales Cache::rememberForever(sprintf('translations.%s', $locale), function () use ($locale) { - $translations = [ - 'php' => $this->phpTranslations($locale), - 'json' => $this->jsonTranslations($locale), + $phpTransFallback = $this->phpTranslations(config('app.fallback_locale')); + $phpTransLocale = $this->phpTranslations($locale); + $jsonTransFallback = $this->jsonTranslations(config('app.fallback_locale')); + $jsonTransLocale = $this->jsonTranslations($locale); + $translations = [ + 'php' => ToolboxHelper::arrayMergeRecursiveDistinct( + $phpTransLocale, + $phpTransFallback, + ), + 'json' => ToolboxHelper::arrayMergeRecursiveDistinct( + $jsonTransLocale, + $jsonTransFallback, + ), ]; return $translations; }); @@ -36,11 +47,13 @@ class TranslationServiceProvider extends ServiceProvider */ private function collectLocalesStrings(): Collection { + // * En dur dans ->keys array. + // @phpstan-ignore-next-line return collect(File::allFiles(resource_path('lang/')))->flatMap(function (SplFileInfo $file) { if ($file->getRelativePath() and \strpos($file->getRelativePath(), 'vendor') !== 0) { return [$file->getRelativePath() => '']; } - })->keys(); + })->keys()->merge(config('app.locales', [])); } /** @@ -53,6 +66,10 @@ class TranslationServiceProvider extends ServiceProvider { $path = resource_path("lang/$locale"); + if (!File::exists($path) or !File::isReadable($path)) { + return []; + } + return collect(File::allFiles($path))->flatMap(function ($file) use ($locale) { $translation = $file->getBasename('.php'); return [$translation => trans($translation, [], $locale)]; @@ -69,10 +86,10 @@ class TranslationServiceProvider extends ServiceProvider { $path = resource_path("lang/$locale.json"); - if (is_string($path) && is_readable($path)) { - return json_decode(file_get_contents($path), true) ?? []; + if (!File::exists($path) or !File::isReadable($path)) { + return []; } - return []; + return json_decode(File::get($path), true) ?? []; } } diff --git a/app/Traits/Controllers/ChangesModelOrder.php b/app/Traits/Controllers/ChangesModelOrder.php index 51af5ba9..1797d90c 100644 --- a/app/Traits/Controllers/ChangesModelOrder.php +++ b/app/Traits/Controllers/ChangesModelOrder.php @@ -37,18 +37,16 @@ trait ChangesModelOrder return DB::transaction(function () use ($request, $className, $model) { /** @var \Illuminate\Database\Eloquent\Model|null */ - $tmp = $className::where('order', $request->direction ? '<' : '>', $model->order) + $tmp = $className::where('order', $request->direction ? '<' : '>', $model->getOriginal('order')) ->orderBy('order', $request->direction ? 'DESC' : 'ASC')->first(); if (!$tmp) { return back()->with('error', trans('crud.messages.order_not_changed')); } - $newOrder = $tmp->order; - $tmp->order = $model->order; - $model->order = $newOrder; - $tmp->saveOrFail(); - $model->saveOrFail(); + $newOrder = $tmp->getOriginal('order'); + $tmp->update(['order' => $model->getOriginal('order')]); + $model->update(['order' => $newOrder]); Session::flash('success', trans('crud.messages.order_changed')); return back(); diff --git a/app/Traits/Controllers/UpdateModelPublished.php b/app/Traits/Controllers/UpdateModelPublished.php index 4ca47df0..05691b11 100644 --- a/app/Traits/Controllers/UpdateModelPublished.php +++ b/app/Traits/Controllers/UpdateModelPublished.php @@ -19,8 +19,7 @@ trait UpdateModelPublished */ public function changePublished(Model $model) { - $model->published = !$model->published; - $model->saveOrFail(); + $model->update(['published' => !$model->getOriginal('published')]); return redirect()->back()->with('success', trans(__('crud.messages.publish_status_saved'))); } } diff --git a/app/Traits/Enums/BaseEnum.php b/app/Traits/Enums/BaseEnum.php index 559b1ee1..d6016cb7 100644 --- a/app/Traits/Enums/BaseEnum.php +++ b/app/Traits/Enums/BaseEnum.php @@ -118,9 +118,9 @@ trait BaseEnum /** * Fetch enum using value. * - * @param \App\Traits\Enums\BaseEnum|integer|string $value - * @param string $field - * @return \App\Traits\Enums\BaseEnum|null + * @param self|integer|string $value + * @param string $field + * @return self|null */ public static function make(self|int|string $value, string $field = 'value'): self|null { diff --git a/app/Traits/Models/IsCachedAsCollection.php b/app/Traits/Models/IsCachedAsCollection.php index f8ede859..b1f3f36d 100644 --- a/app/Traits/Models/IsCachedAsCollection.php +++ b/app/Traits/Models/IsCachedAsCollection.php @@ -10,7 +10,8 @@ use Illuminate\Support\Facades\Cache; /** * ! Use this only on limited elements, (not on tags, or products, or posts for ex.) * - * @property private static array $cacheConditions Eloquent condition to cache elements (to be used in where statement). + * @property array $cacheConditions + * Eloquent condition to cache elements (to be used in where statement). */ trait IsCachedAsCollection { diff --git a/app/Traits/Requests/HasPicture.php b/app/Traits/Requests/HasPicture.php index 64abf968..8ff3c754 100644 --- a/app/Traits/Requests/HasPicture.php +++ b/app/Traits/Requests/HasPicture.php @@ -75,7 +75,7 @@ trait HasPicture (strlen($requiredWithout)) ? 'required_without:' . $requiredWithout : '', ($size) ? 'max:' . $size : '', function (string $attribute, $value, callable $fail) use ($dimensions) { - return ToolboxHelper::validatePicture($attribute, $value, $fail, $dimensions); + ToolboxHelper::validatePicture($attribute, $value, $fail, $dimensions); } ] ]; @@ -110,7 +110,7 @@ trait HasPicture "{$name}Validate.*" => [ 'required', function (string $attribute, $value, callable $fail) use ($sizes) { - return $this->validatePicture($attribute, $value, $fail, $sizes); + ToolboxHelper::validatePicture($attribute, $value, $fail, $sizes); } ] ]; diff --git a/composer.json b/composer.json index 8abb4a33..a2f8ac8f 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "fakerphp/faker": "^1.9.1", "kitloong/laravel-migrations-generator": "^6.8", "krlove/eloquent-model-generator": "dev-l10-compatibility", + "larastan/larastan": "^2.8", "laravel-lang/common": "^4.0", "laravel/pint": "^1.0", "laravel/sail": "^1.18", diff --git a/composer.lock b/composer.lock index 34359fc9..718db396 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "045ad67cc83f34b4a7e6d9d4293e76af", + "content-hash": "a9d32f6b2a6150239bdf7dd628a6bada", "packages": [ { "name": "brick/math", @@ -7643,6 +7643,107 @@ }, "time": "2023-01-30T20:15:06+00:00" }, + { + "name": "larastan/larastan", + "version": "v2.8.1", + "source": { + "type": "git", + "url": "https://github.com/larastan/larastan.git", + "reference": "b7cc6a29c457a7d4f3de90466392ae9ad3e17022" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/larastan/larastan/zipball/b7cc6a29c457a7d4f3de90466392ae9ad3e17022", + "reference": "b7cc6a29c457a7d4f3de90466392ae9ad3e17022", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/console": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/container": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/contracts": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/database": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/http": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/support": "^9.52.16 || ^10.28.0 || ^11.0", + "php": "^8.0.2", + "phpmyadmin/sql-parser": "^5.8.2", + "phpstan/phpstan": "^1.10.50" + }, + "require-dev": { + "nikic/php-parser": "^4.17.1", + "orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.0", + "orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.0", + "phpunit/phpunit": "^9.6.13 || ^10.5" + }, + "suggest": { + "orchestra/testbench": "Using Larastan for analysing a package needs Testbench" + }, + "type": "phpstan-extension", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "Larastan\\Larastan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Can Vural", + "email": "can9119@gmail.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Larastan - Discover bugs in your code without running it. A phpstan/phpstan wrapper for Laravel", + "keywords": [ + "PHPStan", + "code analyse", + "code analysis", + "larastan", + "laravel", + "package", + "php", + "static analysis" + ], + "support": { + "issues": "https://github.com/larastan/larastan/issues", + "source": "https://github.com/larastan/larastan/tree/v2.8.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/canvural", + "type": "github" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2024-01-08T09:11:17+00:00" + }, { "name": "laravel-lang/attributes", "version": "2.9.1", @@ -8709,6 +8810,94 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpmyadmin/sql-parser", + "version": "5.9.0", + "source": { + "type": "git", + "url": "https://github.com/phpmyadmin/sql-parser.git", + "reference": "011fa18a4e55591fac6545a821921dd1d61c6984" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/011fa18a4e55591fac6545a821921dd1d61c6984", + "reference": "011fa18a4e55591fac6545a821921dd1d61c6984", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpmyadmin/motranslator": "<3.0" + }, + "require-dev": { + "phpbench/phpbench": "^1.1", + "phpmyadmin/coding-standard": "^3.0", + "phpmyadmin/motranslator": "^4.0 || ^5.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.9.12", + "phpstan/phpstan-phpunit": "^1.3.3", + "phpunit/php-code-coverage": "*", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "^0.16.1", + "vimeo/psalm": "^4.11", + "zumba/json-serializer": "~3.0.2" + }, + "suggest": { + "ext-mbstring": "For best performance", + "phpmyadmin/motranslator": "Translate messages to your favorite locale" + }, + "bin": [ + "bin/highlight-query", + "bin/lint-query", + "bin/sql-parser", + "bin/tokenize-query" + ], + "type": "library", + "autoload": { + "psr-4": { + "PhpMyAdmin\\SqlParser\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "The phpMyAdmin Team", + "email": "developers@phpmyadmin.net", + "homepage": "https://www.phpmyadmin.net/team/" + } + ], + "description": "A validating SQL lexer and parser with a focus on MySQL dialect.", + "homepage": "https://github.com/phpmyadmin/sql-parser", + "keywords": [ + "analysis", + "lexer", + "parser", + "query linter", + "sql", + "sql lexer", + "sql linter", + "sql parser", + "sql syntax highlighter", + "sql tokenizer" + ], + "support": { + "issues": "https://github.com/phpmyadmin/sql-parser/issues", + "source": "https://github.com/phpmyadmin/sql-parser" + }, + "funding": [ + { + "url": "https://www.phpmyadmin.net/donate/", + "type": "other" + } + ], + "time": "2024-01-20T20:34:02+00:00" + }, { "name": "phpstan/phpdoc-parser", "version": "1.25.0", @@ -8756,6 +8945,68 @@ }, "time": "2024-01-04T17:06:16+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.10.57", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1627b1d03446904aaa77593f370c5201d2ecc34e", + "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2024-01-24T11:51:34+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "10.1.11", diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..df74d87e --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,10 @@ +includes: + - vendor/larastan/larastan/extension.neon + +parameters: + + paths: + - app/ + + # Level 9 is the highest level + level: 5