Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update PHPStan to 2.x #1492

Merged
merged 3 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4",
"phpstan/phpstan": "^1.9.2",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-doctrine": "^1",
"phpstan/phpstan-symfony": "^1.1",
"phpstan/phpstan-webmozart-assert": "^1.2",
"phpstan/phpstan": "^2",
"phpstan/phpstan-deprecation-rules": "^2",
"phpstan/phpstan-doctrine": "^2",
"phpstan/phpstan-symfony": "^2",
"phpstan/phpstan-webmozart-assert": "^2",
"phpunit/phpunit": "^11.0",
"staabm/phpstan-dba": "^0.2",
"staabm/phpstan-todo-by": "^0.1.27",
"staabm/phpstan-dba": "^0.3",
"staabm/phpstan-todo-by": "^0.2",
"symfony/browser-kit": "^7",
"symfony/css-selector": "^7",
"symfony/debug-bundle": "^7",
Expand Down
468 changes: 233 additions & 235 deletions composer.lock

Large diffs are not rendered by default.

60 changes: 42 additions & 18 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -1,61 +1,85 @@
parameters:
ignoreErrors:
-
message: "#^Dead catch \\- Symfony\\\\Component\\\\Lock\\\\Exception\\\\LockReleasingException is never thrown in the try block\\.$#"
message: '#^Dead catch \- Symfony\\Component\\Lock\\Exception\\LockReleasingException is never thrown in the try block\.$#'
identifier: catch.neverThrown
count: 1
path: src/Command/RunWorkersCommand.php

-
message: "#^Parameter \\#1 \\$job of method App\\\\Service\\\\UpdaterWorker\\:\\:process\\(\\) expects App\\\\Entity\\\\Job\\<array\\{id\\: int, update_equal_refs\\: bool, delete_before\\: bool, force_dump\\: bool\\}\\>, App\\\\Entity\\\\Job\\<array\\{id\\: int, update_equal_refs\\: false, delete_before\\: false, force_dump\\: false\\}\\> given\\.$#"
count: 1
path: src/DataFixtures/PackageFixtures.php

-
message: "#^Query error\\: Column \"audit_log\\.attributes\" expects value type string, got type array\\<string, mixed\\>$#"
message: '#^Query error\: Column "audit_log\.attributes" expects value type string, got type array\<string, mixed\>$#'
identifier: dba.keyValue
count: 1
path: src/Entity/AuditRecordRepository.php

-
message: "#^Query error\\: Column \"audit_log\\.datetime\" expects value type string, got type DateTimeImmutable$#"
message: '#^Query error\: Column "audit_log\.datetime" expects value type string, got type DateTimeImmutable$#'
identifier: dba.keyValue
count: 1
path: src/Entity/AuditRecordRepository.php

-
message: "#^Query error\\: Column \"audit_log\\.id\" expects value type string, got type Symfony\\\\Component\\\\Uid\\\\Ulid$#"
message: '#^Query error\: Column "audit_log\.id" expects value type string, got type Symfony\\Component\\Uid\\Ulid$#'
identifier: dba.keyValue
count: 1
path: src/Entity/AuditRecordRepository.php

-
message: "#^Method App\\\\Entity\\\\PackageRepository\\:\\:getDependents\\(\\) should return array\\<array\\{id\\: int, name\\: string, description\\: string\\|null, language\\: string\\|null, abandoned\\: int, replacementPackage\\: string\\|null\\}\\> but returns array\\<int\\<0, max\\>, non\\-empty\\-array\\<string, mixed\\>\\>\\.$#"
message: '#^Method App\\Entity\\PackageRepository\:\:getSuggestCount\(\) should return int\<0, max\> but returns int\.$#'
identifier: return.type
count: 1
path: src/Entity/PackageRepository.php

-
message: "#^Method App\\\\Entity\\\\PackageRepository\\:\\:getSuggestCount\\(\\) should return int\\<0, max\\> but returns int\\.$#"
message: '#^Query error\: Unknown column ''d\.total'' in ''order clause'' \(1054\)\.$#'
identifier: dba.syntaxError
count: 1
path: src/Entity/PackageRepository.php

-
message: "#^Query error\\: Unknown column 'd\\.total' in 'order clause' \\(1054\\)\\.$#"
message: '#^Method App\\Entity\\PhpStatRepository\:\:getStatVersions\(\) should return list\<array\{version\: string, depth\: 0\|1\|2\|3\}\> but returns array\<mixed\>\.$#'
identifier: return.type
count: 1
path: src/Entity/PackageRepository.php
path: src/Entity/PhpStatRepository.php

-
message: "#^Offset 'name' on array\\{name\\: string, description\\?\\: string\\} on left side of \\?\\? always exists and is not nullable\\.$#"
message: '#^Offset ''name'' on array\{name\: string, description\?\: string\} on left side of \?\? always exists and is not nullable\.$#'
identifier: nullCoalesce.offset
count: 2
path: src/Entity/Version.php

-
message: "#^Method App\\\\Model\\\\FavoriteManager\\:\\:getFavoriteCount\\(\\) should return int\\<0, max\\> but returns int\\.$#"
message: '#^Method App\\Model\\FavoriteManager\:\:getFavoriteCount\(\) should return int\<0, max\> but returns int\.$#'
identifier: return.type
count: 1
path: src/Model/FavoriteManager.php

-
message: "#^Parameter \\#1 \\$job of method App\\\\Service\\\\GitHubUserMigrationWorker\\:\\:process\\(\\) expects App\\\\Entity\\\\Job\\<array\\{id\\: int, update_equal_refs\\: bool, delete_before\\: bool, force_dump\\: bool\\}\\>\\|App\\\\Entity\\\\Job\\<array\\{id\\: int, old_scope\\: string, new_scope\\: string\\}\\>\\|App\\\\Entity\\\\Job\\<array\\{source\\: string\\}\\>, App\\\\Entity\\\\Job\\<array\\<string, bool\\|int\\|string\\>\\> given\\.$#"
message: '#^Parameter \#1 \$ids of method App\\Entity\\PackageRepository\:\:getPackagesWithVersions\(\) expects list\<int\>\|null, array\<int\<0, max\>, int\> given\.$#'
identifier: argument.type
count: 1
path: src/Service/QueueWorker.php
path: src/Package/SymlinkDumper.php

-
message: '#^Method App\\Package\\Updater\:\:sanitize\(\) should return T of string\|null but returns null\.$#'
identifier: return.type
count: 1
path: src/Package/Updater.php

-
message: '#^Method App\\Package\\Updater\:\:sanitize\(\) should return T of string\|null but returns string\.$#'
identifier: return.type
count: 1
path: src/Package/Updater.php

-
message: '#^Parameter \#1 \$ids of method App\\Entity\\PackageRepository\:\:getPackagesWithVersions\(\) expects list\<int\>\|null, array\<int\<0, max\>, int\> given\.$#'
identifier: argument.type
count: 1
path: src/Package/V2Dumper.php

-
message: "#^Parameter \\#1 \\$result of method App\\\\Entity\\\\Job\\<array\\<string, bool\\|int\\|string\\>\\>\\:\\:complete\\(\\) expects array\\{status\\: 'completed'\\|'errored'\\|'failed'\\|'package_deleted'\\|'package_gone'\\|'queued'\\|'reschedule'\\|'started'\\|'timeout', message\\?\\: string, after\\?\\: DateTimeInterface&Throwable, details\\?\\: string, exception\\?\\: Throwable, exceptionMsg\\?\\: string, exceptionClass\\?\\: class\\-string\\<Throwable\\>, results\\?\\: array, \\.\\.\\.\\}, array\\{status\\: 'completed'\\|'errored'\\|'failed'\\|'package_deleted'\\|'package_gone', message\\: string, after\\?\\: DateTimeInterface, details\\?\\: string, exception\\?\\: Throwable, exceptionMsg\\?\\: string, exceptionClass\\?\\: class\\-string\\<Throwable\\>, results\\?\\: array, \\.\\.\\.\\} given\\.$#"
message: '#^Parameter \#1 \$job of method App\\Service\\GitHubUserMigrationWorker\:\:process\(\) expects App\\Entity\\Job\<array\{id\: int, update_equal_refs\: bool, delete_before\: bool, force_dump\: bool\}\>\|App\\Entity\\Job\<array\{id\: int, old_scope\: string, new_scope\: string\}\>\|App\\Entity\\Job\<array\{source\: string\}\>, App\\Entity\\Job\<array\<string, bool\|int\|string\>\> given\.$#'
identifier: argument.type
count: 1
path: src/Service/QueueWorker.php
1 change: 1 addition & 0 deletions phpstan-bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
$config->stringifyTypes(false);
// $config->analyzeQueryPlans(true);
// $config->debugMode(true);
// $config->utilizeSqlAst(true); // requires sqlftw/sqlftw

(new Dotenv())->bootEnv(__DIR__ . '/.env');
$dsn = parse_url($_SERVER['DATABASE_URL']);
Expand Down
15 changes: 13 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,16 @@ parameters:
PackageUpdateJob: 'array{id: int, update_equal_refs: bool, delete_before: bool, force_dump: bool}'
GitHubUserMigrateJob: 'array{id: int, old_scope: string, new_scope: string}'
SecurityAdvisoryJob: 'array{source: string}'
# TODO maybe split those results per class as well instead of this cobbled up mess
JobResult: 'array{status: \App\Entity\Job::STATUS_*, message?: string, after?: \DateTimeInterface, details?: string, exception?: \Throwable, exceptionMsg?: string, exceptionClass?: class-string<\Throwable>, results?: array<mixed>, vendor?: string}'

JobResult: 'array{status: \App\Entity\Job::STATUS_*, message: string, vendor?: string, details?: string, exceptionMsg?: string, exceptionClass?: class-string<\Throwable>, results?: array{hooks_setup: int, hooks_failed: array<int, array{package: string, reason: mixed}>, hooks_ok_unchanged: int}}'
ErroredResult: 'array{status: \App\Entity\Job::STATUS_ERRORED, message: string, exception: \Throwable}'
GenericCompletedResult: 'array{status: \App\Entity\Job::STATUS_COMPLETED, message: string}'
RescheduleResult: 'array{status: \App\Entity\Job::STATUS_RESCHEDULE, after: \DateTimeInterface, message: string, vendor?: string}'
PackageCompletedResult: 'array{status: \App\Entity\Job::STATUS_COMPLETED, message: string, details: string, vendor: string}'
PackageFailedResult: 'array{status: \App\Entity\Job::STATUS_FAILED, message: string, vendor: string, exception: \Throwable, details?: string}'
PackageGoneResult: 'array{status: \App\Entity\Job::STATUS_PACKAGE_GONE, message: string, vendor: string, exception: \Throwable, details?: string}'
PackageDeletedResult: 'array{status: \App\Entity\Job::STATUS_PACKAGE_DELETED, message: string, vendor: string, exception: \Throwable, details: string}'
AdvisoriesCompletedResult: 'array{status: \App\Entity\Job::STATUS_COMPLETED, message: string, details: string}'
AdvisoriesErroredResult: 'array{status: \App\Entity\Job::STATUS_ERRORED, message: string}'
GitHubMigrationResult: 'array{status: \App\Entity\Job::STATUS_COMPLETED, message: string, results: array{hooks_setup: int, hooks_failed: array<int, array{package: string, reason: mixed}>, hooks_ok_unchanged: int}}'
GitHubMigrationFailedResult: 'array{status: \App\Entity\Job::STATUS_FAILED, message: string}'
1 change: 0 additions & 1 deletion src/Controller/ExploreController.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ public function popularAction(Request $req, RedisClient $redis, FavoriteManager
'total' => $packages->getNbResults(),
];

/** @var Package $package */
foreach ($packages as $package) {
$url = $this->generateUrl('view_package', ['name' => $package->getName()], UrlGeneratorInterface::ABSOLUTE_URL);

Expand Down
9 changes: 9 additions & 0 deletions src/Controller/PackageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1571,13 +1571,19 @@ public function securityAdvisoryAction(Request $request, string $id): Response
return $this->render('package/security_advisory.html.twig', ['securityAdvisories' => $securityAdvisories, 'id' => $id]);
}

/**
* @return FormInterface<MaintainerRequest>
*/
private function createAddMaintainerForm(Package $package): FormInterface
{
$maintainerRequest = new MaintainerRequest();

return $this->createForm(AddMaintainerRequestType::class, $maintainerRequest);
}

/**
* @return FormInterface<MaintainerRequest>
*/
private function createRemoveMaintainerForm(Package $package): FormInterface
{
$maintainerRequest = new MaintainerRequest();
Expand All @@ -1587,6 +1593,9 @@ private function createRemoveMaintainerForm(Package $package): FormInterface
]);
}

/**
* @return FormInterface<array{}>
*/
private function createDeletePackageForm(Package $package): FormInterface
{
return $this->createFormBuilder([])->getForm();
Expand Down
6 changes: 3 additions & 3 deletions src/Controller/WebController.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function searchApi(Request $req, Algolia $algolia): JsonResponse
try {
$query = new Query(
$req->query->has('q') ? $req->query->getString('q') : $req->query->getString('query'),
(array) ($req->query->all()['tags'] ?? []),
array_values((array) ($req->query->all()['tags'] ?? [])),
$req->query->getString('type', ''),
$req->query->getInt('per_page', 15),
$req->query->getInt('page', 1)
Expand Down Expand Up @@ -177,9 +177,9 @@ public function statsAction(RedisClient $redis): Response
'versions' => !empty($chart['versions']) ? max($chart['versions']) : 0,
'downloads' => $downloads,
'downloadsChart' => $dlChart,
'maxDailyDownloads' => !empty($dlChart) ? max($dlChart['values']) : null,
'maxDailyDownloads' => !empty($dlChart) && \count($dlChart['values']) > 0 ? max($dlChart['values']) : null,
'downloadsChartMonthly' => $dlChartMonthly,
'maxMonthlyDownloads' => !empty($dlChartMonthly) ? max($dlChartMonthly['values']) : null,
'maxMonthlyDownloads' => !empty($dlChartMonthly) && \count($dlChartMonthly['values']) > 0 ? max($dlChartMonthly['values']) : null,
'downloadsStartDate' => $downloadsStartDate,
]);
}
Expand Down
33 changes: 0 additions & 33 deletions src/Entity/DependentRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
use Doctrine\Persistence\ManagerRegistry;

/**
* @method Dependent|null find($id, $lockMode = null, $lockVersion = null)
* @method Dependent|null findOneBy(array $criteria, array $orderBy = null)
* @method Dependent[] findAll()
* @method Dependent[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
* @extends ServiceEntityRepository<Dependent>
*/
class DependentRepository extends ServiceEntityRepository
Expand Down Expand Up @@ -63,33 +59,4 @@ public function deletePackageDependentSuggesters(int $packageId): void
$conn->executeStatement('DELETE FROM dependent WHERE package_id = :id', ['id' => $packageId]);
$conn->executeStatement('DELETE FROM suggester WHERE package_id = :id', ['id' => $packageId]);
}

// /**
// * @return Dependent[] Returns an array of Dependent objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('d')
->andWhere('d.exampleField = :val')
->setParameter('val', $value)
->orderBy('d.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/

/*
public function findOneBySomeField($value): ?Dependent
{
return $this->createQueryBuilder('d')
->andWhere('d.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
6 changes: 3 additions & 3 deletions src/Entity/Job.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class Job
#[ORM\Column(type: 'string')]
private string $status = self::STATUS_QUEUED;

/** @var (JobResult&array<string, int|string|bool|null|array<mixed>|\Throwable>)|null */
/** @var JobResult|null */
#[ORM\Column(type: 'json', nullable: true)]
private ?array $result = null;

Expand Down Expand Up @@ -97,7 +97,7 @@ public function start(): void
}

/**
* @param JobResult&array<string, int|string|bool|null|array<mixed>|\Throwable> $result
* @param JobResult $result
*/
public function complete(array $result): void
{
Expand Down Expand Up @@ -158,7 +158,7 @@ public function getStatus(): string
}

/**
* @return JobResult&array<string, int|string|bool|null|array<mixed>|\Throwable>
* @return JobResult
*/
public function getResult(): ?array
{
Expand Down
4 changes: 3 additions & 1 deletion src/Entity/PackageRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ public function getPackagesWithFields(array $filters, array $fields): array
}

/**
* @param Query<mixed, array{name: string}> $query
* @return list<string>
*/
private function getPackageNamesForQuery(Query $query): array
Expand Down Expand Up @@ -500,7 +501,7 @@ public function getDependentCount(string $name, ?int $type = null): int
* @param string $name Package name to find the dependents of
* @param int|null $type One of Dependent::TYPE_*
* @param 'downloads'|'name' $orderBy
* @return array<array{id: int, name: string, description: string|null, language: string|null, abandoned: int, replacementPackage: string|null}>
* @return list<array{id: int, name: string, description: string|null, language: string|null, abandoned: int, replacementPackage: string|null}>
*/
public function getDependents(string $name, int $offset = 0, int $limit = 15, string $orderBy = 'name', ?int $type = null): array
{
Expand All @@ -526,6 +527,7 @@ public function getDependents(string $name, int $offset = 0, int $limit = 15, st
) x ON x.package_id = p.id '.$join.' ORDER BY '.$orderByField.' LIMIT '.((int) $limit).' OFFSET '.((int) $offset);

$res = [];
/** @var array{id: int, name: string, description: string|null, language: string|null, abandoned: bool, replacementPackage: string|null} $row */
foreach ($this->getEntityManager()->getConnection()->fetchAllAssociative($sql, $args) as $row) {
$res[] = ['id' => (int) $row['id'], 'abandoned' => (int) $row['abandoned']] + $row;
}
Expand Down
33 changes: 0 additions & 33 deletions src/Entity/SuggesterRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
use Doctrine\Persistence\ManagerRegistry;

/**
* @method Suggester|null find($id, $lockMode = null, $lockVersion = null)
* @method Suggester|null findOneBy(array $criteria, array $orderBy = null)
* @method Suggester[] findAll()
* @method Suggester[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
* @extends ServiceEntityRepository<Suggester>
*/
class SuggesterRepository extends ServiceEntityRepository
Expand All @@ -28,33 +24,4 @@ public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Suggester::class);
}

// /**
// * @return Suggester[] Returns an array of Suggester objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('d')
->andWhere('d.exampleField = :val')
->setParameter('val', $value)
->orderBy('d.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/

/*
public function findOneBySomeField($value): ?Suggester
{
return $this->createQueryBuilder('d')
->andWhere('d.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
2 changes: 1 addition & 1 deletion src/Entity/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class User implements UserInterface, TwoFactorInterface, BackupCodeInterface, Eq
private bool $enabled = false;

/**
* @var list<string>
* @var array<string>
*/
#[ORM\Column(type: 'json')]
private array $roles = [];
Expand Down
4 changes: 2 additions & 2 deletions src/Entity/Version.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
* autoload?: array<mixed>,
* extra?: array<mixed>,
* target-dir?: string,
* include-path?: list<string>,
* bin?: list<string>,
* include-path?: array<string>,
* bin?: array<string>,
* default-branch?: true,
* require?: array<string, string>,
* require-dev?: array<string, string>,
Expand Down
3 changes: 3 additions & 0 deletions src/Form/ChangePasswordFormType.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
use Symfony\Component\Validator\Constraints\NotBlank;

/**
* @extends AbstractType<User>
*/
class ChangePasswordFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
Expand Down
3 changes: 3 additions & 0 deletions src/Form/RegistrationFormType.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\IsTrue;

/**
* @extends AbstractType<User>
*/
class RegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
Expand Down
Loading