Add phpstan for static analysis (#3718)

This commit is contained in:
Dane Everitt 2021-10-30 13:41:38 -07:00 committed by GitHub
parent 871d0bdd1c
commit cdd8eabcc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
103 changed files with 1286 additions and 877 deletions

View file

@ -5,6 +5,7 @@ APP_THEME=pterodactyl
APP_TIMEZONE=America/Los_Angeles
APP_URL=http://localhost/
DB_CONNECTION=testing
TESTING_DB_HOST=127.0.0.1
TESTING_DB_DATABASE=panel_test
TESTING_DB_USERNAME=root

View file

@ -37,9 +37,7 @@ jobs:
path: |
~/.php_cs.cache
${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-cache-${{ matrix.php }}-${{ hashFiles('**.composer.lock') }}
restore-keys: |
${{ runner.os }}-cache-${{ matrix.php }}-
key: ${{ runner.os }}-cache-${{ matrix.php }}-${{ hashFiles('composer.lock') }}
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
@ -52,16 +50,22 @@ jobs:
- name: composer install
run: composer install --prefer-dist --no-interaction --no-progress
- name: Run cs-fixer
run: vendor/bin/php-cs-fixer fix --dry-run --diff --diff-format=udiff --config .php-cs-fixer.dist.php
run: vendor/bin/php-cs-fixer fix --dry-run --diff --format=txt --config .php-cs-fixer.dist.php
continue-on-error: true
- name: Static Analysis
if: ${{ matrix.php }} == '8.0'
run: |
php artisan ide-helper:models -N
./vendor/bin/phpstan analyse --memory-limit=2G
env:
TESTING_DB_PORT: ${{ job.services.database.ports[3306] }}
- name: Execute Unit Tests
run: php artisan test tests/Unit
if: ${{ always() }}
env:
TESTING_DB_PORT: ${{ job.services.database.ports[3306] }}
TESTING_DB_USERNAME: root
- name: Execute Integration Tests
run: php artisan test tests/Integration
if: ${{ always() }}
env:
TESTING_DB_PORT: ${{ job.services.database.ports[3306] }}
TESTING_DB_USERNAME: root

View file

@ -10,6 +10,9 @@ $finder = (new Finder())
'node_modules',
'storage',
'bootstrap/cache',
'.phpstorm.meta.php',
'_ide_helper.php',
'_ide_helper_models.php',
])
->notName(['_ide_helper*']);

View file

@ -54,15 +54,15 @@ class InfoCommand extends Command
$this->output->title('Version Information');
$this->table([], [
['Panel Version', $this->config->get('app.version')],
['Latest Version', $this->versionService->getPanel()],
['Latest Version', $this->versionService->getLatestPanel()],
['Up-to-Date', $this->versionService->isLatestPanel() ? 'Yes' : $this->formatText('No', 'bg=red')],
['Unique Identifier', $this->config->get('pterodactyl.service.author')],
], 'compact');
$this->output->title('Application Configuration');
$this->table([], [
['Environment', $this->formatText($this->config->get('app.env'), $this->config->get('app.env') === 'production' ?: 'bg=red')],
['Debug Mode', $this->formatText($this->config->get('app.debug') ? 'Yes' : 'No', !$this->config->get('app.debug') ?: 'bg=red')],
['Environment', $this->formatText($this->config->get('app.env'), $this->config->get('app.env') === 'production' ? '' : 'bg=red')],
['Debug Mode', $this->formatText($this->config->get('app.debug') ? 'Yes' : 'No', !$this->config->get('app.debug') ? '' : 'bg=red')],
['Installation URL', $this->config->get('app.url')],
['Installation Directory', base_path()],
['Timezone', $this->config->get('app.timezone')],

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Console\Commands\Location;
@ -26,9 +19,9 @@ class DeleteLocationCommand extends Command
protected $description = 'Deletes a location from the Panel.';
/**
* @var \Illuminate\Support\Collection
* @var \Illuminate\Support\Collection|null
*/
protected $locations;
protected $locations = null;
/**
* @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface

View file

@ -13,14 +13,14 @@ class SeedCommand extends BaseSeedCommand
* Block someone from running this seed command if they have not completed
* the migration process.
*/
public function handle()
public function handle(): int
{
if (!$this->hasCompletedMigrations()) {
$this->showMigrationWarning();
return;
return 1;
}
parent::handle();
return parent::handle();
}
}

View file

@ -13,14 +13,14 @@ class UpCommand extends BaseUpCommand
* Block someone from running this up command if they have not completed
* the migration process.
*/
public function handle()
public function handle(): int
{
if (!$this->hasCompletedMigrations()) {
$this->showMigrationWarning();
return;
return 1;
}
parent::handle();
return parent::handle();
}
}

View file

@ -24,7 +24,7 @@ class ProcessRunnableCommand extends Command
/**
* Handle command execution.
*/
public function handle()
public function handle(): int
{
$schedules = Schedule::query()->with('tasks')
->where('is_active', true)
@ -35,7 +35,7 @@ class ProcessRunnableCommand extends Command
if ($schedules->count() < 1) {
$this->line('There are no scheduled tasks for servers that need to be run.');
return;
return 0;
}
$bar = $this->output->createProgressBar(count($schedules));
@ -47,6 +47,8 @@ class ProcessRunnableCommand extends Command
}
$this->line('');
return 0;
}
/**
@ -69,7 +71,7 @@ class ProcessRunnableCommand extends Command
'schedule' => $schedule->name,
'hash' => $schedule->hashid,
]));
} catch (Throwable | Exception $exception) {
} catch (Throwable|Exception $exception) {
Log::error($exception, ['schedule_id' => $schedule->id]);
$this->error("An error was encountered while processing Schedule #{$schedule->id}: " . $exception->getMessage());

View file

@ -87,11 +87,12 @@ class UpgradeCommand extends Command
if (!$this->confirm('Are you sure you want to run the upgrade process for your Panel?')) {
$this->warn('Upgrade process terminated by user.');
return;
}
}
ini_set('output_buffering', 0);
ini_set('output_buffering', '0');
$bar = $this->output->createProgressBar($skipDownload ? 9 : 10);
$bar->start();

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Console\Commands\User;
@ -47,11 +40,9 @@ class DeleteUserCommand extends Command
}
/**
* @return bool
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function handle()
public function handle(): int
{
$search = $this->option('user') ?? $this->ask(trans('command/messages.user.search_users'));
Assert::notEmpty($search, 'Search term should be an email address, got: %s.');
@ -68,13 +59,13 @@ class DeleteUserCommand extends Command
return $this->handle();
}
return false;
return 1;
}
if ($this->input->isInteractive()) {
$tableValues = [];
foreach ($results as $user) {
$tableValues[] = [$user->id, $user->email, $user->name];
$tableValues[] = [$user->id, $user->email, $user->name_first];
}
$this->table(['User ID', 'Email', 'Name'], $tableValues);
@ -85,7 +76,7 @@ class DeleteUserCommand extends Command
if (count($results) > 1) {
$this->error(trans('command/messages.user.multiple_found'));
return false;
return 1;
}
$deleteUser = $results->first();
@ -95,5 +86,7 @@ class DeleteUserCommand extends Command
$this->deletionService->handle($deleteUser);
$this->info(trans('command/messages.user.deleted'));
}
return 0;
}
}

View file

@ -62,7 +62,7 @@ class MakeUserCommand extends Command
['UUID', $user->uuid],
['Email', $user->email],
['Username', $user->username],
['Name', $user->name],
['Name', $user->name_first],
['Admin', $user->root_admin ? 'Yes' : 'No'],
]);
}

View file

@ -39,10 +39,8 @@ interface DatabaseRepositoryInterface extends RepositoryInterface
/**
* Create a new database user on a given connection.
*
* @param $max_connections
*/
public function createUser(string $username, string $remote, string $password, string $max_connections): bool;
public function createUser(string $username, string $remote, string $password, int $max_connections): bool;
/**
* Give a specific user access to a given database.
@ -61,8 +59,6 @@ interface DatabaseRepositoryInterface extends RepositoryInterface
/**
* Drop a given user on a specific connection.
*
* @return mixed
*/
public function dropUser(string $username, string $remote): bool;
}

View file

@ -20,8 +20,6 @@ interface LocationRepositoryInterface extends RepositoryInterface
/**
* Return all of the nodes and their respective count of servers for a location.
*
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithNodes(int $id): Location;
@ -29,8 +27,6 @@ interface LocationRepositoryInterface extends RepositoryInterface
/**
* Return a location and the count of nodes in that location.
*
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithNodeCount(int $id): Location;

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Contracts\Repository;
@ -16,27 +9,7 @@ interface NestRepositoryInterface extends RepositoryInterface
/**
* Return a nest or all nests with their associated eggs and variables.
*
* @param int $id
*
* @return \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Nest
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithEggs(int $id = null);
/**
* Return a nest or all nests and the count of eggs and servers for that nest.
*
* @return \Pterodactyl\Models\Nest|\Illuminate\Database\Eloquent\Collection
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithCounts(int $id = null);
/**
* Return a nest along with its associated eggs and the servers relation on those eggs.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithEggServers(int $id): Nest;
public function getWithEggs(int $id = null): Nest;
}

View file

@ -21,20 +21,20 @@ class Fractal extends SpatieFractal
public function createData()
{
// Set the serializer by default.
if (is_null($this->serializer)) {
if (is_null($this->serializer)) { // @phpstan-ignore-line
$this->serializer = new PterodactylSerializer();
}
// Automatically set the paginator on the response object if the
// data being provided implements a paginator.
if (is_null($this->paginator) && $this->data instanceof LengthAwarePaginator) {
if (is_null($this->paginator) && $this->data instanceof LengthAwarePaginator) { // @phpstan-ignore-line
$this->paginator = new IlluminatePaginatorAdapter($this->data);
}
// If the resource name is not set attempt to pull it off the transformer
// itself and set it automatically.
$class = is_string($this->transformer) ? new $this->transformer() : $this->transformer;
if (is_null($this->resourceName) && $class instanceof Transformer) {
if (is_null($this->resourceName) && $class instanceof Transformer) { // @phpstan-ignore-line
$this->resourceName = $class->getResourceName();
}

View file

@ -17,6 +17,6 @@ final class Time
{
$offset = round(CarbonImmutable::now($timezone)->getTimezone()->getOffset(CarbonImmutable::now('UTC')) / 3600);
return sprintf('%s%s:00', $offset > 0 ? '+' : '-', str_pad(abs($offset), 2, '0', STR_PAD_LEFT));
return sprintf('%s%s:00', $offset > 0 ? '+' : '-', str_pad((string) abs($offset), 2, '0', STR_PAD_LEFT));
}
}

View file

@ -40,7 +40,7 @@ class DatabaseController extends ApplicationApiController
*/
public function index(GetDatabasesRequest $request): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}

View file

@ -36,11 +36,12 @@ class EggController extends ApplicationApiController
*/
public function index(GetEggsRequest $request, Nest $nest): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}
// @phpstan-ignore-next-line
$eggs = QueryBuilder::for(Egg::query())
->where('nest_id', '=', $nest->id)
->allowedFilters(['id', 'name', 'author'])

View file

@ -55,7 +55,7 @@ class EggVariableController extends ApplicationApiController
{
$validated = $request->validated();
$this->connection->transaction(function () use($egg, $validated) {
$this->connection->transaction(function () use ($egg, $validated) {
foreach ($validated as $data) {
$this->variableUpdateService->handle($egg, $data);
}

View file

@ -46,7 +46,7 @@ class LocationController extends ApplicationApiController
*/
public function index(GetLocationsRequest $request): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}

View file

@ -34,7 +34,7 @@ class MountController extends ApplicationApiController
*/
public function index(GetMountsRequest $request): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}

View file

@ -13,8 +13,8 @@ use Pterodactyl\Transformers\Api\Application\EggTransformer;
use Pterodactyl\Transformers\Api\Application\NestTransformer;
use Pterodactyl\Exceptions\Http\QueryValueOutOfRangeHttpException;
use Pterodactyl\Http\Requests\Api\Application\Nests\GetNestRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\GetNestsRequest;
use Pterodactyl\Http\Requests\Api\Application\Eggs\ImportEggRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\GetNestsRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\StoreNestRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\DeleteNestRequest;
use Pterodactyl\Http\Requests\Api\Application\Nests\UpdateNestRequest;
@ -51,7 +51,7 @@ class NestController extends ApplicationApiController
*/
public function index(GetNestsRequest $request): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}

View file

@ -42,7 +42,7 @@ class AllocationController extends ApplicationApiController
*/
public function index(GetAllocationsRequest $request, Node $node): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}

View file

@ -50,7 +50,7 @@ class NodeController extends ApplicationApiController
*/
public function index(GetNodesRequest $request): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}

View file

@ -35,7 +35,7 @@ class NodeDeploymentController extends ApplicationApiController
$nodes = $this->viableNodesService->setLocations($data['location_ids'] ?? [])
->setMemory($data['memory'])
->setDisk($data['disk'])
->handle($request->query('per_page'), $request->query('page'));
->handle($request->query('per_page'), $request->query('page')); // @phpstan-ignore-line
return $this->fractal->collection($nodes)
->transformWith(NodeTransformer::class)

View file

@ -32,7 +32,7 @@ class RoleController extends ApplicationApiController
*/
public function index(GetRolesRequest $request): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}

View file

@ -52,7 +52,7 @@ class ServerController extends ApplicationApiController
*/
public function index(GetServersRequest $request): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}

View file

@ -52,7 +52,7 @@ class UserController extends ApplicationApiController
*/
public function index(GetUsersRequest $request): array
{
$perPage = $request->query('per_page', 10);
$perPage = (int) $request->query('per_page', '10');
if ($perPage < 1 || $perPage > 100) {
throw new QueryValueOutOfRangeHttpException('per_page', 1, 100);
}

View file

@ -15,7 +15,7 @@ class AccountController extends ClientApiController
private UserUpdateService $updateService;
/**
* @var \Illuminate\Auth\SessionGuard
* @var \Illuminate\Auth\AuthManager
*/
private $sessionGuard;
@ -64,7 +64,9 @@ class AccountController extends ClientApiController
// cached copy of the user that does not include the updated password. Do this
// to correctly store the new user details in the guard and allow the logout
// other devices functionality to work.
$this->sessionGuard->setUser($user);
if (method_exists($this->sessionGuard, 'setUser')) {
$this->sessionGuard->setUser($user);
}
// TODO: Find another way to do this, function doesn't exist due to API changes.
//$this->sessionGuard->logoutOtherDevices($request->input('password'));

View file

@ -66,7 +66,7 @@ class ClientController extends ClientApiController
$builder = $builder->whereIn('servers.id', $user->accessibleServers()->pluck('id')->all());
}
$servers = $builder->paginate(min($request->query('per_page', 50), 100))->appends($request->query());
$servers = $builder->paginate(min((int) $request->query('per_page', '50'), 100))->appends($request->query());
return $this->fractal->transformWith(new ServerTransformer())->collection($servers)->toArray();
}

View file

@ -61,7 +61,6 @@ class StartupController extends ClientApiController
*/
public function update(UpdateStartupVariableRequest $request, Server $server): array
{
/** @var \Pterodactyl\Models\EggVariable $variable */
$variable = $server->variables()->where('env_variable', $request->input('key'))->first();
if (is_null($variable) || !$variable->user_viewable) {

View file

@ -87,8 +87,6 @@ class WebauthnController extends ClientApiController
$request->input('name'),
);
return $this->fractal->item($webauthnKey)
->transformWith(WebauthnKeyTransformer::class)
->toArray();

View file

@ -91,9 +91,6 @@ abstract class AbstractLoginController extends Controller
/**
* Determine if the user is logging in using an email or username,.
*
* @param string|null $input
* @return string
*/
protected function getField(string $input = null): string
{

View file

@ -16,7 +16,6 @@ class ForgotPasswordController extends Controller
/**
* Get the response for a failed password reset link.
*
* @param \Illuminate\Http\Request
* @param string $response
*/
protected function sendResetLinkFailedResponse(Request $request, $response): JsonResponse

View file

@ -2,8 +2,8 @@
namespace Pterodactyl\Http\Controllers\Auth;
use Carbon\CarbonInterface;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Pterodactyl\Models\User;
use PragmaRX\Google2FA\Google2FA;
use Illuminate\Contracts\Encryption\Encrypter;
@ -50,17 +50,20 @@ class LoginCheckpointController extends AbstractLoginController
{
if ($this->hasTooManyLoginAttempts($request)) {
$this->sendLockoutResponse($request);
return;
}
$details = $request->session()->get('auth_confirmation_token');
if (!$this->hasValidSessionData($details)) {
$this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE);
return;
}
if (!hash_equals($request->input('confirmation_token') ?? '', $details['token_value'])) {
$this->sendFailedLoginResponse($request);
return;
}
@ -69,6 +72,7 @@ class LoginCheckpointController extends AbstractLoginController
$user = User::query()->findOrFail($details['user_id']);
} catch (ModelNotFoundException $exception) {
$this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE);
return;
}
@ -91,8 +95,6 @@ class LoginCheckpointController extends AbstractLoginController
/**
* Determines if a given recovery token is valid for the user account. If we find a matching token
* it will be deleted from the database.
*
* @return bool
*/
protected function isValidRecoveryToken(User $user, string $value): bool
{
@ -116,9 +118,6 @@ class LoginCheckpointController extends AbstractLoginController
* Determines if the data provided from the session is valid or not. This
* will return false if the data is invalid, or if more time has passed than
* was configured when the session was written.
*
* @param array $data
* @return bool
*/
public static function isValidSessionData(ValidationFactory $validation, array $data): bool
{

View file

@ -10,7 +10,6 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Contracts\View\View;
use LaravelWebauthn\Facades\Webauthn;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\Database\Eloquent\ModelNotFoundException;
class LoginController extends AbstractLoginController
{
@ -24,7 +23,8 @@ class LoginController extends AbstractLoginController
/**
* LoginController constructor.
*/
public function __construct(ViewFactory $view) {
public function __construct(ViewFactory $view)
{
parent::__construct();
$this->view = $view;
@ -57,12 +57,11 @@ class LoginController extends AbstractLoginController
return;
}
try {
$username = $request->input('user');
$username = $request->input('user');
/** @var \Pterodactyl\Models\User $user */
$user = User::query()->where($this->getField($username), $username)->firstOrFail();
} catch (ModelNotFoundException $exception) {
/** @var \Pterodactyl\Models\User|null $user */
$user = User::query()->where($this->getField($username), $username)->first();
if (is_null($user)) {
$this->sendFailedLoginResponse($request);
}

View file

@ -87,7 +87,7 @@ class ResetPasswordController extends Controller
* account do not automatically log them in. In those cases, send the user back to the login
* form with a note telling them their password was changed and to log back in.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword|\Pterodactyl\Models\User $user
* @param \Pterodactyl\Models\User $user
* @param string $password
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException

View file

@ -38,17 +38,20 @@ class WebauthnController extends AbstractLoginController
{
if ($this->hasTooManyLoginAttempts($request)) {
$this->sendLockoutResponse($request);
return;
}
$details = $request->session()->get('auth_confirmation_token');
if (!LoginCheckpointController::isValidSessionData($this->validation, $details)) {
$this->sendFailedLoginResponse($request, null, LoginCheckpointController::TOKEN_EXPIRED_MESSAGE);
return;
}
if (!hash_equals($request->input('confirmation_token') ?? '', $details['token_value'])) {
$this->sendFailedLoginResponse($request);
return;
}
@ -57,6 +60,7 @@ class WebauthnController extends AbstractLoginController
$user = User::query()->findOrFail($details['user_id']);
} catch (ModelNotFoundException $exception) {
$this->sendFailedLoginResponse($request, null, LoginCheckpointController::TOKEN_EXPIRED_MESSAGE);
return;
}

View file

@ -109,7 +109,5 @@ class Kernel extends HttpKernel
'bindings' => SubstituteBindings::class,
'recaptcha' => VerifyReCaptcha::class,
'node.maintenance' => MaintenanceMiddleware::class,
// API Specific Middleware
'api..key' => AuthenticateKey::class,
];
}

View file

@ -54,7 +54,7 @@ class SubstituteApplicationApiBindings
try {
$this->router->substituteImplicitBindings($route = $request->route());
} catch (ModelNotFoundException $exception) {
if (isset($route) && $route->getMissing()) {
if (!empty($route) && $route->getMissing()) {
$route->getMissing()($request);
}

View file

@ -25,7 +25,7 @@ class SubstituteClientApiBindings
/**
* Perform substitution of route parameters for the Client API.
*
* @param \Illuminate\Http\Request
* @param \Illuminate\Http\Request $request
*
* @return mixed
*/
@ -76,7 +76,7 @@ class SubstituteClientApiBindings
/* @var \Illuminate\Routing\Route $route */
$this->router->substituteBindings($route = $request->route());
} catch (ModelNotFoundException $exception) {
if (isset($route) && $route->getMissing()) {
if (!empty($route) && $route->getMissing()) {
$route->getMissing()($request);
}

View file

@ -41,7 +41,7 @@ class RequireTwoFactorAuthentication
*/
public function handle(Request $request, Closure $next)
{
/** @var \Pterodactyl\Models\User $user */
/** @var \Pterodactyl\Models\User|null $user */
$user = $request->user();
$uri = rtrim($request->getRequestUri(), '/') . '/';
$current = $request->route()->getName();
@ -66,6 +66,7 @@ class RequireTwoFactorAuthentication
throw new TwoFactorAuthRequiredException();
}
// @phpstan-ignore-next-line
$this->alert->danger(trans('auth.2fa_must_be_enabled'))->flash();
return redirect()->to($this->redirectRoute);

View file

@ -3,7 +3,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Eggs\Variables;
use Pterodactyl\Models\EggVariable;
use Illuminate\Validation\Validator;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class UpdateEggVariablesRequest extends ApplicationApiRequest

View file

@ -3,9 +3,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers;
use Pterodactyl\Models\Server;
use Illuminate\Validation\Rule;
use Illuminate\Contracts\Validation\Validator;
use Pterodactyl\Models\Objects\DeploymentObject;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreServerRequest extends ApplicationApiRequest

View file

@ -65,8 +65,6 @@ abstract class SubuserRequest extends ClientApiRequest
// Otherwise, get the current subuser's permission set, and ensure that the
// permissions they are trying to assign are not _more_ than the ones they
// already have.
/** @var \Pterodactyl\Models\Subuser|null $subuser */
/** @var \Pterodactyl\Services\Servers\GetUserPermissionsService $service */
$service = $this->container->make(GetUserPermissionsService::class);
if (count(array_diff($permissions, $service->handle($server, $user))) > 0) {

View file

@ -101,7 +101,7 @@ class AuditLog extends Model
* currently authenticated user if available. This model is not saved at this point, so
* you can always make modifications to it as needed before saving.
*
* @return $this
* @return self
*/
public static function instance(string $action, array $metadata, bool $isSystem = false)
{

View file

@ -2,17 +2,6 @@
namespace Pterodactyl\Models;
/**
* @property int $id
* @property string $name
* @property string $host
* @property int $port
* @property string $username
* @property string $password
* @property int|null $max_databases
* @property \Carbon\CarbonImmutable $created_at
* @property \Carbon\CarbonImmutable $updated_at
*/
class DatabaseHost extends Model
{
/**

View file

@ -2,44 +2,6 @@
namespace Pterodactyl\Models;
/**
* @property int $id
* @property string $uuid
* @property int $nest_id
* @property string $author
* @property string $name
* @property string|null $description
* @property array|null $features
* @property string $docker_image -- deprecated, use $docker_images
* @property string $update_url
* @property array $docker_images
* @property array|null $file_denylist
* @property string|null $config_files
* @property string|null $config_startup
* @property string|null $config_stop
* @property int|null $config_from
* @property string|null $startup
* @property bool $script_is_privileged
* @property string|null $script_install
* @property string $script_entry
* @property string $script_container
* @property int|null $copy_script_from
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string|null $copy_script_install
* @property string $copy_script_entry
* @property string $copy_script_container
* @property string|null $inherit_config_files
* @property string|null $inherit_config_startup
* @property string|null $inherit_config_stop
* @property string $inherit_file_denylist
* @property array|null $inherit_features
* @property \Pterodactyl\Models\Nest $nest
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Server[] $servers
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\EggVariable[] $variables
* @property \Pterodactyl\Models\Egg|null $scriptFrom
* @property \Pterodactyl\Models\Egg|null $configFrom
*/
class Egg extends Model
{
/**
@ -162,10 +124,12 @@ class Egg extends Model
*/
public function getCopyScriptEntryAttribute()
{
// @phpstan-ignore-next-line
if (!is_null($this->script_entry) || is_null($this->copy_script_from)) {
return $this->script_entry;
}
// @phpstan-ignore-next-line
return $this->scriptFrom->script_entry;
}
@ -177,10 +141,12 @@ class Egg extends Model
*/
public function getCopyScriptContainerAttribute()
{
// @phpstan-ignore-next-line
if (!is_null($this->script_container) || is_null($this->copy_script_from)) {
return $this->script_container;
}
// @phpstan-ignore-next-line
return $this->scriptFrom->script_container;
}

View file

@ -2,25 +2,6 @@
namespace Pterodactyl\Models;
/**
* @property int $id
* @property int $egg_id
* @property string $name
* @property string $description
* @property string $env_variable
* @property string $default_value
* @property bool $user_viewable
* @property bool $user_editable
* @property string $rules
* @property \Carbon\CarbonImmutable $created_at
* @property \Carbon\CarbonImmutable $updated_at
* @property \Pterodactyl\Models\Egg $egg
* @property \Pterodactyl\Models\ServerVariable $serverVariable
*
* The "server_value" variable is only present on the object if you've loaded this model
* using the server relationship.
* @property string|null $server_value
*/
class EggVariable extends Model
{
/**

View file

@ -48,6 +48,7 @@ class MultiFieldServerFilter implements Filter
}
},
// Otherwise, just try to search for that specific port in the allocations.
// @phpstan-ignore-next-line
function (Builder $builder) use ($value) {
$builder->orWhere('allocations.port', 'LIKE', substr($value, 1) . '%');
}

View file

@ -23,22 +23,15 @@ abstract class Model extends IlluminateModel
/**
* Determines if the model should undergo data validation before it is saved
* to the database.
*
* @var bool
*/
protected $skipValidation = false;
protected bool $skipValidation = false;
/**
* The validator instance used by this model.
*
* @var \Illuminate\Validation\Validator
*/
protected $validator;
protected ?Validator $validator = null;
/**
* @var \Illuminate\Contracts\Validation\Factory
*/
protected static $validatorFactory;
protected static Factory $validatorFactory;
public static array $validationRules = [];
@ -82,6 +75,7 @@ abstract class Model extends IlluminateModel
{
$rules = $this->getKey() ? static::getRulesForUpdate($this) : static::getRules();
// @phpstan-ignore-next-line
return $this->validator ?: $this->validator = static::$validatorFactory->make(
[],
$rules,

View file

@ -8,38 +8,6 @@ use Illuminate\Container\Container;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Encryption\Encrypter;
/**
* @property int $id
* @property string $uuid
* @property bool $public
* @property string $name
* @property string|null $description
* @property int $location_id
* @property int|null $database_host_id
* @property string $fqdn
* @property int $listen_port_http
* @property int $public_port_http
* @property int $listen_port_sftp
* @property int $public_port_sftp
* @property string $scheme
* @property bool $behind_proxy
* @property bool $maintenance_mode
* @property int $memory
* @property int $memory_overallocate
* @property int $disk
* @property int $disk_overallocate
* @property int $upload_size
* @property string $daemon_token_id
* @property string $daemon_token
* @property string $daemon_base
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Pterodactyl\Models\Location $location
* @property \Pterodactyl\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
* @property \Pterodactyl\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations
* @property \Pterodactyl\Models\DatabaseHost $databaseHost
*/
class Node extends Model
{
use Notifiable;
@ -275,6 +243,7 @@ class Node extends Model
$memoryLimit = $this->memory * (1 + ($this->memory_overallocate / 100));
$diskLimit = $this->disk * (1 + ($this->disk_overallocate / 100));
// @phpstan-ignore-next-line
return ($this->sum_memory + $memory) <= $memoryLimit && ($this->sum_disk + $disk) <= $diskLimit;
}
}

View file

@ -213,7 +213,7 @@ class Permission extends Model
* Returns all of the permissions available on the system for a user to
* have when controlling a server.
*
* @return \Illuminate\Database\Eloquent\Collection
* @phpstan-return \Illuminate\Support\Collection<string, array{description: string, keys: array<string, string>}>
*/
public static function permissions(): Collection
{

View file

@ -8,50 +8,6 @@ use Illuminate\Database\Query\JoinClause;
use Znck\Eloquent\Traits\BelongsToThrough;
use Pterodactyl\Exceptions\Http\Server\ServerStateConflictException;
/**
* @property int $id
* @property string|null $external_id
* @property string $uuid
* @property string $uuidShort
* @property int $node_id
* @property string $name
* @property string $description
* @property string|null $status
* @property bool $skip_scripts
* @property int $owner_id
* @property int $memory
* @property int $swap
* @property int $disk
* @property int $io
* @property int $cpu
* @property string $threads
* @property bool $oom_disabled
* @property int $allocation_id
* @property int $nest_id
* @property int $egg_id
* @property string $startup
* @property string $image
* @property int $allocation_limit
* @property int $database_limit
* @property int $backup_limit
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Pterodactyl\Models\User $user
* @property \Pterodactyl\Models\Subuser[]|\Illuminate\Database\Eloquent\Collection $subusers
* @property \Pterodactyl\Models\Allocation $allocation
* @property \Pterodactyl\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations
* @property \Pterodactyl\Models\Node $node
* @property \Pterodactyl\Models\Nest $nest
* @property \Pterodactyl\Models\Egg $egg
* @property \Pterodactyl\Models\EggVariable[]|\Illuminate\Database\Eloquent\Collection $variables
* @property \Pterodactyl\Models\Schedule[]|\Illuminate\Database\Eloquent\Collection $schedule
* @property \Pterodactyl\Models\Database[]|\Illuminate\Database\Eloquent\Collection $databases
* @property \Pterodactyl\Models\Location $location
* @property \Pterodactyl\Models\ServerTransfer $transfer
* @property \Pterodactyl\Models\Backup[]|\Illuminate\Database\Eloquent\Collection $backups
* @property \Pterodactyl\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts
* @property \Pterodactyl\Models\AuditLog[] $audits
*/
class Server extends Model
{
use BelongsToThrough;
@ -239,6 +195,7 @@ class Server extends Model
* Gets information for the service variables associated with this server.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
* @phpstan-return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\EggVariable>
*/
public function variables()
{

View file

@ -58,7 +58,7 @@ class AccountCreated extends Notification implements ShouldQueue
public function toMail($notifiable)
{
$message = (new MailMessage())
->greeting('Hello ' . $this->user->name . '!')
->greeting('Hello ' . $this->user->name_first . '!')
->line('You are receiving this email because an account has been created for you on ' . config('app.name') . '.')
->line('Username: ' . $this->user->username)
->line('Email: ' . $this->user->email);

View file

@ -27,7 +27,7 @@ class MailTested extends Notification
{
return (new MailMessage())
->subject('Pterodactyl Test Message')
->greeting('Hello ' . $this->user->name . '!')
->greeting('Hello ' . $this->user->name_first . '!')
->line('This is a test of the Pterodactyl mail system. You\'re good to go!');
}
}

View file

@ -2,6 +2,7 @@
namespace Pterodactyl\Notifications;
use Webmozart\Assert\Assert;
use Illuminate\Bus\Queueable;
use Pterodactyl\Events\Event;
use Illuminate\Container\Container;
@ -33,6 +34,8 @@ class ServerInstalled extends Notification implements ShouldQueue, ReceivesEvent
*/
public function handle(Event $event): void
{
Assert::propertyExists($event, 'server');
$event->server->loadMissing('user');
$this->server = $event->server;

View file

@ -20,10 +20,12 @@ class BackupRepository extends EloquentRepository
/**
* Determines if too many backups have been generated by the server.
*
* @return \Pterodactyl\Models\Backup[]|\Illuminate\Support\Collection
* @return \Illuminate\Support\Collection
* @phpstan-return \Illuminate\Support\Collection<\Pterodactyl\Models\Backup>
*/
public function getBackupsGeneratedDuringTimespan(int $server, int $seconds = 600)
{
// @phpstan-ignore-next-line
return $this->getBuilder()
->withTrashed()
->where('server_id', $server)

View file

@ -89,10 +89,8 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
/**
* Create a new database user on a given connection.
*
* @param $max_connections
*/
public function createUser(string $username, string $remote, string $password, $max_connections): bool
public function createUser(string $username, string $remote, string $password, int $max_connections): bool
{
if (!$max_connections) {
return $this->run(sprintf('CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'', $username, $remote, $password));
@ -132,8 +130,6 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
/**
* Drop a given user on a specific connection.
*
* @return mixed
*/
public function dropUser(string $username, string $remote): bool
{

View file

@ -29,6 +29,8 @@ class EggRepository extends EloquentRepository implements EggRepositoryInterface
public function getWithVariables(int $id): Egg
{
try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('variables')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException();
@ -55,6 +57,8 @@ class EggRepository extends EloquentRepository implements EggRepositoryInterface
Assert::true((is_digit($value) || is_string($value)), 'First argument passed to getWithCopyAttributes must be an integer or string, received %s.');
try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('scriptFrom', 'configFrom')->where($column, '=', $value)->firstOrFail($this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException();
@ -69,6 +73,8 @@ class EggRepository extends EloquentRepository implements EggRepositoryInterface
public function getWithExportAttributes(int $id): Egg
{
try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('scriptFrom', 'configFrom', 'variables')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException();

View file

@ -4,6 +4,7 @@ namespace Pterodactyl\Repositories\Eloquent;
use Illuminate\Http\Request;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\Model;
use Illuminate\Support\Collection;
use Pterodactyl\Repositories\Repository;
use Illuminate\Database\Eloquent\Builder;
@ -25,12 +26,8 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
* Determines if the repository function should use filters off the request object
* present when returning results. This allows repository methods to be called in API
* context's such that we can pass through ?filter[name]=Dane&sort=desc for example.
*
* @param bool $usingFilters
*
* @return $this
*/
public function usingRequestFilters($usingFilters = true)
public function usingRequestFilters(bool $usingFilters = true): self
{
$this->useRequestFilters = $usingFilters;
@ -39,26 +36,22 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
/**
* Returns the request instance.
*
* @return \Illuminate\Http\Request
*/
protected function request()
protected function request(): Request
{
return $this->app->make(Request::class);
}
/**
* Paginate the response data based on the page para.
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
protected function paginate(Builder $instance, int $default = 50)
protected function paginate(Builder $instance, int $default = 50): LengthAwarePaginator
{
if (!$this->useRequestFilters) {
return $instance->paginate($default);
}
return $instance->paginate($this->request()->query('per_page', $default));
return $instance->paginate((int) $this->request()->query('per_page', (string) $default));
}
/**
@ -91,15 +84,20 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
*/
public function create(array $fields, bool $validate = true, bool $force = false)
{
/** @phpstan-var \Illuminate\Database\Eloquent\Model $instance */
$instance = $this->getBuilder()->newModelInstance();
($force) ? $instance->forceFill($fields) : $instance->fill($fields);
if (!$validate) {
$saved = $instance->skipValidation()->save();
} else {
if (!$saved = $instance->save()) {
throw new DataValidationException($instance->getValidator());
if ($instance instanceof Model) {
if (!$validate) {
$saved = $instance->skipValidation()->save();
} else {
if (!$saved = $instance->save()) {
throw new DataValidationException($instance->getValidator());
}
}
} else {
$saved = $instance->save();
}
return ($this->withFresh) ? $instance->fresh() : $saved;
@ -150,6 +148,7 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
*/
public function findCountWhere(array $fields): int
{
// @phpstan-ignore-next-line
return $this->getBuilder()->where($fields)->count($this->getColumns());
}
@ -191,12 +190,16 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
($force) ? $instance->forceFill($fields) : $instance->fill($fields);
if (!$validate) {
$saved = $instance->skipValidation()->save();
} else {
if (!$saved = $instance->save()) {
throw new DataValidationException($instance->getValidator());
if ($instance instanceof Model) {
if (!$validate) {
$saved = $instance->skipValidation()->save();
} else {
if (!$saved = $instance->save()) {
throw new DataValidationException($instance->getValidator());
}
}
} else {
$saved = $instance->save();
}
return ($this->withFresh) ? $instance->fresh() : $saved;
@ -245,6 +248,7 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
return $this->create(array_merge($where, $fields), $validate, $force);
}
// @phpstan-ignore-next-line
return $this->update($instance->id, $fields, $validate, $force);
}

View file

@ -39,13 +39,13 @@ class LocationRepository extends EloquentRepository implements LocationRepositor
/**
* Return all of the nodes and their respective count of servers for a location.
*
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithNodes(int $id): Location
{
try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('nodes.servers')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException();
@ -55,13 +55,13 @@ class LocationRepository extends EloquentRepository implements LocationRepositor
/**
* Return a location and the count of nodes in that location.
*
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithNodeCount(int $id): Location
{
try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->withCount('nodes')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException();

View file

@ -31,13 +31,13 @@ class MountRepository extends EloquentRepository
/**
* Return all of the mounts and their respective relations.
*
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithRelations(string $id): Mount
{
try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('eggs', 'nodes')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException();

View file

@ -28,15 +28,14 @@ class NestRepository extends EloquentRepository implements NestRepositoryInterfa
/**
* Return a nest or all nests with their associated eggs and variables.
*
* @return \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Nest
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithEggs(int $id = null)
public function getWithEggs(int $id = null): Nest
{
$instance = $this->getBuilder()->with('eggs', 'eggs.variables');
if (!is_null($id)) {
/** @var \Pterodactyl\Models\Nest|null $instance */
$instance = $instance->find($id, $this->getColumns());
if (!$instance) {
throw new RecordNotFoundException();
@ -45,45 +44,8 @@ class NestRepository extends EloquentRepository implements NestRepositoryInterfa
return $instance;
}
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $instance->get($this->getColumns());
}
/**
* Return a nest or all nests and the count of eggs and servers for that nest.
*
* @return \Pterodactyl\Models\Nest|\Illuminate\Database\Eloquent\Collection
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithCounts(int $id = null)
{
$instance = $this->getBuilder()->withCount(['eggs', 'servers']);
if (!is_null($id)) {
$instance = $instance->find($id, $this->getColumns());
if (!$instance) {
throw new RecordNotFoundException();
}
return $instance;
}
return $instance->get($this->getColumns());
}
/**
* Return a nest along with its associated eggs and the servers relation on those eggs.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithEggServers(int $id): Nest
{
$instance = $this->getBuilder()->with('eggs.servers')->find($id, $this->getColumns());
if (!$instance) {
throw new RecordNotFoundException();
}
/* @var Nest $instance */
return $instance;
}
}

View file

@ -59,7 +59,10 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
$this->getBuilder()->raw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk')
)->join('servers', 'servers.node_id', '=', 'nodes.id')->where('node_id', $node->id)->first();
return collect(['disk' => $stats->sum_disk, 'memory' => $stats->sum_memory])->mapWithKeys(function ($value, $key) use ($node) {
return collect([
'disk' => $stats->sum_disk,
'memory' => $stats->sum_memory,
])->mapWithKeys(function ($value, $key) use ($node) {
$maxUsage = $node->{$key};
if ($node->{$key . '_overallocate'} > 0) {
$maxUsage = $node->{$key} * (1 + ($node->{$key . '_overallocate'} / 100));
@ -85,6 +88,7 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
// This is quite ugly and can probably be improved down the road.
// And by probably, I mean it should.
// @phpstan-ignore-next-line
if (is_null($node->servers_count) || $refresh) {
$node->load('servers');
$node->setRelation('servers_count', count($node->getRelation('servers')));
@ -118,22 +122,28 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
*/
public function getNodesForServerCreation(): Collection
{
return $this->getBuilder()->with('allocations')->get()->map(function (Node $item) {
/** @phpstan-var \Illuminate\Database\Eloquent\Collection<\Pterodactyl\Models\Node> $collection */
$collection = $this->getBuilder()->with('allocations')->get();
return $collection->map(function (Node $item) {
/** @phpstan-var \Illuminate\Support\Collection<array{id: string, ip: string, port: string|int}> $filtered */
$filtered = $item->getRelation('allocations')->where('server_id', null)->map(function ($map) {
return collect($map)->only(['id', 'ip', 'port']);
});
$item->ports = $filtered->map(function ($map) {
$ports = $filtered->map(function ($map) {
return [
'id' => $map['id'],
'text' => sprintf('%s:%s', $map['ip'], $map['port']),
];
})->values();
$item->setAttribute('ports', $ports);
return [
'id' => $item->id,
'text' => $item->name,
'allocations' => $item->ports,
'allocations' => $ports,
];
})->values();
}
@ -144,11 +154,22 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
public function getNodeWithResourceUsage(int $node_id): Node
{
$instance = $this->getBuilder()
->select(['nodes.id', 'nodes.fqdn', 'nodes.public_port_http', 'nodes.scheme', 'nodes.daemon_token', 'nodes.memory', 'nodes.disk', 'nodes.memory_overallocate', 'nodes.disk_overallocate'])
->select([
'nodes.id',
'nodes.fqdn',
'nodes.public_port_http',
'nodes.scheme',
'nodes.daemon_token',
'nodes.memory',
'nodes.disk',
'nodes.memory_overallocate',
'nodes.disk_overallocate',
])
->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk')
->leftJoin('servers', 'servers.node_id', '=', 'nodes.id')
->where('nodes.id', $node_id);
/* @noinspection PhpIncompatibleReturnTypeInspection */
return $instance->first();
}
}

View file

@ -36,6 +36,8 @@ class ScheduleRepository extends EloquentRepository implements ScheduleRepositor
public function getScheduleWithTasks(int $schedule): Schedule
{
try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('tasks')->findOrFail($schedule, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException();

View file

@ -74,6 +74,8 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
public function findWithVariables(int $id): Server
{
try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('egg.variables', 'variables')
->where($this->getModel()->getKeyName(), '=', $id)
->firstOrFail($this->getColumns());

View file

@ -27,6 +27,8 @@ class TaskRepository extends EloquentRepository implements TaskRepositoryInterfa
public function getTaskForJobProcess(int $id): Task
{
try {
/* @noinspection PhpIncompatibleReturnTypeInspection */
// @phpstan-ignore-next-line
return $this->getBuilder()->with('server.user', 'schedule')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException();

View file

@ -118,7 +118,8 @@ abstract class Repository implements RepositoryInterface
/**
* Take the provided model and make it accessible to the rest of the repository.
*
* @param array $model
* @param string[] $model
* @phpstan-param class-string<\Illuminate\Database\Eloquent\Model> $model
*
* @return mixed
*/
@ -128,6 +129,7 @@ abstract class Repository implements RepositoryInterface
case 1:
return $this->model = $this->app->make($model[0]);
case 2:
// @phpstan-ignore-next-line
return $this->model = call_user_func([$this->app->make($model[0]), $model[1]]);
default:
throw new InvalidArgumentException('Model must be a FQDN or an array with a count of two.');

View file

@ -22,7 +22,7 @@ class Username implements Rule
*/
public function passes($attribute, $value): bool
{
return preg_match(self::VALIDATION_REGEX, mb_strtolower($value));
return preg_match(self::VALIDATION_REGEX, mb_strtolower($value)) === 1;
}
/**

View file

@ -64,6 +64,7 @@ class AssignmentService
$parsed = Network::parse($underlying);
} catch (Exception $exception) {
/* @noinspection PhpUndefinedVariableInspection */
// @phpstan-ignore-next-line
throw new DisplayException("Could not parse provided allocation IP address ({$underlying}): {$exception->getMessage()}", $exception);
}

View file

@ -102,6 +102,7 @@ class DeleteBackupService
/** @var \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter */
$adapter = $this->manager->adapter(Backup::ADAPTER_AWS_S3);
// @phpstan-ignore-next-line this is defined on the actual S3Client class, just not on the interface.
$adapter->getClient()->deleteObject([
'Bucket' => $adapter->getBucket(),
'Key' => sprintf('%s/%s.tar.gz', $backup->server->uuid, $backup->uuid),

View file

@ -9,6 +9,7 @@ use Pterodactyl\Models\Backup;
use Pterodactyl\Models\Server;
use Illuminate\Database\ConnectionInterface;
use Pterodactyl\Extensions\Backups\BackupManager;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Pterodactyl\Repositories\Eloquent\BackupRepository;
use Pterodactyl\Repositories\Wings\DaemonBackupRepository;
use Pterodactyl\Exceptions\Service\Backup\TooManyBackupsException;
@ -53,8 +54,6 @@ class InitiateBackupService
/**
* InitiateBackupService constructor.
*
* @param \Pterodactyl\Services\Backups\DeleteBackupService $deleteBackupService
*/
public function __construct(
BackupRepository $repository,
@ -140,7 +139,7 @@ class InitiateBackupService
// Get the oldest backup the server has that is not "locked" (indicating a backup that should
// never be automatically purged). If we find a backup we will delete it and then continue with
// this process. If no backup is found that can be used an exception is thrown.
/** @var \Pterodactyl\Models\Backup $oldest */
/** @var \Pterodactyl\Models\Backup|null $oldest */
$oldest = $successful->where('is_locked', false)->orderBy('created_at')->first();
if (!$oldest) {
throw new TooManyBackupsException($server->backup_limit);

View file

@ -152,6 +152,7 @@ class DatabaseManagementService
});
} catch (Exception $exception) {
try {
// @phpstan-ignore-next-line doesn't understand the pass-by-reference above
if ($database instanceof Database) {
$this->repository->dropDatabase($database->database);
$this->repository->dropUser($database->username, $database->remote);

View file

@ -49,8 +49,6 @@ class DatabasePasswordService
/**
* Updates a password for a given database.
*
* @param \Pterodactyl\Models\Database|int $database
*
* @throws \Throwable
*/
public function handle(Database $database): string

View file

@ -205,6 +205,7 @@ class EggConfigurationService
// Replace anything starting with "server." with the value out of the server configuration
// array that used to be created for the old daemon.
if (Str::startsWith($key, 'server.')) {
// @phpstan-ignore-next-line
$plucked = Arr::get($structure, preg_replace('/^server\./', '', $key), '');
$value = str_replace("{{{$key}}}", $plucked, $value);
@ -215,6 +216,7 @@ class EggConfigurationService
// variable from the server configuration.
$plucked = Arr::get(
$structure,
// @phpstan-ignore-next-line
preg_replace('/^env\./', 'build.env.', $key),
''
);

View file

@ -24,13 +24,11 @@ class InstallScriptService
/**
* Modify the install script for a given Egg.
*
* @param int|\Pterodactyl\Models\Egg $egg
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Egg\InvalidCopyFromException
*/
public function handle(Egg $egg, array $data)
public function handle(Egg $egg, array $data): void
{
if (!is_null(array_get($data, 'copy_script_from'))) {
if (!$this->repository->isCopyableScript(array_get($data, 'copy_script_from'), $egg->nest_id)) {

View file

@ -14,8 +14,8 @@ use Symfony\Component\Yaml\Exception\ParseException;
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
use Pterodactyl\Exceptions\Service\Egg\BadJsonFormatException;
use Pterodactyl\Exceptions\Service\InvalidFileUploadException;
use Pterodactyl\Exceptions\Service\Egg\BadYamlFormatException;
use Pterodactyl\Exceptions\Service\InvalidFileUploadException;
use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
class EggImporterService
@ -58,7 +58,7 @@ class EggImporterService
/**
* Take an uploaded JSON file and parse it into a new egg.
*
* @deprecated Use `handleFile` or `handleContent` instead.
* @deprecated use `handleFile` or `handleContent` instead
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Egg\BadJsonFormatException

View file

@ -59,6 +59,7 @@ class VariableCreationService
'user_editable' => in_array('user_editable', $options),
'rules' => $data['rules'] ?? '',
]);
return $model;
}
}

View file

@ -8,7 +8,6 @@ use Pterodactyl\Models\EggVariable;
use Illuminate\Contracts\Validation\Factory;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Traits\Services\ValidatesValidationRules;
use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
use Pterodactyl\Exceptions\Service\Egg\Variable\ReservedVariableNameException;
class VariableUpdateService
@ -51,7 +50,7 @@ class VariableUpdateService
}
$count = $egg->variables()
->where('egg_variables.env_variable',$data['env_variable'])
->where('egg_variables.env_variable', $data['env_variable'])
->where('egg_variables.id', '!=', $data['id'])
->count();

View file

@ -6,6 +6,7 @@ use Exception;
use GuzzleHttp\Client;
use Carbon\CarbonImmutable;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Contracts\Cache\Repository as CacheRepository;
use Pterodactyl\Exceptions\Service\Helper\CdnVersionFetchingException;

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Services\Nodes;
@ -48,23 +41,15 @@ class NodeDeletionService
/**
* Delete a node from the panel if no servers are attached to it.
*
* @param int|\Pterodactyl\Models\Node $node
*
* @return bool|null
*
* @throws \Pterodactyl\Exceptions\Service\HasActiveServersException
*/
public function handle($node)
public function handle(Node $node): void
{
if ($node instanceof Node) {
$node = $node->id;
}
$servers = $this->serverRepository->setColumns('id')->findCountWhere([['node_id', '=', $node]]);
$servers = $this->serverRepository->setColumns('id')->findCountWhere([['node_id', '=', $node->id]]);
if ($servers > 0) {
throw new HasActiveServersException($this->translator->trans('exceptions.node.servers_attached'));
throw new HasActiveServersException($this->translator->get('exceptions.node.servers_attached'));
}
return $this->repository->delete($node);
$this->repository->delete($node->id);
}
}

View file

@ -63,8 +63,6 @@ class NodeJWTService
/**
* Generate a new JWT for a given node.
*
* @param string|null $identifiedBy
*
* @return \Lcobucci\JWT\Token\Plain
*/
public function handle(Node $node, string $identifiedBy, string $algo = 'md5')

View file

@ -45,7 +45,7 @@ class ProcessScheduleService
*/
public function handle(Schedule $schedule, bool $now = false)
{
/** @var \Pterodactyl\Models\Task $task */
/** @var \Pterodactyl\Models\Task|null $task */
$task = $schedule->tasks()->orderBy('sequence_id')->first();
if (is_null($task)) {

View file

@ -33,8 +33,6 @@ class BuildModificationService
* BuildModificationService constructor.
*
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $structureService
* @param \Illuminate\Database\ConnectionInterface $connection
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
*/
public function __construct(
ServerConfigurationStructureService $structureService,
@ -57,7 +55,7 @@ class BuildModificationService
public function handle(Server $server, array $data)
{
/** @var \Pterodactyl\Models\Server $server */
$server = $this->connection->transaction(function() use ($server, $data) {
$server = $this->connection->transaction(function () use ($server, $data) {
$this->processAllocations($server, $data);
if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) {
@ -115,11 +113,12 @@ class BuildModificationService
$query = Allocation::query()
->where('node_id', $server->node_id)
->whereIn('id', $data['add_allocations'])
->whereNull('server_id');
->whereNull('server_id')
->first();
// Keep track of all the allocations we're just now adding so that we can use the first
// one to reset the default allocation to.
$freshlyAllocated = $query->pluck('id')->first();
$freshlyAllocated = optional($query)->id;
$query->update(['server_id' => $server->id, 'notes' => null]);
}

View file

@ -36,6 +36,7 @@ class EnvironmentService
public function handle(Server $server): array
{
$variables = $server->variables->toBase()->mapWithKeys(function (EggVariable $variable) {
// @phpstan-ignore-next-line
return [$variable->env_variable => $variable->server_value ?? $variable->default_value];
});

View file

@ -16,6 +16,7 @@ class StartupCommandService
foreach ($server->variables as $variable) {
$find[] = '{{' . $variable->env_variable . '}}';
// @phpstan-ignore-next-line
$replace[] = ($variable->user_viewable && !$hideAllValues) ? ($variable->server_value ?? $variable->default_value) : '[hidden]';
}

View file

@ -4,15 +4,9 @@ namespace Pterodactyl\Services\Servers;
use Pterodactyl\Models\Server;
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
class TransferService
{
/**
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
*/
private $repository;
/**
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
*/
@ -21,19 +15,14 @@ class TransferService
/**
* TransferService constructor.
*/
public function __construct(
DaemonServerRepository $daemonServerRepository,
ServerRepositoryInterface $repository
) {
$this->repository = $repository;
public function __construct(DaemonServerRepository $daemonServerRepository)
{
$this->daemonServerRepository = $daemonServerRepository;
}
/**
* Requests an archive from the daemon.
*
* @param int|\Pterodactyl\Models\Server $server
*
* @throws \Throwable
*/
public function requestArchive(Server $server)

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Services\Users;
@ -48,23 +41,15 @@ class UserDeletionService
/**
* Delete a user from the panel only if they have no servers attached to their account.
*
* @param int|\Pterodactyl\Models\User $user
*
* @return bool|null
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function handle($user)
public function handle(User $user): void
{
if ($user instanceof User) {
$user = $user->id;
}
$servers = $this->serverRepository->setColumns('id')->findCountWhere([['owner_id', '=', $user]]);
$servers = $this->serverRepository->setColumns('id')->findCountWhere([['owner_id', '=', $user->id]]);
if ($servers > 0) {
throw new DisplayException($this->translator->trans('admin/user.exceptions.user_has_servers'));
throw new DisplayException($this->translator->get('admin/user.exceptions.user_has_servers'));
}
return $this->repository->delete($user);
$this->repository->delete($user->id);
}
}

View file

@ -8,14 +8,14 @@ use Illuminate\Filesystem\Filesystem;
trait AvailableLanguages
{
/**
* @var \Illuminate\Filesystem\Filesystem
* @var \Illuminate\Filesystem\Filesystem|null;
*/
private $filesystem;
private $filesystem = null;
/**
* @var \Matriphe\ISO639\ISO639
* @var \Matriphe\ISO639\ISO639|null
*/
private $iso639;
private $iso639 = null;
/**
* Return all of the available languages on the Panel based on those

View file

@ -28,6 +28,7 @@ class DatabaseHostTransformer extends Transformer
'host' => $model->host,
'port' => $model->port,
'username' => $model->username,
// @phpstan-ignore-next-line no clue why it can't find this.
'node' => $model->node_id,
'created_at' => self::formatTimestamp($model->created_at),
'updated_at' => self::formatTimestamp($model->updated_at),

View file

@ -40,6 +40,8 @@ class ServerVariableTransformer extends Transformer
return $this->null();
}
// TODO: confirm this code?
// @phpstan-ignore-next-line This might actually be wrong, not sure?
return $this->item($variable->variable, new EggVariableTransformer());
}
}

View file

@ -27,7 +27,7 @@ class EggVariableTransformer extends Transformer
'description' => $variable->description,
'env_variable' => $variable->env_variable,
'default_value' => $variable->default_value,
'server_value' => $variable->server_value,
'server_value' => property_exists($variable, 'server_value') ? $variable->server_value : null,
'is_editable' => $variable->user_editable,
'rules' => $variable->rules,
];

View file

@ -5,6 +5,7 @@ namespace Pterodactyl\Transformers\Api;
use Closure;
use DateTimeInterface;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Illuminate\Http\Request;
use Pterodactyl\Models\User;
use Webmozart\Assert\Assert;
@ -64,7 +65,7 @@ abstract class Transformer extends TransformerAbstract
*
* @param mixed $data
* @param callable|\League\Fractal\TransformerAbstract $transformer
* @param null $resourceKey
* @param string|null $resourceKey
*
* @return \League\Fractal\Resource\Item
*/
@ -76,7 +77,7 @@ abstract class Transformer extends TransformerAbstract
$item = parent::item($data, $transformer, $resourceKey);
if (!$item->getResourceKey()) {
if (!$item->getResourceKey() && method_exists($transformer, 'getResourceName')) {
$item->setResourceKey($transformer->getResourceName());
}
@ -88,7 +89,7 @@ abstract class Transformer extends TransformerAbstract
*
* @param mixed $data
* @param callable|\League\Fractal\TransformerAbstract $transformer
* @param null $resourceKey
* @param string|null $resourceKey
*
* @return \League\Fractal\Resource\Collection
*/
@ -100,7 +101,7 @@ abstract class Transformer extends TransformerAbstract
$collection = parent::collection($data, $transformer, $resourceKey);
if (!$collection->getResourceKey()) {
if (!$collection->getResourceKey() && method_exists($transformer, 'getResourceName')) {
$collection->setResourceKey($transformer->getResourceName());
}
@ -151,7 +152,7 @@ abstract class Transformer extends TransformerAbstract
if ($timestamp instanceof DateTimeInterface) {
$value = CarbonImmutable::instance($timestamp);
} else {
$value = CarbonImmutable::createFromFormat(CarbonImmutable::DEFAULT_TO_STRING_FORMAT, $timestamp);
$value = CarbonImmutable::createFromFormat(CarbonInterface::DEFAULT_TO_STRING_FORMAT, $timestamp);
}
return $value->setTimezone($tz ?? self::$timezone)->toIso8601String();

View file

@ -21,8 +21,8 @@ if (!function_exists('object_get_strict')) {
* and will not trigger the response of a default value (unlike object_get).
*
* @param object $object
* @param string $key
* @param null $default
* @param string|null $key
* @param mixed|null $default
*
* @return mixed
*/

View file

@ -24,7 +24,7 @@
"guzzlehttp/guzzle": "^7.3",
"hashids/hashids": "^4.1",
"laracasts/utilities": "^3.2",
"laravel/framework": "^8.58",
"laravel/framework": "^8.68",
"laravel/helpers": "^1.4",
"laravel/sanctum": "^2.11",
"laravel/tinker": "^2.6",
@ -53,7 +53,9 @@
"laravel/dusk": "^6.18",
"mockery/mockery": "^1.4",
"nunomaduro/collision": "^5.9",
"nunomaduro/larastan": "^0.7.15",
"php-mock/php-mock-phpunit": "^2.6",
"phpstan/phpstan-webmozart-assert": "^0.12.16",
"phpunit/phpunit": "^9.5"
},
"autoload": {

1193
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class UpdateDefaultValuesForEggs extends Migration
{

257
phpstan-baseline.neon Normal file
View file

@ -0,0 +1,257 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$string of function strtoupper expects string, int\\|string given\\.$#"
count: 1
path: app/Console/Commands/Environment/AppSettingsCommand.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match_all expects string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/AppSettingsCommand.php
-
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/AppSettingsCommand.php
-
message: "#^Parameter \\#1 \\$string of function strtoupper expects string, int\\|string given\\.$#"
count: 1
path: app/Console/Commands/Environment/DatabaseSettingsCommand.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match_all expects string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/DatabaseSettingsCommand.php
-
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/DatabaseSettingsCommand.php
-
message: "#^Parameter \\#1 \\$string of function strtoupper expects string, int\\|string given\\.$#"
count: 1
path: app/Console/Commands/Environment/EmailSettingsCommand.php
-
message: "#^Parameter \\#1 \\$value of function studly_case expects string, array\\|bool\\|string given\\.$#"
count: 1
path: app/Console/Commands/Environment/EmailSettingsCommand.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match_all expects string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/EmailSettingsCommand.php
-
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false\\|null given\\.$#"
count: 1
path: app/Console/Commands/Environment/EmailSettingsCommand.php
-
message: "#^Parameter \\#1 \\$action of method Pterodactyl\\\\Repositories\\\\Wings\\\\DaemonPowerRepository\\:\\:send\\(\\) expects string, array\\|string\\|null given\\.$#"
count: 1
path: app/Console/Commands/Server/BulkPowerActionCommand.php
-
message: "#^Parameter \\#2 \\$string of function explode expects string, array\\|bool\\|string given\\.$#"
count: 2
path: app/Console/Commands/Server/BulkPowerActionCommand.php
-
message: "#^Binary operation \"\\.\" between 'download/v' and array\\|bool\\|string\\|null results in an error\\.$#"
count: 1
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Cannot access offset 'name' on array\\|false\\.$#"
count: 2
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Method Pterodactyl\\\\Console\\\\Commands\\\\UpgradeCommand\\:\\:getUrl\\(\\) should return string but returns array\\|bool\\|string\\|null\\.$#"
count: 1
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Parameter \\#1 \\$group_id of function posix_getgrgid expects int, int\\|false given\\.$#"
count: 1
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Parameter \\#1 \\$user_id of function posix_getpwuid expects int, int\\|false given\\.$#"
count: 1
path: app/Console/Commands/UpgradeCommand.php
-
message: "#^Binary operation \"\\.\" between array\\|string and '\\.' results in an error\\.$#"
count: 1
path: app/Exceptions/Handler.php
-
message: "#^Possibly invalid array key type array\\|string\\.$#"
count: 1
path: app/Exceptions/Handler.php
-
message: "#^Unable to resolve the template type TReturn in call to method Illuminate\\\\Support\\\\Collection\\<mixed,array\\<int, mixed\\>\\>\\:\\:flatMap\\(\\)$#"
count: 1
path: app/Exceptions/Handler.php
-
message: "#^Possibly invalid array key type array\\<string\\>\\|string\\.$#"
count: 1
path: app/Extensions/Backups/BackupManager.php
-
message: "#^Parameter \\#1 \\$message of static method Illuminate\\\\Log\\\\Logger\\:\\:info\\(\\) expects string, string\\|false given\\.$#"
count: 2
path: app/Http/Controllers/Api/Application/Eggs/EggController.php
-
message: "#^Parameter \\#2 \\$content of method Pterodactyl\\\\Services\\\\Eggs\\\\Sharing\\\\EggImporterService\\:\\:handleContent\\(\\) expects string, resource\\|string given\\.$#"
count: 1
path: app/Http/Controllers/Api/Application/Nests/NestController.php
-
message: "#^Parameter \\#1 \\$perPage of method Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany\\<Pterodactyl\\\\Models\\\\Backup\\>\\:\\:paginate\\(\\) expects int\\|null, array\\|int\\|string given\\.$#"
count: 1
path: app/Http/Controllers/Api/Client/Servers/BackupController.php
-
message: "#^Parameter \\#2 \\$content of method Pterodactyl\\\\Repositories\\\\Wings\\\\DaemonFileRepository\\:\\:putContent\\(\\) expects string, resource\\|string given\\.$#"
count: 1
path: app/Http/Controllers/Api/Client/Servers/FileController.php
-
message: "#^Parameter \\#1 \\$string of function md5 expects string, string\\|false given\\.$#"
count: 1
path: app/Http/Controllers/Base/LocaleController.php
-
message: "#^Parameter \\#1 \\$key of method Illuminate\\\\Routing\\\\Router\\:\\:bind\\(\\) expects string, int\\|string given\\.$#"
count: 1
path: app/Http/Middleware/Api/Application/SubstituteApplicationApiBindings.php
-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, resource\\|string given\\.$#"
count: 1
path: app/Http/Middleware/Api/IsValidJson.php
-
message: "#^Parameter \\#1 \\$array of function array_get expects array\\|ArrayAccess, array\\<string, int\\|string\\>\\|false given\\.$#"
count: 1
path: app/Http/Middleware/VerifyReCaptcha.php
-
message: "#^Parameter \\#1 \\$value of function snake_case expects string, int\\|string given\\.$#"
count: 1
path: app/Http/Requests/Api/Application/Nodes/StoreNodeRequest.php
-
message: "#^Method Pterodactyl\\\\Jobs\\\\Schedule\\\\RunTaskJob\\:\\:__construct\\(\\) has parameter \\$manualRun with no typehint specified\\.$#"
count: 1
path: app/Jobs/Schedule/RunTaskJob.php
-
message: "#^Parameter \\#2 \\$column of static method Illuminate\\\\Validation\\\\Rule\\:\\:unique\\(\\) expects string, int\\|string given\\.$#"
count: 1
path: app/Models/Model.php
-
message: "#^Method Pterodactyl\\\\Models\\\\Node\\:\\:getJsonConfiguration\\(\\) should return string but returns string\\|false\\.$#"
count: 1
path: app/Models/Node.php
-
message: "#^Method Pterodactyl\\\\Repositories\\\\Eloquent\\\\EloquentRepository\\:\\:updateOrCreate\\(\\) should return Illuminate\\\\Database\\\\Eloquent\\\\Model but returns bool\\|Illuminate\\\\Database\\\\Eloquent\\\\Model\\.$#"
count: 1
path: app/Repositories/Eloquent/EloquentRepository.php
-
message: "#^Parameter \\#1 \\.\\.\\.\\$model of method Pterodactyl\\\\Repositories\\\\Repository\\:\\:initializeModel\\(\\) expects class\\-string\\<Illuminate\\\\Database\\\\Eloquent\\\\Model\\>, mixed given\\.$#"
count: 1
path: app/Repositories/Repository.php
-
message: "#^Parameter \\#2 \\$content of method Pterodactyl\\\\Services\\\\Eggs\\\\Sharing\\\\EggImporterService\\:\\:handleContent\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Eggs/Sharing/EggImporterService.php
-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Eggs/Sharing/EggUpdateImporterService.php
-
message: "#^Parameter \\#1 \\$value of static method Illuminate\\\\Support\\\\Str\\:\\:snake\\(\\) expects string, array\\|string given\\.$#"
count: 1
path: app/Services/Eggs/Variables/VariableCreationService.php
-
message: "#^Parameter \\#1 \\$value of static method Illuminate\\\\Support\\\\Str\\:\\:snake\\(\\) expects string, array\\|string given\\.$#"
count: 1
path: app/Services/Eggs/Variables/VariableUpdateService.php
-
message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Helpers/SoftwareVersionService.php
-
message: "#^Parameter \\#2 \\$string of function explode expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Helpers/SoftwareVersionService.php
-
message: "#^Parameter \\#1 \\$id of method Lcobucci\\\\JWT\\\\Builder\\:\\:identifiedBy\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: app/Services/Nodes/NodeJWTService.php
-
message: "#^Parameter \\#1 \\$name of method Lcobucci\\\\JWT\\\\Builder\\:\\:withClaim\\(\\) expects string, int\\|string given\\.$#"
count: 1
path: app/Services/Nodes/NodeJWTService.php
-
message: "#^Parameter \\#1 \\$key of method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:setAttribute\\(\\) expects string, int\\|string given\\.$#"
count: 1
path: app/Services/Servers/ServerConfigurationStructureService.php
-
message: "#^Access to an undefined property Illuminate\\\\Database\\\\Eloquent\\\\Collection\\<Pterodactyl\\\\Models\\\\Allocation\\>\\|Pterodactyl\\\\Models\\\\Allocation\\:\\:\\$node_id\\.$#"
count: 1
path: app/Services/Servers/ServerCreationService.php
-
message: "#^Access to an undefined property Illuminate\\\\Database\\\\Eloquent\\\\Collection\\<Pterodactyl\\\\Models\\\\Egg\\>\\|Pterodactyl\\\\Models\\\\Egg\\:\\:\\$nest_id\\.$#"
count: 1
path: app/Services/Servers/ServerCreationService.php
-
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false given\\.$#"
count: 1
path: app/Services/Subusers/SubuserCreationService.php
-
message: "#^Parameter \\#1 \\$string of function urlencode expects string, array\\|string\\|null given\\.$#"
count: 1
path: app/Services/Users/TwoFactorSetupService.php
-
message: "#^Cannot call method getResourceName\\(\\) on \\(callable&class\\-string\\)\\|\\(callable&object\\)\\|League\\\\Fractal\\\\TransformerAbstract\\.$#"
count: 2
path: app/Transformers/Api/Transformer.php
-
message: "#^Cannot call method setTimezone\\(\\) on Carbon\\\\CarbonImmutable\\|false\\.$#"
count: 1
path: app/Transformers/Api/Transformer.php
-
message: "#^Parameter \\#1 \\$object_or_class of function method_exists expects object\\|string, \\(callable\\)\\|League\\\\Fractal\\\\TransformerAbstract given\\.$#"
count: 2
path: app/Transformers/Api/Transformer.php

15
phpstan.neon Normal file
View file

@ -0,0 +1,15 @@
includes:
- ./phpstan-baseline.neon
- ./vendor/nunomaduro/larastan/extension.neon
- ./vendor/phpstan/phpstan-webmozart-assert/extension.neon
parameters:
paths:
- app
- database/Seeders
level: 7
ignoreErrors:
- '#Unsafe usage of new static#'
- '#has no return typehint specified.#'
- '#has no typehint specified.#'
checkMissingIterableValueType: false

Some files were not shown because too many files have changed in this diff Show more