diff --git a/app/Console/Commands/ImportHubCommand.php b/app/Console/Commands/ImportHubCommand.php index b89bb91..1d92474 100644 --- a/app/Console/Commands/ImportHubCommand.php +++ b/app/Console/Commands/ImportHubCommand.php @@ -2,7 +2,7 @@ namespace App\Console\Commands; -use App\Jobs\ImportHubDataJob; +use App\Jobs\Import\ImportHubDataJob; use Illuminate\Console\Command; class ImportHubCommand extends Command diff --git a/app/Http/Filters/V1/ModFilter.php b/app/Http/Filters/V1/ModFilter.php index dd64b11..58a0992 100644 --- a/app/Http/Filters/V1/ModFilter.php +++ b/app/Http/Filters/V1/ModFilter.php @@ -2,9 +2,13 @@ namespace App\Http\Filters\V1; +use App\Models\Mod; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Str; +/** + * @extends QueryFilter + */ class ModFilter extends QueryFilter { protected array $sortable = [ @@ -23,6 +27,11 @@ class ModFilter extends QueryFilter // TODO: Many of these are repeated across UserFilter and ModFilter. Consider refactoring into a shared trait. // Also, consider using common filter types and making the field names dynamic. + /** + * Filter by ID. + * + * @return Builder + */ public function id(string $value): Builder { $ids = array_map('trim', explode(',', $value)); @@ -30,6 +39,11 @@ class ModFilter extends QueryFilter return $this->builder->whereIn('id', $ids); } + /** + * Filter by hub ID. + * + * @return Builder + */ public function hub_id(string $value): Builder { $ids = array_map('trim', explode(',', $value)); @@ -37,6 +51,11 @@ class ModFilter extends QueryFilter return $this->builder->whereIn('hub_id', $ids); } + /** + * Filter by name. + * + * @return Builder + */ public function name(string $value): Builder { // The API handles the wildcard character as an asterisk (*), but the database uses the percentage sign (%). @@ -45,6 +64,11 @@ class ModFilter extends QueryFilter return $this->builder->where('name', 'like', $like); } + /** + * Filter by slug. + * + * @return Builder + */ public function slug(string $value): Builder { // The API handles the wildcard character as an asterisk (*), but the database uses the percentage sign (%). @@ -53,6 +77,11 @@ class ModFilter extends QueryFilter return $this->builder->where('slug', 'like', $like); } + /** + * Filter by teaser. + * + * @return Builder + */ public function teaser(string $value): Builder { // The API handles the wildcard character as an asterisk (*), but the database uses the percentage sign (%). @@ -61,6 +90,11 @@ class ModFilter extends QueryFilter return $this->builder->where('teaser', 'like', $like); } + /** + * Filter by source code link. + * + * @return Builder + */ public function source_code_link(string $value): Builder { // The API handles the wildcard character as an asterisk (*), but the database uses the percentage sign (%). @@ -69,6 +103,11 @@ class ModFilter extends QueryFilter return $this->builder->where('source_code_link', 'like', $like); } + /** + * Filter by created at date. + * + * @return Builder + */ public function created_at(string $value): Builder { // The API allows for a range of dates to be passed as a comma-separated list. @@ -80,6 +119,11 @@ class ModFilter extends QueryFilter return $this->builder->whereDate('created_at', $value); } + /** + * Filter by updated at date. + * + * @return Builder + */ public function updated_at(string $value): Builder { // The API allows for a range of dates to be passed as a comma-separated list. @@ -91,6 +135,11 @@ class ModFilter extends QueryFilter return $this->builder->whereDate('updated_at', $value); } + /** + * Filter by published at date. + * + * @return Builder + */ public function published_at(string $value): Builder { // The API allows for a range of dates to be passed as a comma-separated list. @@ -102,6 +151,11 @@ class ModFilter extends QueryFilter return $this->builder->whereDate('published_at', $value); } + /** + * Filter by featured. + * + * @return Builder + */ public function featured(string $value): Builder { // We need to convert the string user input to a boolean, or null if it's not a valid "truthy/falsy" value. @@ -115,6 +169,11 @@ class ModFilter extends QueryFilter return $this->builder->where('featured', $value); } + /** + * Filter by contains ads. + * + * @return Builder + */ public function contains_ads(string $value): Builder { // We need to convert the string user input to a boolean, or null if it's not a valid "truthy/falsy" value. @@ -128,6 +187,11 @@ class ModFilter extends QueryFilter return $this->builder->where('contains_ads', $value); } + /** + * Filter by contains AI content. + * + * @return Builder + */ public function contains_ai_content(string $value): Builder { // We need to convert the string user input to a boolean, or null if it's not a valid "truthy/falsy" value. diff --git a/app/Http/Filters/V1/QueryFilter.php b/app/Http/Filters/V1/QueryFilter.php index f636cd7..3e4c789 100644 --- a/app/Http/Filters/V1/QueryFilter.php +++ b/app/Http/Filters/V1/QueryFilter.php @@ -3,15 +3,25 @@ namespace App\Http\Filters\V1; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Request; use Illuminate\Support\Str; +/** + * @template TModelClass of Model + */ abstract class QueryFilter { + /** + * The query builder instance. + * + * @var Builder + */ protected Builder $builder; protected Request $request; + /** @var array */ protected array $sortable = []; public function __construct(Request $request) @@ -19,6 +29,12 @@ abstract class QueryFilter $this->request = $request; } + /** + * Apply the filter to the query builder. + * + * @param Builder $builder + * @return Builder + */ public function apply(Builder $builder): Builder { $this->builder = $builder; @@ -32,17 +48,11 @@ abstract class QueryFilter return $this->builder; } - protected function filter(array $filters): Builder - { - foreach ($filters as $attribute => $value) { - if (method_exists($this, $attribute)) { - $this->$attribute($value); - } - } - - return $this->builder; - } - + /** + * Apply the sort type to the query. + * + * @return Builder + */ protected function sort(string $values): Builder { $sortables = array_map('trim', explode(',', $values)); diff --git a/app/Http/Filters/V1/UserFilter.php b/app/Http/Filters/V1/UserFilter.php index 1eec8fc..f7c5c51 100644 --- a/app/Http/Filters/V1/UserFilter.php +++ b/app/Http/Filters/V1/UserFilter.php @@ -2,11 +2,20 @@ namespace App\Http\Filters\V1; +use App\Models\User; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Str; +/** + * @extends QueryFilter + */ class UserFilter extends QueryFilter { + /** + * The sortable fields. + * + * @var array + */ protected array $sortable = [ 'name', 'created_at', @@ -16,6 +25,11 @@ class UserFilter extends QueryFilter // TODO: Many of these are repeated across UserFilter and ModFilter. Consider refactoring into a shared trait. // Also, consider using common filter types and making the field names dynamic. + /** + * Filter by ID. + * + * @return Builder + */ public function id(string $value): Builder { $ids = array_map('trim', explode(',', $value)); @@ -23,6 +37,11 @@ class UserFilter extends QueryFilter return $this->builder->whereIn('id', $ids); } + /** + * Filter by name. + * + * @return Builder + */ public function name(string $value): Builder { // The API handles the wildcard character as an asterisk (*), but the database uses the percentage sign (%). @@ -31,6 +50,11 @@ class UserFilter extends QueryFilter return $this->builder->where('name', 'like', $like); } + /** + * Filter by created at date. + * + * @return Builder + */ public function created_at(string $value): Builder { // The API allows for a range of dates to be passed as a comma-separated list. @@ -42,6 +66,11 @@ class UserFilter extends QueryFilter return $this->builder->whereDate('created_at', $value); } + /** + * Filter by updated at date. + * + * @return Builder + */ public function updated_at(string $value): Builder { // The API allows for a range of dates to be passed as a comma-separated list. diff --git a/app/Http/Requests/Api/LoginUserRequest.php b/app/Http/Requests/Api/LoginUserRequest.php index 4ad184e..0fc932a 100644 --- a/app/Http/Requests/Api/LoginUserRequest.php +++ b/app/Http/Requests/Api/LoginUserRequest.php @@ -16,6 +16,8 @@ class LoginUserRequest extends FormRequest /** * Get the validation rules that apply to the request. + * + * @return array */ public function rules(): array { diff --git a/app/Http/Requests/Api/V0/StoreModRequest.php b/app/Http/Requests/Api/V0/StoreModRequest.php index 69bf403..267f46f 100644 --- a/app/Http/Requests/Api/V0/StoreModRequest.php +++ b/app/Http/Requests/Api/V0/StoreModRequest.php @@ -16,11 +16,11 @@ class StoreModRequest extends FormRequest /** * Get the validation rules that apply to the request. + * + * @return array */ public function rules(): array { - return [ - // - ]; + return []; } } diff --git a/app/Http/Requests/Api/V0/StoreUserRequest.php b/app/Http/Requests/Api/V0/StoreUserRequest.php index 590b441..38b3837 100644 --- a/app/Http/Requests/Api/V0/StoreUserRequest.php +++ b/app/Http/Requests/Api/V0/StoreUserRequest.php @@ -16,11 +16,11 @@ class StoreUserRequest extends FormRequest /** * Get the validation rules that apply to the request. + * + * @return array */ public function rules(): array { - return [ - // - ]; + return []; } } diff --git a/app/Http/Requests/Api/V0/UpdateModRequest.php b/app/Http/Requests/Api/V0/UpdateModRequest.php index e4fabca..2193e6b 100644 --- a/app/Http/Requests/Api/V0/UpdateModRequest.php +++ b/app/Http/Requests/Api/V0/UpdateModRequest.php @@ -16,11 +16,11 @@ class UpdateModRequest extends FormRequest /** * Get the validation rules that apply to the request. + * + * @return array */ public function rules(): array { - return [ - // - ]; + return []; } } diff --git a/app/Http/Requests/Api/V0/UpdateUserRequest.php b/app/Http/Requests/Api/V0/UpdateUserRequest.php index 12a1768..d52533e 100644 --- a/app/Http/Requests/Api/V0/UpdateUserRequest.php +++ b/app/Http/Requests/Api/V0/UpdateUserRequest.php @@ -16,11 +16,11 @@ class UpdateUserRequest extends FormRequest /** * Get the validation rules that apply to the request. + * + * @return array */ public function rules(): array { - return [ - // - ]; + return []; } } diff --git a/app/Http/Requests/ModRequest.php b/app/Http/Requests/ModRequest.php index 9f483ad..3899ae6 100644 --- a/app/Http/Requests/ModRequest.php +++ b/app/Http/Requests/ModRequest.php @@ -6,6 +6,11 @@ use Illuminate\Foundation\Http\FormRequest; class ModRequest extends FormRequest { + /** + * Get the validation rules that apply to the request. + * + * @return array + */ public function rules(): array { return [ @@ -18,6 +23,9 @@ class ModRequest extends FormRequest ]; } + /** + * Determine if the user is authorized to make this request. + */ public function authorize(): bool { return true; diff --git a/app/Http/Resources/Api/V0/LicenseResource.php b/app/Http/Resources/Api/V0/LicenseResource.php index a64ebe2..e2e54b2 100644 --- a/app/Http/Resources/Api/V0/LicenseResource.php +++ b/app/Http/Resources/Api/V0/LicenseResource.php @@ -9,6 +9,11 @@ use Illuminate\Http\Resources\Json\JsonResource; /** @mixin License */ class LicenseResource extends JsonResource { + /** + * Transform the resource into an array. + * + * @return array + */ public function toArray(Request $request): array { return [ diff --git a/app/Http/Resources/Api/V0/ModResource.php b/app/Http/Resources/Api/V0/ModResource.php index 23ed9cc..36bcfba 100644 --- a/app/Http/Resources/Api/V0/ModResource.php +++ b/app/Http/Resources/Api/V0/ModResource.php @@ -12,6 +12,8 @@ class ModResource extends JsonResource { /** * Transform the resource into an array. + * + * @return array */ public function toArray(Request $request): array { diff --git a/app/Http/Resources/Api/V0/ModVersionResource.php b/app/Http/Resources/Api/V0/ModVersionResource.php index d42008d..107b21c 100644 --- a/app/Http/Resources/Api/V0/ModVersionResource.php +++ b/app/Http/Resources/Api/V0/ModVersionResource.php @@ -11,6 +11,8 @@ class ModVersionResource extends JsonResource { /** * Transform the resource into an array. + * + * @return array */ public function toArray(Request $request): array { @@ -32,7 +34,6 @@ class ModVersionResource extends JsonResource // downloads that are made, so we'll need a new route/feature for that. #35 'link' => $this->link, - 'spt_version_id' => $this->spt_version_id, 'virus_total_link' => $this->virus_total_link, 'downloads' => $this->downloads, 'created_at' => $this->created_at, @@ -44,7 +45,6 @@ class ModVersionResource extends JsonResource [ 'data' => [ 'type' => 'spt_version', - 'id' => $this->spt_version_id, ], ], ], diff --git a/app/Http/Resources/Api/V0/UserResource.php b/app/Http/Resources/Api/V0/UserResource.php index 903012f..8dfd91f 100644 --- a/app/Http/Resources/Api/V0/UserResource.php +++ b/app/Http/Resources/Api/V0/UserResource.php @@ -10,6 +10,11 @@ use Illuminate\Http\Resources\Json\JsonResource; /** @mixin User */ class UserResource extends JsonResource { + /** + * Transform the resource into an array. + * + * @return array + */ public function toArray(Request $request): array { return [ diff --git a/app/Http/Resources/Api/V0/UserRoleResource.php b/app/Http/Resources/Api/V0/UserRoleResource.php index 51d5146..4d16ad6 100644 --- a/app/Http/Resources/Api/V0/UserRoleResource.php +++ b/app/Http/Resources/Api/V0/UserRoleResource.php @@ -9,6 +9,11 @@ use Illuminate\Http\Resources\Json\JsonResource; /** @mixin UserRole */ class UserRoleResource extends JsonResource { + /** + * Transform the resource into an array. + * + * @return array + */ public function toArray(Request $request): array { return [ diff --git a/app/Http/Resources/LicenseResource.php b/app/Http/Resources/LicenseResource.php index ccc580b..46d9f43 100644 --- a/app/Http/Resources/LicenseResource.php +++ b/app/Http/Resources/LicenseResource.php @@ -2,12 +2,18 @@ namespace App\Http\Resources; +use App\Models\License; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; -/** @mixin \App\Models\License */ +/** @mixin License */ class LicenseResource extends JsonResource { + /** + * Transform the resource into an array. + * + * @return array + */ public function toArray(Request $request): array { return [ diff --git a/app/Http/Resources/ModResource.php b/app/Http/Resources/ModResource.php index c869ee5..db56e51 100644 --- a/app/Http/Resources/ModResource.php +++ b/app/Http/Resources/ModResource.php @@ -2,12 +2,18 @@ namespace App\Http\Resources; +use App\Models\Mod; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; -/** @mixin \App\Models\Mod */ +/** @mixin Mod */ class ModResource extends JsonResource { + /** + * Transform the resource into an array. + * + * @return array + */ public function toArray(Request $request): array { return [ diff --git a/app/Http/Resources/ModVersionResource.php b/app/Http/Resources/ModVersionResource.php index 1f4d045..1878b8b 100644 --- a/app/Http/Resources/ModVersionResource.php +++ b/app/Http/Resources/ModVersionResource.php @@ -2,12 +2,18 @@ namespace App\Http\Resources; +use App\Models\ModVersion; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; -/** @mixin \App\Models\ModVersion */ +/** @mixin ModVersion */ class ModVersionResource extends JsonResource { + /** + * Transform the resource into an array. + * + * @return array + */ public function toArray(Request $request): array { return [ @@ -19,10 +25,7 @@ class ModVersionResource extends JsonResource 'description' => $this->description, 'virus_total_link' => $this->virus_total_link, 'downloads' => $this->downloads, - 'mod_id' => $this->mod_id, - 'spt_version_id' => $this->spt_version_id, - 'mod' => new ModResource($this->whenLoaded('mod')), 'sptVersion' => new SptVersionResource($this->whenLoaded('sptVersion')), ]; diff --git a/app/Http/Resources/SptVersionResource.php b/app/Http/Resources/SptVersionResource.php index 49ecf3a..58d3d62 100644 --- a/app/Http/Resources/SptVersionResource.php +++ b/app/Http/Resources/SptVersionResource.php @@ -2,12 +2,18 @@ namespace App\Http\Resources; +use App\Models\SptVersion; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; -/** @mixin \App\Models\SptVersion */ +/** @mixin SptVersion */ class SptVersionResource extends JsonResource { + /** + * Transform the resource into an array. + * + * @return array + */ public function toArray(Request $request): array { return [ diff --git a/app/Jobs/Import/DataTransferObjects/HubUser.php b/app/Jobs/Import/DataTransferObjects/HubUser.php new file mode 100644 index 0000000..946b1ee --- /dev/null +++ b/app/Jobs/Import/DataTransferObjects/HubUser.php @@ -0,0 +1,23 @@ +collectUserData($curl, $user); + $hubUser = new HubUser( + $user->userID, + $user->username, + $user->email, + $user->password, + $user->registrationDate, + $user->banned, + $user->banReason, + $user->banExpires, + $user->coverPhotoHash, + $user->coverPhotoExtension, + $user->rankID, + $user->rankTitle + ); - $bannedUserData = $this->collectBannedUserData($user); + $userData[] = $this->collectUserData($curl, $hubUser); + + $bannedUserData = $this->collectBannedUserData($hubUser); if ($bannedUserData) { $bannedUsers[] = $bannedUserData; } - $userRankData = $this->collectUserRankData($user); + $userRankData = $this->collectUserRankData($hubUser); if ($userRankData) { $userRanks[] = $userRankData; } @@ -328,16 +344,21 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue curl_close($curl); } - protected function collectUserData(CurlHandle $curl, object $user): array + /** + * Build an array of user data ready to be inserted into the local database. + * + * @return array + */ + protected function collectUserData(CurlHandle $curl, HubUser $hubUser): array { return [ - 'hub_id' => (int) $user->userID, - 'name' => $user->username, - 'email' => Str::lower($user->email), - 'password' => $this->cleanPasswordHash($user->password), - 'profile_photo_path' => $this->fetchUserAvatar($curl, $user), - 'cover_photo_path' => $this->fetchUserCoverPhoto($curl, $user), - 'created_at' => $this->cleanRegistrationDate($user->registrationDate), + 'hub_id' => (int) $hubUser->userID, + 'name' => $hubUser->username, + 'email' => Str::lower($hubUser->email), + 'password' => $this->cleanPasswordHash($hubUser->password), + 'profile_photo_path' => $this->fetchUserAvatar($curl, $hubUser), + 'cover_photo_path' => $this->fetchUserCoverPhoto($curl, $hubUser), + 'created_at' => $this->cleanRegistrationDate($hubUser->registrationDate), 'updated_at' => now('UTC')->toDateTimeString(), ]; } @@ -358,10 +379,10 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue /** * Fetch the user avatar from the Hub and store it anew. */ - protected function fetchUserAvatar(CurlHandle $curl, object $user): string + protected function fetchUserAvatar(CurlHandle $curl, HubUser $hubUser): string { // Fetch the user's avatar data from the temporary table. - $avatar = DB::table('temp_user_avatar')->where('userID', $user->userID)->first(); + $avatar = DB::table('temp_user_avatar')->where('userID', $hubUser->userID)->first(); if (! $avatar) { return ''; @@ -410,15 +431,15 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue /** * Fetch the user avatar from the Hub and store it anew. */ - protected function fetchUserCoverPhoto(CurlHandle $curl, object $user): string + protected function fetchUserCoverPhoto(CurlHandle $curl, HubUser $hubUser): string { - if (empty($user->coverPhotoHash) || empty($user->coverPhotoExtension)) { + if (empty($hubUser->coverPhotoHash) || empty($hubUser->coverPhotoExtension)) { return ''; } - $hashShort = substr($user->coverPhotoHash, 0, 2); - $fileName = $user->coverPhotoHash.'.'.$user->coverPhotoExtension; - $hubUrl = 'https://hub.sp-tarkov.com/images/coverPhotos/'.$hashShort.'/'.$user->userID.'-'.$fileName; + $hashShort = substr($hubUser->coverPhotoHash, 0, 2); + $fileName = $hubUser->coverPhotoHash.'.'.$hubUser->coverPhotoExtension; + $hubUrl = 'https://hub.sp-tarkov.com/images/coverPhotos/'.$hashShort.'/'.$hubUser->userID.'-'.$fileName; $relativePath = 'user-covers/'.$fileName; return $this->fetchAndStoreImage($curl, $hubUrl, $relativePath); @@ -441,14 +462,16 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue /** * Build an array of banned user data ready to be inserted into the local database. + * + * @return array|null */ - protected function collectBannedUserData($user): ?array + protected function collectBannedUserData(HubUser $hubUser): ?array { - if ($user->banned) { + if ($hubUser->banned) { return [ - 'hub_id' => (int) $user->userID, - 'comment' => $user->banReason ?? '', - 'expired_at' => $this->cleanUnbannedAtDate($user->banExpires), + 'hub_id' => (int) $hubUser->userID, + 'comment' => $hubUser->banReason ?? '', + 'expired_at' => $this->cleanUnbannedAtDate($hubUser->banExpires), ]; } @@ -495,12 +518,17 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue } } - protected function collectUserRankData($user): ?array + /** + * Build an array of user rank data ready to be inserted into the local database. + * + * @return array|null + */ + protected function collectUserRankData(HubUser $hubUser): ?array { - if ($user->rankID && $user->rankTitle) { + if ($hubUser->rankID && $hubUser->rankTitle) { return [ - 'hub_id' => (int) $user->userID, - 'title' => $user->rankTitle, + 'hub_id' => (int) $hubUser->userID, + 'title' => $hubUser->rankTitle, ]; } @@ -509,8 +537,10 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue /** * Insert or update the users in the local database. + * + * @param array> $usersData */ - protected function upsertUsers($usersData): void + protected function upsertUsers(array $usersData): void { if (! empty($usersData)) { DB::table('users')->upsert($usersData, ['hub_id'], [ @@ -525,8 +555,10 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue /** * Fetch the hub-banned users from the local database and ban them locally. + * + * @param array> $bannedUsers */ - protected function handleBannedUsers($bannedUsers): void + protected function handleBannedUsers(array $bannedUsers): void { foreach ($bannedUsers as $bannedUser) { $user = User::whereHubId($bannedUser['hub_id'])->first(); @@ -539,8 +571,10 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue /** * Fetch or create the user ranks in the local database and assign them to the users. + * + * @param array> $userRanks */ - protected function handleUserRoles($userRanks): void + protected function handleUserRoles(array $userRanks): void { foreach ($userRanks as $userRank) { $roleName = Str::ucfirst(Str::afterLast($userRank['title'], '.')); @@ -555,6 +589,8 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue /** * Build the user role data based on the role name. + * + * @return array */ protected function buildUserRoleData(string $name): array { @@ -672,6 +708,8 @@ class ImportHubDataJob implements ShouldBeUnique, ShouldQueue /** * Get the latest current version from the response data. + * + * @param array> $versions */ protected function getLatestVersion(array $versions): string { diff --git a/app/Livewire/GlobalSearch.php b/app/Livewire/GlobalSearch.php index 991f5d1..e8dfd39 100644 --- a/app/Livewire/GlobalSearch.php +++ b/app/Livewire/GlobalSearch.php @@ -4,6 +4,7 @@ namespace App\Livewire; use App\Models\Mod; use App\Models\User; +use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\View\View; use Livewire\Component; @@ -34,16 +35,18 @@ class GlobalSearch extends Component /** * Execute the search against each of the searchable models. + * + * @return array>> */ protected function executeSearch(string $query): array { $query = Str::trim($query); $results = ['data' => [], 'total' => 0]; - if (Str::length($query)) { + if (Str::length($query) > 0) { $results['data'] = [ - 'user' => collect(User::search($query)->raw()['hits']), - 'mod' => collect(Mod::search($query)->raw()['hits']), + 'user' => $this->fetchUserResults($query), + 'mod' => $this->fetchModResults($query), ]; $results['total'] = $this->countTotalResults($results['data']); } @@ -55,11 +58,39 @@ class GlobalSearch extends Component } /** - * Count the total number of results across all models. + * Fetch the user search results. + * + * @return Collection> */ - protected function countTotalResults($results): int + protected function fetchUserResults(string $query): Collection { - return collect($results)->reduce(function ($carry, $result) { + /** @var array> $userHits */ + $userHits = User::search($query)->raw()['hits']; + + return collect($userHits); + } + + /** + * Fetch the mod search results. + * + * @return Collection> + */ + protected function fetchModResults(string $query): Collection + { + /** @var array> $modHits */ + $modHits = Mod::search($query)->raw()['hits']; + + return collect($modHits); + } + + /** + * Count the total number of results across all models. + * + * @param array>> $results + */ + protected function countTotalResults(array $results): int + { + return collect($results)->reduce(function (int $carry, Collection $result) { return $carry + $result->count(); }, 0); } diff --git a/app/Livewire/Mod/Index.php b/app/Livewire/Mod/Index.php index 69cabb4..34c27fc 100644 --- a/app/Livewire/Mod/Index.php +++ b/app/Livewire/Mod/Index.php @@ -30,6 +30,8 @@ class Index extends Component /** * The SPT versions filter value. + * + * @var array */ #[Url] public array $sptVersions = []; @@ -42,6 +44,8 @@ class Index extends Component /** * The available SPT versions. + * + * @var Collection */ public Collection $activeSptVersions; @@ -59,6 +63,8 @@ class Index extends Component /** * Get all patch versions of the latest minor SPT version. + * + * @return Collection */ public function getLatestMinorVersions(): Collection { diff --git a/app/Models/License.php b/app/Models/License.php index 7c3118b..00533bc 100644 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -2,6 +2,7 @@ namespace App\Models; +use Database\Factories\LicenseFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -9,10 +10,15 @@ use Illuminate\Database\Eloquent\SoftDeletes; class License extends Model { - use HasFactory, SoftDeletes; + /** @use HasFactory */ + use HasFactory; + + use SoftDeletes; /** * The relationship between a license and mod. + * + * @return HasMany */ public function mods(): HasMany { diff --git a/app/Models/Mod.php b/app/Models/Mod.php index 7d81d9d..3093205 100644 --- a/app/Models/Mod.php +++ b/app/Models/Mod.php @@ -5,6 +5,7 @@ namespace App\Models; use App\Http\Filters\V1\QueryFilter; use App\Models\Scopes\DisabledScope; use App\Models\Scopes\PublishedScope; +use Database\Factories\ModFactory; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -19,24 +20,20 @@ use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; use Laravel\Scout\Searchable; -/** - * @property int $id - * @property string $name - * @property string $slug - */ class Mod extends Model { - use HasFactory, Searchable, SoftDeletes; + /** @use HasFactory */ + use HasFactory; + + use Searchable; + use SoftDeletes; /** * Post boot method to configure the model. */ protected static function booted(): void { - // Apply the global scope to exclude disabled mods. static::addGlobalScope(new DisabledScope); - - // Apply the global scope to exclude non-published mods. static::addGlobalScope(new PublishedScope); } @@ -51,6 +48,8 @@ class Mod extends Model /** * The relationship between a mod and its users. + * + * @return BelongsToMany */ public function users(): BelongsToMany { @@ -59,6 +58,8 @@ class Mod extends Model /** * The relationship between a mod and its license. + * + * @return BelongsTo */ public function license(): BelongsTo { @@ -67,6 +68,8 @@ class Mod extends Model /** * The relationship between a mod and its versions. + * + * @return HasMany */ public function versions(): HasMany { @@ -78,6 +81,8 @@ class Mod extends Model /** * The relationship between a mod and its last updated version. + * + * @return HasOne */ public function lastUpdatedVersion(): HasOne { @@ -89,6 +94,8 @@ class Mod extends Model /** * The data that is searchable by Scout. + * + * @return array */ public function toSearchableArray(): array { @@ -102,13 +109,15 @@ class Mod extends Model 'created_at' => strtotime($this->created_at), 'updated_at' => strtotime($this->updated_at), 'published_at' => strtotime($this->published_at), - 'latestVersion' => $this->latestVersion()?->first()?->latestSptVersion()?->first()?->version_formatted, - 'latestVersionColorClass' => $this->latestVersion()?->first()?->latestSptVersion()?->first()?->color_class, + 'latestVersion' => $this->latestVersion()->first()->latestSptVersion()->first()->version_formatted, + 'latestVersionColorClass' => $this->latestVersion()->first()->latestSptVersion()->first()->color_class, ]; } /** * The relationship to the latest mod version, dictated by the mod version number. + * + * @return HasOne */ public function latestVersion(): HasOne { @@ -136,7 +145,7 @@ class Mod extends Model } // Fetch the latest version instance. - $latestVersion = $this->latestVersion()?->first(); + $latestVersion = $this->latestVersion()->first(); // Ensure the mod has a latest version. if (is_null($latestVersion)) { @@ -162,6 +171,8 @@ class Mod extends Model /** * Build the URL to the mod's thumbnail. + * + * @return Attribute */ public function thumbnailUrl(): Attribute { @@ -185,6 +196,10 @@ class Mod extends Model /** * Scope a query by applying QueryFilter filters. + * + * @param Builder $builder + * @param QueryFilter $filters + * @return Builder */ public function scopeFilter(Builder $builder, QueryFilter $filters): Builder { @@ -201,6 +216,8 @@ class Mod extends Model /** * The attributes that should be cast to native types. + * + * @return array */ protected function casts(): array { @@ -214,6 +231,8 @@ class Mod extends Model /** * Mutate the slug attribute to always be lower case on get and slugified on set. + * + * @return Attribute */ protected function slug(): Attribute { diff --git a/app/Models/ModDependency.php b/app/Models/ModDependency.php index 1a0ec75..1a65b71 100644 --- a/app/Models/ModDependency.php +++ b/app/Models/ModDependency.php @@ -2,24 +2,21 @@ namespace App\Models; +use Database\Factories\ModDependencyFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -/** - * @property int $id - * @property int $mod_version_id - * @property int $dependency_mod_id - * @property string $constraint - * @property int|null $resolved_version_id - */ class ModDependency extends Model { + /** @use HasFactory */ use HasFactory; /** * The relationship between the mod dependency and the mod version. + * + * @return BelongsTo */ public function modVersion(): BelongsTo { @@ -28,6 +25,8 @@ class ModDependency extends Model /** * The relationship between the mod dependency and the resolved dependency. + * + * @return HasMany */ public function resolvedDependencies(): HasMany { @@ -37,6 +36,8 @@ class ModDependency extends Model /** * The relationship between the mod dependency and the dependent mod. + * + * @return BelongsTo */ public function dependentMod(): BelongsTo { diff --git a/app/Models/ModResolvedDependency.php b/app/Models/ModResolvedDependency.php index ee6e747..41d47c8 100644 --- a/app/Models/ModResolvedDependency.php +++ b/app/Models/ModResolvedDependency.php @@ -9,6 +9,8 @@ class ModResolvedDependency extends Model { /** * The relationship between the resolved dependency and the mod version. + * + * @return BelongsTo */ public function modVersion(): BelongsTo { @@ -17,6 +19,8 @@ class ModResolvedDependency extends Model /** * The relationship between the resolved dependency and the dependency. + * + * @return BelongsTo */ public function dependency(): BelongsTo { @@ -25,6 +29,8 @@ class ModResolvedDependency extends Model /** * The relationship between the resolved dependency and the resolved mod version. + * + * @return BelongsTo */ public function resolvedModVersion(): BelongsTo { diff --git a/app/Models/ModVersion.php b/app/Models/ModVersion.php index 3221173..abef339 100644 --- a/app/Models/ModVersion.php +++ b/app/Models/ModVersion.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Models\Scopes\DisabledScope; use App\Models\Scopes\PublishedScope; +use Database\Factories\ModFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -11,14 +12,12 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\SoftDeletes; -/** - * @property int $id - * @property int $mod_id - * @property string $version - */ class ModVersion extends Model { - use HasFactory, SoftDeletes; + /** @use HasFactory */ + use HasFactory; + + use SoftDeletes; /** * Post boot method to configure the model. @@ -31,6 +30,8 @@ class ModVersion extends Model /** * The relationship between a mod version and mod. + * + * @return BelongsTo */ public function mod(): BelongsTo { @@ -39,6 +40,8 @@ class ModVersion extends Model /** * The relationship between a mod version and its dependencies. + * + * @return HasMany */ public function dependencies(): HasMany { @@ -48,6 +51,8 @@ class ModVersion extends Model /** * The relationship between a mod version and its resolved dependencies. + * + * @return BelongsToMany */ public function resolvedDependencies(): BelongsToMany { @@ -58,6 +63,8 @@ class ModVersion extends Model /** * The relationship between a mod version and its each of it's resolved dependencies' latest versions. + * + * @return BelongsToMany */ public function latestResolvedDependencies(): BelongsToMany { @@ -74,6 +81,8 @@ class ModVersion extends Model /** * The relationship between a mod version and each of its SPT versions' latest version. * Hint: Be sure to call `->first()` on this to get the actual instance. + * + * @return BelongsToMany */ public function latestSptVersion(): BelongsToMany { @@ -84,6 +93,8 @@ class ModVersion extends Model /** * The relationship between a mod version and its SPT versions. + * + * @return BelongsToMany */ public function sptVersions(): BelongsToMany { diff --git a/app/Models/Scopes/DisabledScope.php b/app/Models/Scopes/DisabledScope.php index 517d3ba..58a982e 100644 --- a/app/Models/Scopes/DisabledScope.php +++ b/app/Models/Scopes/DisabledScope.php @@ -6,10 +6,15 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; +/** + * @template TModelClass of Model + */ class DisabledScope implements Scope { /** * Apply the scope to a given Eloquent query builder. + * + * @param Builder $builder */ public function apply(Builder $builder, Model $model): void { diff --git a/app/Models/Scopes/PublishedScope.php b/app/Models/Scopes/PublishedScope.php index a4576ed..ac8a2a9 100644 --- a/app/Models/Scopes/PublishedScope.php +++ b/app/Models/Scopes/PublishedScope.php @@ -6,10 +6,15 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; +/** + * @template TModelClass of Model + */ class PublishedScope implements Scope { /** * Apply the scope to a given Eloquent query builder. + * + * @param Builder $builder */ public function apply(Builder $builder, Model $model): void { diff --git a/app/Models/SptVersion.php b/app/Models/SptVersion.php index 9d0aa0f..353e52a 100644 --- a/app/Models/SptVersion.php +++ b/app/Models/SptVersion.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Exceptions\InvalidVersionNumberException; +use Database\Factories\SptVersionFactory; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -12,10 +13,15 @@ use Illuminate\Support\Facades\Cache; class SptVersion extends Model { - use HasFactory, SoftDeletes; + /** @use HasFactory */ + use HasFactory; + + use SoftDeletes; /** * Get all versions for the last three minor versions. + * + * @return Collection */ public static function getVersionsForLastThreeMinors(): Collection { @@ -44,6 +50,8 @@ class SptVersion extends Model /** * Get the last three minor versions (major.minor format). + * + * @return array */ public static function getLastThreeMinorVersions(): array { @@ -54,7 +62,7 @@ class SptVersion extends Model ->orderByDesc('version_minor') ->limit(3) ->get() - ->map(function ($version) { + ->map(function (SptVersion $version) { return [ 'major' => (int) $version->version_major, 'minor' => (int) $version->version_minor, @@ -69,7 +77,7 @@ class SptVersion extends Model protected static function booted(): void { // Callback that runs before saving the model. - static::saving(function ($model) { + static::saving(function (SptVersion $model) { // Extract the version sections from the version string. if (! empty($model->version)) { // Default values in case there's an exception. @@ -95,6 +103,8 @@ class SptVersion extends Model /** * Extract the version sections from the version string. * + * @return array{major: int, minor: int, patch: int, pre_release: string} + * * @throws InvalidVersionNumberException */ public static function extractVersionSections(string $version): array @@ -131,6 +141,8 @@ class SptVersion extends Model /** * The relationship between an SPT version and mod version. + * + * @return BelongsToMany */ public function modVersions(): BelongsToMany { diff --git a/app/Models/User.php b/app/Models/User.php index 157248b..c5efa96 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -6,6 +6,7 @@ use App\Http\Filters\V1\QueryFilter; use App\Notifications\ResetPassword; use App\Notifications\VerifyEmail; use App\Traits\HasCoverPhoto; +use Database\Factories\UserFactory; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -25,7 +26,10 @@ class User extends Authenticatable implements MustVerifyEmail use Bannable; use HasApiTokens; use HasCoverPhoto; + + /** @use HasFactory */ use HasFactory; + use HasProfilePhoto; use Notifiable; use Searchable; @@ -44,6 +48,8 @@ class User extends Authenticatable implements MustVerifyEmail /** * The relationship between a user and their mods. + * + * @return BelongsToMany */ public function mods(): BelongsToMany { @@ -52,6 +58,8 @@ class User extends Authenticatable implements MustVerifyEmail /** * The data that is searchable by Scout. + * + * @return array */ public function toSearchableArray(): array { @@ -132,6 +140,8 @@ class User extends Authenticatable implements MustVerifyEmail /** * The relationship between a user and their role. + * + * @return BelongsTo */ public function role(): BelongsTo { @@ -140,6 +150,10 @@ class User extends Authenticatable implements MustVerifyEmail /** * Scope a query by applying QueryFilter filters. + * + * @param Builder $builder + * @param QueryFilter $filters + * @return Builder */ public function scopeFilter(Builder $builder, QueryFilter $filters): Builder { @@ -156,6 +170,8 @@ class User extends Authenticatable implements MustVerifyEmail /** * The attributes that should be cast to native types. + * + * @return array */ protected function casts(): array {