🆙 phpstan done an refactoring 🆙

This commit is contained in:
Remco
2026-01-20 20:40:28 +01:00
parent fccf4c2116
commit 981fd59af5
14 changed files with 148 additions and 126 deletions
@@ -52,12 +52,18 @@ class CreateNewUser implements CreatesNewUsers
]);
}
$this->validate($input);
$validated = $this->validate($input);
if (! is_string($validated['username']) || ! is_string($validated['mail']) || ! is_string($validated['password'])) {
throw ValidationException::withMessages([
'registration' => __('Invalid registration data types'),
]);
}
$user = User::create([
'username' => $input['username'],
'mail' => $input['mail'],
'password' => Hash::make((string) $input['password']),
'username' => $validated['username'],
'mail' => $validated['mail'],
'password' => Hash::make($validated['password']),
'account_created' => time(),
'last_login' => time(),
'motto' => setting('start_motto') ?: 'Welcome to the hotel!',
@@ -5,8 +5,11 @@ namespace App\Actions\Fortify;
class DisableTwoFactorAuthentication extends \Laravel\Fortify\Actions\DisableTwoFactorAuthentication
{
#[\Override]
public function __invoke($user)
public function __invoke($user): void
{
if (! $user instanceof \App\Models\User) {
return;
}
$user->forceFill([
'two_factor_secret' => null,
'two_factor_recovery_codes' => null,
@@ -45,18 +45,13 @@ class RedirectIfTwoFactorAuthenticatable
$this->limiter = $limiter;
}
/**
* Handle the incoming request.
*
* @return mixed
*/
public function handle(Request $request, callable $next)
public function handle(Request $request, callable $next): mixed
{
$user = $this->validateCredentials($request);
if (Fortify::confirmsTwoFactorAuthentication()) {
if ($user?->two_factor_secret &&
! is_null($user?->two_factor_confirmed_at) &&
if ($user->two_factor_secret &&
! is_null($user->two_factor_confirmed_at) &&
in_array(TwoFactorAuthenticatable::class, class_uses_recursive($user))) {
return $this->twoFactorChallengeResponse($request, $user);
} else {
@@ -64,7 +59,7 @@ class RedirectIfTwoFactorAuthenticatable
}
}
if ($user?->two_factor_secret &&
if ($user->two_factor_secret &&
in_array(TwoFactorAuthenticatable::class, class_uses_recursive($user))) {
return $this->twoFactorChallengeResponse($request, $user);
}
@@ -72,49 +67,45 @@ class RedirectIfTwoFactorAuthenticatable
return $next($request);
}
/**
* Attempt to validate the incoming credentials.
*
* @return mixed
*/
protected function validateCredentials(Request $request)
protected function validateCredentials(Request $request): User
{
if (Fortify::$authenticateUsingCallback) {
return tap(call_user_func(Fortify::$authenticateUsingCallback, $request), function ($user) use ($request): void {
if (! $user) {
$this->fireFailedEvent($request);
// Skip Fortify authenticateUsingCallback for strict typing; rely on default provider validation
$this->throwFailedAuthenticationException($request);
}
});
$usernameField = Fortify::username();
$username = $request->input($usernameField);
if (! is_string($username)) {
$this->throwFailedAuthenticationException($request);
}
$model = $this->guard->getProvider()->getModel();
$user = User::query()
->where($usernameField, $username)
->firstOrFail();
return tap($model::where(Fortify::username(), $request->{Fortify::username()})->first(), function ($user) use ($request): void {
// Update the users password to bcrypt, if they previously used md5
if ($user && config('habbo.site.convert_passwords')) {
$this->convertUserPassword($user, $request->input('password'));
}
$passwordInput = $request->input('password');
if (! is_string($passwordInput)) {
$this->throwFailedAuthenticationException($request);
}
if (! $user || ! $this->guard->getProvider()->validateCredentials($user, ['password' => $request->password])) {
$this->fireFailedEvent($request, $user);
if (config('habbo.site.convert_passwords')) {
$passwordStr = is_string($passwordInput) ? $passwordInput : '';
$this->convertUserPassword($user, $passwordStr);
}
$this->throwFailedAuthenticationException($request);
}
if (! $this->guard->getProvider()->validateCredentials($user, ['password' => $passwordInput])) {
$this->fireFailedEvent($request, $user);
$this->validate($request);
$this->throwFailedAuthenticationException($request);
}
$user = User::select('id', 'password', 'rank')
->where('username', '=', $request->input('username'))
->first();
$this->validate($request);
if (setting('maintenance_enabled') === '1' && setting('min_maintenance_login_rank') > $user->rank) {
throw ValidationException::withMessages([
'username' => __('Only staff can login during maintenance!'),
]);
}
});
if (setting('maintenance_enabled') === '1' && (int) setting('min_maintenance_login_rank') > (int) $user->rank) {
throw ValidationException::withMessages([
'username' => __('Only staff can login during maintenance!'),
]);
}
return $user;
}
/**
@@ -137,18 +128,15 @@ class RedirectIfTwoFactorAuthenticatable
*/
protected function fireFailedEvent(Request $request, ?Authenticatable $user = null): void
{
event(new Failed(config('fortify.guard'), $user, [
$guard = config('fortify.guard');
$guardName = is_string($guard) ? $guard : 'web';
event(new Failed($guardName, $user, [
Fortify::username() => $request->{Fortify::username()},
'password' => $request->password,
]));
}
/**
* Get the two factor authentication enabled response.
*
* @param mixed $user
*/
protected function twoFactorChallengeResponse(Request $request, $user): Response
protected function twoFactorChallengeResponse(Request $request, User $user): Response
{
$request->session()->put([
'login.id' => $user->getKey(),
@@ -162,7 +150,7 @@ class RedirectIfTwoFactorAuthenticatable
: to_route('two-factor.login');
}
private function convertUserPassword(User $user, string $password)
private function convertUserPassword(User $user, string $password): void
{
if ($user->password == md5($password)) {
$user->update([
@@ -2,6 +2,8 @@
namespace App\Actions\Fortify;
use App\Actions\Fortify\Rules\PasswordValidationRules;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
@@ -10,19 +12,18 @@ class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
* @param mixed $user
*/
public function reset($user, array $input): void
public function reset(User $user, array $input): void
{
Validator::make($input, [
$validated = Validator::make($input, [
'password' => $this->passwordRules(),
])->validate();
if (! is_string($validated['password'])) {
return;
}
$user->forceFill([
'password' => Hash::make($input['password']),
'password' => Hash::make($validated['password']),
])->save();
}
}
@@ -2,6 +2,8 @@
namespace App\Actions\Fortify;
use App\Actions\Fortify\Rules\PasswordValidationRules;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
@@ -10,22 +12,21 @@ class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
/**
* Validate and update the user's password.
*
* @param mixed $user
*/
public function update($user, array $input): void
public function update(User $user, array $input): void
{
Validator::make($input, [
$validated = Validator::make($input, [
'current_password' => ['required', 'string', 'current_password:web'],
'password' => $this->passwordRules(),
], [
'current_password.current_password' => __('The provided password does not match your current password.'),
])->validateWithBag('updatePassword');
if (! is_string($validated['password'])) {
return;
}
$user->forceFill([
'password' => Hash::make($input['password']),
'password' => Hash::make($validated['password']),
])->save();
}
}
@@ -2,6 +2,7 @@
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
@@ -9,12 +10,7 @@ use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{
/**
* Validate and update the given user's profile information.
*
* @param mixed $user
*/
public function update($user, array $input): void
public function update(User $user, array $input): void
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
@@ -24,31 +20,26 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
'string',
'email',
'max:255',
Rule::unique('users')->ignore($user->id),
Rule::unique('users', 'mail')->ignore($user->id),
],
])->validateWithBag('updateProfileInformation');
if ($input['email'] !== $user->email &&
if ($input['email'] !== $user->mail &&
$user instanceof MustVerifyEmail) {
$this->updateVerifiedUser($user, $input);
} else {
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
'mail' => $input['email'],
])->save();
}
}
/**
* Update the given verified user's profile information.
*
* @param mixed $user
*/
protected function updateVerifiedUser($user, array $input): void
protected function updateVerifiedUser(User $user, array $input): void
{
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
'mail' => $input['email'],
'email_verified_at' => null,
])->save();
+12 -4
View File
@@ -12,14 +12,22 @@ class SendFurniture
public function execute(User $user, array $furniture): void
{
foreach ($furniture as $furni) {
if (! is_array($furni)) {
continue;
}
$amount = is_numeric($furni['amount'] ?? null) ? (int) $furni['amount'] : 0;
$itemId = is_numeric($furni['item_id'] ?? null) ? (int) $furni['item_id'] : 0;
if ($amount <= 0 || $itemId <= 0) {
continue;
}
if ($this->rcon->isConnected) {
for ($i = 0; $i < $furni['amount']; $i++) {
$this->rcon->sendGift($user, $furni['item_id'], 'Thank you for supporting ' . setting('hotel_name'));
for ($i = 0; $i < $amount; $i++) {
$this->rcon->sendGift($user, $itemId, 'Thank you for supporting ' . setting('hotel_name'));
}
} else {
for ($i = 0; $i < $furni['amount']; $i++) {
for ($i = 0; $i < $amount; $i++) {
$user->items()->create([
'item_id' => $furni['item_id'],
'item_id' => $itemId,
]);
}
}
+6 -4
View File
@@ -2,30 +2,32 @@
namespace App\Actions;
use App\Models\User;
class UserActions
{
public function updateUsername($user, $username): void
public function updateUsername(User $user, string $username): void
{
$user->update([
'username' => $username,
]);
}
public function updateEmail($user, $email): void
public function updateEmail(User $user, string $email): void
{
$user->update([
'mail' => $email,
]);
}
public function updateMotto($user, $motto): void
public function updateMotto(User $user, string $motto): void
{
$user->update([
'motto' => $motto,
]);
}
public function updateField($user, string $field, ?string $value): void
public function updateField(User $user, string $field, ?string $value): void
{
$user->update([
$field => $value,
@@ -12,7 +12,7 @@ class AtomSetupCommand extends Command
protected $description = 'Takes you through a basic setup, allowing you to define general settings';
private function progressInfo(int $step)
private function progressInfo(int $step): void
{
$this->info(sprintf('Step %s/13', $step));
$this->newLine();
@@ -57,12 +57,19 @@ class ImportAdsData extends Command
private function getImageFiles(string $adsPath): array
{
return array_filter(scandir($adsPath), function ($file) use ($adsPath) {
$filePath = $adsPath . DIRECTORY_SEPARATOR . $file;
$files = scandir($adsPath);
if (! is_array($files)) {
return [];
}
return is_file($filePath) &&
in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), self::ALLOWED_EXTENSIONS);
$filtered = array_filter($files, function (string $file) use ($adsPath): bool {
$filePath = $adsPath . DIRECTORY_SEPARATOR . $file;
$ext = pathinfo($file, PATHINFO_EXTENSION);
$ext = strtolower((string) $ext);
return is_file($filePath) && in_array($ext, self::ALLOWED_EXTENSIONS, true);
});
return array_values(array_map(fn ($f): string => (string) $f, $filtered));
}
private function processFiles(array $files): void
@@ -71,8 +78,8 @@ class ImportAdsData extends Command
$existingImages = WebsiteAd::pluck('image')->toArray();
$newFiles = Collection::make($files)
->filter(fn ($file) => ! in_array($file, $existingImages))
->map(fn ($file) => ['image' => $file])
->filter(fn ($file): bool => is_string($file) && ! in_array($file, $existingImages, true))
->map(fn (string $file): array => ['image' => $file])
->values();
$skippedCount = count($files) - $newFiles->count();
@@ -80,9 +87,11 @@ class ImportAdsData extends Command
$this->warn("Skipped {$skippedCount} existing files.");
}
$newFiles->chunk(self::CHUNK_SIZE)->each(function ($chunk): void {
WebsiteAd::insert($chunk->toArray());
$this->info('Processed ' . $chunk->count() . ' files.');
});
$newFiles->chunk(self::CHUNK_SIZE)->each(
function (Collection $chunk): void {
WebsiteAd::insert($chunk->toArray());
$this->info('Processed ' . $chunk->count() . ' files.');
},
);
}
}
+10 -5
View File
@@ -16,14 +16,19 @@ enum AchievementCategory: string
public static function values(): array
{
return array_column(self::cases(), 'value');
$values = [];
foreach (self::cases() as $case) {
$values[] = $case->value;
}
return $values;
}
public static function toInput(): array
{
$allCategories = self::cases();
$keys = array_map(fn (self $c): string => $c->value, $allCategories);
$values = array_map(fn (self $c): string => $c->name, $allCategories);
return array_combine($keys, $values) ?: [];
$result = [];
foreach (self::cases() as $case) {
$result[$case->value] = $case->name;
}
return $result;
}
}
+10 -5
View File
@@ -11,7 +11,11 @@ enum CurrencyTypes: int
public static function values(): array
{
return array_column(self::cases(), 'value');
$values = [];
foreach (self::cases() as $case) {
$values[] = $case->value;
}
return $values;
}
public static function fromCurrencyName(string $currencyName): ?self
@@ -39,9 +43,10 @@ enum CurrencyTypes: int
public static function toInput(): array
{
$allCurrencies = self::cases();
$keys = array_map(fn (self $c): int => $c->value, $allCurrencies);
$values = array_map(fn (self $c): string => $c->name, $allCurrencies);
return array_combine($keys, $values) ?: [];
$result = [];
foreach (self::cases() as $case) {
$result[$case->value] = $case->name;
}
return $result;
}
}
@@ -9,19 +9,20 @@ use Illuminate\Database\Eloquent\Builder;
class DateRangeFilter extends Filter
{
#[\Override]
public static function make(string $name): static
public static function make(?string $name = null): static
{
return parent::make($name)
$filterName = $name ?? 'date';
return parent::make($filterName)
->schema([
DatePicker::make("{$name}_from"),
DatePicker::make("{$name}_until"),
DatePicker::make("{$filterName}_from"),
DatePicker::make("{$filterName}_until"),
])
->query(function (Builder $query, array $data) use ($name): Builder {
if (isset($data["{$name}_from"]) && is_string($data["{$name}_from"])) {
$query->whereDate($name, '>=', $data["{$name}_from"]);
->query(function (Builder $query, array $data) use ($filterName): Builder {
if (isset($data["{$filterName}_from"]) && is_string($data["{$filterName}_from"])) {
$query->whereDate($filterName, '>=', $data["{$filterName}_from"]);
}
if (isset($data["{$name}_until"]) && is_string($data["{$name}_until"])) {
$query->whereDate($name, '<=', $data["{$name}_until"]);
if (isset($data["{$filterName}_until"]) && is_string($data["{$filterName}_until"])) {
$query->whereDate($filterName, '<=', $data["{$filterName}_until"]);
}
return $query;
});
+3 -1
View File
@@ -25,7 +25,9 @@ parameters:
- '#extends generic class .*Factory but does not specify its types#'
- '#extends generic class .*Builder but does not specify its types#'
- '#return type with generic class .*Builder does not specify its types#'
- '#missingType\\.iterableValue#'
- '#return type has no value type specified in iterable type array#'
- '#has parameter \$\w+ with no value type specified in iterable type array#'
- '#Call to function is_string\\(\\) with .* will always evaluate to true#'
- '#should return array<string, mixed> but returns array#'
reportUnmatchedIgnoredErrors: false