diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 9e331fbada..b5351db396 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -16,71 +16,25 @@ ->in(__DIR__.'/tests') ->name('*.php') ->notPath('Fixtures') + ->notPath('Search/results') ; $config = new PhpCsFixer\Config(); -return $config->setRules([ - '@PSR2' => true, - 'binary_operator_spaces' => true, - 'blank_line_before_statement' => ['statements' => ['declare', 'return']], - 'cast_spaces' => ['space' => 'single'], - 'header_comment' => ['header' => $header], - 'include' => true, - - 'class_attributes_separation' => ['elements' => ['method' => 'one', 'trait_import' => 'none']], - 'no_blank_lines_after_class_opening' => true, - 'no_blank_lines_after_phpdoc' => true, - 'no_empty_statement' => true, - 'no_extra_blank_lines' => true, - 'no_leading_namespace_whitespace' => true, - 'no_trailing_comma_in_singleline' => true, - 'no_whitespace_in_blank_line' => true, - 'object_operator_without_whitespace' => true, - //'phpdoc_align' => true, - 'phpdoc_indent' => true, - 'no_empty_comment' => true, - 'no_empty_phpdoc' => true, - 'phpdoc_no_access' => true, - 'phpdoc_no_package' => true, - //'phpdoc_order' => true, - 'phpdoc_scalar' => true, - 'phpdoc_trim' => true, - 'phpdoc_types' => true, - 'psr_autoloading' => true, - 'blank_lines_before_namespace' => true, - 'standardize_not_equals' => true, - 'ternary_operator_spaces' => true, - 'trailing_comma_in_multiline' => ['elements' => ['arrays']], - 'unary_operator_spaces' => true, - - // imports - 'no_unused_imports' => true, - 'fully_qualified_strict_types' => true, - 'single_line_after_imports' => true, - //'global_namespace_import' => ['import_classes' => true], - 'no_leading_import_slash' => true, - 'single_import_per_statement' => true, - - // PHP 7.2 migration - 'array_syntax' => true, - 'list_syntax' => true, - 'regular_callable_call' => true, - 'static_lambda' => true, - 'nullable_type_declaration_for_default_null_value' => true, - 'explicit_indirect_variable' => true, - 'visibility_required' => ['elements' => ['property', 'method', 'const']], - 'non_printable_character' => true, - 'combine_nested_dirname' => true, - 'random_api_migration' => true, - 'ternary_to_null_coalescing' => true, - 'phpdoc_to_param_type' => true, - 'declare_strict_types' => true, - 'no_superfluous_phpdoc_tags' => [ - 'allow_mixed' => true, - ], - - // TODO php 7.4 migration (one day..) - 'phpdoc_to_property_type' => true, +return $config + ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) + ->setRules([ + '@PHP84Migration' => true, + '@PHPUnit100Migration:risky' => true, + '@PER-CS' => true, + '@Symfony' => true, + '@Symfony:risky' => true, + + // overrides + 'blank_line_after_opening_tag' => false, + 'linebreak_after_opening_tag' => false, + 'yoda_style' => false, + 'phpdoc_summary' => false, + 'increment_style' => false, ]) ->setUsingCache(true) ->setRiskyAllowed(true) diff --git a/src/ArgumentResolver/UserResolver.php b/src/ArgumentResolver/UserResolver.php index c50233c511..696a307c38 100644 --- a/src/ArgumentResolver/UserResolver.php +++ b/src/ArgumentResolver/UserResolver.php @@ -49,7 +49,7 @@ public function resolve(Request $request, ArgumentMetadata $argument): iterable } $username = $request->attributes->get($varName); - if (!is_string($username)) { + if (!\is_string($username)) { throw new \UnexpectedValueException('Missing "'.$varName.'" in request attributes, cannot resolve $'.$argument->getName()); } diff --git a/src/Audit/AuditRecordType.php b/src/Audit/AuditRecordType.php index de017047b0..3d760dd3ce 100644 --- a/src/Audit/AuditRecordType.php +++ b/src/Audit/AuditRecordType.php @@ -14,30 +14,30 @@ enum AuditRecordType: string { - # package ownership - case AddMaintainer = 'add_maintainer'; # TODO - case RemoveMaintainer = 'remove_maintainer'; # TODO - case TransferPackage = 'transfer_package'; # TODO + // package ownership + case AddMaintainer = 'add_maintainer'; // TODO + case RemoveMaintainer = 'remove_maintainer'; // TODO + case TransferPackage = 'transfer_package'; // TODO - # package management + // package management case PackageCreated = 'package_created'; case PackageDeleted = 'package_deleted'; case CanonicalUrlChange = 'canonical_url_change'; case VersionDeleted = 'version_deleted'; case VersionReferenceChange = 'version_reference_change'; - case PackageAbandoned = 'package_abandoned'; # TODO - case PackageUnabandoned = 'package_unabandoned'; # TODO + case PackageAbandoned = 'package_abandoned'; // TODO + case PackageUnabandoned = 'package_unabandoned'; // TODO - # user management - case UserCreated = 'user_created'; # TODO - case UserDeleted = 'user_deleted'; # TODO - case PasswordResetRequest = 'password_reset_request'; # TODO - case PasswordReset = 'password_reset'; # TODO - case PasswordChange = 'password_change'; # TODO - case EmailChange = 'email_change'; # TODO - case UsernameChange = 'username_change'; # TODO - case GitHubLinkedWithUser = 'github_linked_with_user'; # TODO - case GitHubDisconnectedFromUser = 'github_disconnected_from_user'; # TODO - case TwoFaActivated = 'two_fa_activated'; # TODO - case TwoFaDeactivated = 'two_fa_deactivated'; # TODO + // user management + case UserCreated = 'user_created'; // TODO + case UserDeleted = 'user_deleted'; // TODO + case PasswordResetRequest = 'password_reset_request'; // TODO + case PasswordReset = 'password_reset'; // TODO + case PasswordChange = 'password_change'; // TODO + case EmailChange = 'email_change'; // TODO + case UsernameChange = 'username_change'; // TODO + case GitHubLinkedWithUser = 'github_linked_with_user'; // TODO + case GitHubDisconnectedFromUser = 'github_disconnected_from_user'; // TODO + case TwoFaActivated = 'two_fa_activated'; // TODO + case TwoFaDeactivated = 'two_fa_deactivated'; // TODO } diff --git a/src/Command/CleanIndexCommand.php b/src/Command/CleanIndexCommand.php index 497e681ea2..bb164a9d99 100644 --- a/src/Command/CleanIndexCommand.php +++ b/src/Command/CleanIndexCommand.php @@ -13,11 +13,11 @@ namespace App\Command; use Algolia\AlgoliaSearch\SearchClient; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; use App\Service\Locker; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; class CleanIndexCommand extends Command { @@ -74,11 +74,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $page = 0; $perPage = 100; do { - $results = $index->search('', ['facets' => "*,type,tags", 'facetFilters' => ['type:virtual-package'], 'numericFilters' => ['trendiness=100'], 'hitsPerPage' => $perPage, 'page' => $page]); + $results = $index->search('', ['facets' => '*,type,tags', 'facetFilters' => ['type:virtual-package'], 'numericFilters' => ['trendiness=100'], 'hitsPerPage' => $perPage, 'page' => $page]); foreach ($results['hits'] as $result) { - if (0 !== strpos($result['objectID'], 'virtual:')) { - $duplicate = $index->search('', ['facets' => "*,objectID,type,tags", 'facetFilters' => ['objectID:virtual:'.$result['objectID']]]); - if (count($duplicate['hits']) === 1) { + if (!str_starts_with($result['objectID'], 'virtual:')) { + $duplicate = $index->search('', ['facets' => '*,objectID,type,tags', 'facetFilters' => ['objectID:virtual:'.$result['objectID']]]); + if (\count($duplicate['hits']) === 1) { if ($verbose) { $output->writeln('Deleting '.$result['objectID'].' which is a duplicate of '.$duplicate['hits'][0]['objectID']); } @@ -95,7 +95,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } $page++; - } while (count($results['hits']) >= $perPage); + } while (\count($results['hits']) >= $perPage); $this->locker->unlockCommand(__CLASS__); diff --git a/src/Command/CleanSpamPackagesCommand.php b/src/Command/CleanSpamPackagesCommand.php index 2ca445813a..eca211d41c 100644 --- a/src/Command/CleanSpamPackagesCommand.php +++ b/src/Command/CleanSpamPackagesCommand.php @@ -12,13 +12,13 @@ namespace App\Command; +use App\Entity\Package; use App\Entity\PackageFreezeReason; use App\Entity\Version; use App\Entity\VersionRepository; use App\Model\PackageManager; use App\Model\ProviderManager; use Doctrine\Persistence\ManagerRegistry; -use App\Entity\Package; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/src/Command/ClearVersionsCommand.php b/src/Command/ClearVersionsCommand.php index 97ac5c0209..63c6b1afb0 100644 --- a/src/Command/ClearVersionsCommand.php +++ b/src/Command/ClearVersionsCommand.php @@ -12,13 +12,13 @@ namespace App\Command; -use Doctrine\Persistence\ManagerRegistry; use App\Entity\Package; use App\Entity\Version; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Output\OutputInterface; /** diff --git a/src/Command/CompileStatsCommand.php b/src/Command/CompileStatsCommand.php index 83147ecc1d..c7148012c5 100644 --- a/src/Command/CompileStatsCommand.php +++ b/src/Command/CompileStatsCommand.php @@ -12,14 +12,14 @@ namespace App\Command; -use Doctrine\DBAL\Connection; -use Doctrine\Persistence\ManagerRegistry; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; use App\Entity\Download; use App\Service\Locker; +use Doctrine\DBAL\Connection; +use Doctrine\Persistence\ManagerRegistry; use Predis\Client; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; /** * @author Jordi Boggiano diff --git a/src/Command/DumpPackagesCommand.php b/src/Command/DumpPackagesCommand.php index 30332164c5..bd81cb09f3 100644 --- a/src/Command/DumpPackagesCommand.php +++ b/src/Command/DumpPackagesCommand.php @@ -12,10 +12,10 @@ namespace App\Command; -use Doctrine\Persistence\ManagerRegistry; use App\Entity\Package; use App\Package\SymlinkDumper; use App\Service\Locker; +use Doctrine\Persistence\ManagerRegistry; use Psr\Log\LoggerInterface; use Seld\Signal\SignalHandler; use Symfony\Component\Console\Command\Command; diff --git a/src/Command/DumpPackagesV2Command.php b/src/Command/DumpPackagesV2Command.php index f3a9e4e93d..4bb4573328 100644 --- a/src/Command/DumpPackagesV2Command.php +++ b/src/Command/DumpPackagesV2Command.php @@ -12,10 +12,10 @@ namespace App\Command; -use Doctrine\Persistence\ManagerRegistry; use App\Entity\Package; use App\Package\V2Dumper; use App\Service\Locker; +use Doctrine\Persistence\ManagerRegistry; use Psr\Log\LoggerInterface; use Seld\Signal\SignalHandler; use Symfony\Component\Console\Command\Command; diff --git a/src/Command/GenerateTokensCommand.php b/src/Command/GenerateTokensCommand.php index 4a7453a305..60e051eb80 100644 --- a/src/Command/GenerateTokensCommand.php +++ b/src/Command/GenerateTokensCommand.php @@ -12,9 +12,9 @@ namespace App\Command; +use App\Entity\User; use App\Util\DoctrineTrait; use Doctrine\Persistence\ManagerRegistry; -use App\Entity\User; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/src/Command/IndexPackagesCommand.php b/src/Command/IndexPackagesCommand.php index b6701920d0..74df89ab08 100644 --- a/src/Command/IndexPackagesCommand.php +++ b/src/Command/IndexPackagesCommand.php @@ -17,16 +17,16 @@ use App\Entity\PackageFreezeReason; use App\Model\DownloadManager; use App\Model\FavoriteManager; +use App\Service\Locker; use Composer\Pcre\Preg; use Doctrine\DBAL\ArrayParameterType; +use Doctrine\Persistence\ManagerRegistry; +use Predis\Client; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Doctrine\Persistence\ManagerRegistry; -use App\Service\Locker; -use Predis\Client; -use Symfony\Component\Console\Command\Command; class IndexPackagesCommand extends Command { @@ -119,12 +119,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $index->clear(); } - $total = count($ids); + $total = \count($ids); $current = 0; // update package index while ($ids) { - $indexTime = new \DateTime; + $indexTime = new \DateTime(); $idsSlice = array_splice($ids, 0, 50); $packages = $this->getEM()->getRepository(Package::class)->findBy(['id' => $idsSlice]); @@ -134,7 +134,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($packages as $package) { $current++; if ($verbose) { - $output->writeln('['.sprintf('%'.strlen((string) $total).'d', $current).'/'.$total.'] Indexing '.$package->getName()); + $output->writeln('['.\sprintf('%'.\strlen((string) $total).'d', $current).'/'.$total.'] Indexing '.$package->getName()); } // delete spam packages from the search index @@ -168,7 +168,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int try { $index->saveObjects($records); } catch (\Exception $e) { - $output->writeln(''.get_class($e).': '.$e->getMessage().', occurred while processing packages: '.implode(',', $idsSlice).''); + $output->writeln(''.$e::class.': '.$e->getMessage().', occurred while processing packages: '.implode(',', $idsSlice).''); continue; } @@ -192,7 +192,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * @param string[] $tags - * @return array> + * + * @return array|null> */ private function packageToSearchableArray(Package $package, array $tags): array { @@ -213,9 +214,9 @@ private function packageToSearchableArray(Package $package, array $tags): array 'type' => $package->getType(), 'repository' => $package->getRepository(), 'language' => $package->getLanguage(), - # log10 of downloads over the last 7days + // log10 of downloads over the last 7days 'trendiness' => $trendiness > 0 ? log($trendiness, 10) : 0, - # log10 of downloads + gh stars + // log10 of downloads + gh stars 'popularity' => $popularity, 'meta' => [ 'downloads' => $downloads['total'], @@ -233,7 +234,7 @@ private function packageToSearchableArray(Package $package, array $tags): array $record['replacementPackage'] = ''; } - if (in_array($package->getType(), ['php-ext', 'php-ext-zend'], true)) { + if (\in_array($package->getType(), ['php-ext', 'php-ext-zend'], true)) { $record['extension'] = 1; } diff --git a/src/Command/MigrateDataTypesCommand.php b/src/Command/MigrateDataTypesCommand.php index b9484522c3..7049aa5258 100644 --- a/src/Command/MigrateDataTypesCommand.php +++ b/src/Command/MigrateDataTypesCommand.php @@ -43,7 +43,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $em = $this->getEM(); $versions = $em->getConnection()->fetchAllAssociative('SELECT id, extra FROM package_version WHERE extra LIKE "a%" LIMIT 5000'); - $output->writeln(count($versions).' versions to update'); + $output->writeln(\count($versions).' versions to update'); $em->getConnection()->beginTransaction(); foreach ($versions as $version) { $extra = unserialize($version['extra']); @@ -57,12 +57,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $em->getConnection()->update('package_version', ['extra' => $extra], ['id' => $version['id']]); } $em->getConnection()->commit(); - } while (count($versions) > 0); + } while (\count($versions) > 0); do { $emptyRefs = $em->getConnection()->fetchAllAssociative('SELECT package_id, emptyReferences FROM empty_references WHERE emptyReferences LIKE "a%" LIMIT 1000'); - $output->writeln(count($emptyRefs).' empty refs to update'); + $output->writeln(\count($emptyRefs).' empty refs to update'); $em->getConnection()->beginTransaction(); foreach ($emptyRefs as $emptyRef) { $emptyReferences = unserialize($emptyRef['emptyReferences']); @@ -76,12 +76,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $em->getConnection()->update('empty_references', ['emptyReferences' => $emptyReferences], ['package_id' => $emptyRef['package_id']]); } $em->getConnection()->commit(); - } while (count($emptyRefs) > 0); + } while (\count($emptyRefs) > 0); do { $users = $em->getConnection()->fetchAllAssociative('SELECT id, roles FROM fos_user WHERE roles LIKE "a%" LIMIT 1000'); - $output->writeln(count($users).' users to update'); + $output->writeln(\count($users).' users to update'); $em->getConnection()->beginTransaction(); foreach ($users as $user) { $roles = unserialize($user['roles']); @@ -95,7 +95,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $em->getConnection()->update('fos_user', ['roles' => $roles], ['id' => $user['id']]); } $em->getConnection()->commit(); - } while (count($users) > 0); + } while (\count($users) > 0); return 0; } diff --git a/src/Command/MigrateDownloadCountsCommand.php b/src/Command/MigrateDownloadCountsCommand.php index 6aa03bbbd5..83866423d5 100644 --- a/src/Command/MigrateDownloadCountsCommand.php +++ b/src/Command/MigrateDownloadCountsCommand.php @@ -12,16 +12,16 @@ namespace App\Command; -use Composer\Pcre\Preg; -use Doctrine\Persistence\ManagerRegistry; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Seld\Signal\SignalHandler; use App\Model\DownloadManager; use App\Service\Locker; +use Composer\Pcre\Preg; +use Doctrine\Persistence\ManagerRegistry; use Predis\Client; use Psr\Log\LoggerInterface; +use Seld\Signal\SignalHandler; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; class MigrateDownloadCountsCommand extends Command { @@ -69,7 +69,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // skip today datapoints as we will store that to the DB tomorrow $keysToUpdate = array_filter($keysToUpdate, static function ($key) use ($todaySuffix) { - return strpos($key, $todaySuffix) === false; + return !str_contains($key, $todaySuffix); }); // sort by package id, then package datapoint first followed by version datapoints diff --git a/src/Command/MigratePhpStatsCommand.php b/src/Command/MigratePhpStatsCommand.php index 627499ae92..a0cf6b0f56 100644 --- a/src/Command/MigratePhpStatsCommand.php +++ b/src/Command/MigratePhpStatsCommand.php @@ -13,16 +13,16 @@ namespace App\Command; use App\Entity\PhpStat; +use App\Service\Locker; use App\Util\DoctrineTrait; use Composer\Pcre\Preg; use Doctrine\Persistence\ManagerRegistry; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Seld\Signal\SignalHandler; -use App\Service\Locker; use Predis\Client; use Psr\Log\LoggerInterface; +use Seld\Signal\SignalHandler; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; class MigratePhpStatsCommand extends Command { diff --git a/src/Command/PopulateDependentsSuggestersCommand.php b/src/Command/PopulateDependentsSuggestersCommand.php index c8fbd10507..97b2ff1765 100644 --- a/src/Command/PopulateDependentsSuggestersCommand.php +++ b/src/Command/PopulateDependentsSuggestersCommand.php @@ -13,11 +13,11 @@ namespace App\Command; use App\Entity\Dependent; +use App\Service\Locker; use Doctrine\Persistence\ManagerRegistry; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use App\Service\Locker; -use Symfony\Component\Console\Command\Command; /** * @author Jordi Boggiano @@ -52,7 +52,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $ids = $conn->fetchFirstColumn('SELECT id FROM package ORDER BY id ASC'); $ids = array_map('intval', $ids); - $total = count($ids); + $total = \count($ids); $done = 0; while ($id = array_shift($ids)) { if (!$this->locker->lockPackageUpdate($id)) { diff --git a/src/Command/PopulateVersionIdCacheCommand.php b/src/Command/PopulateVersionIdCacheCommand.php index cf3a9229e9..7ce5b0cdc3 100644 --- a/src/Command/PopulateVersionIdCacheCommand.php +++ b/src/Command/PopulateVersionIdCacheCommand.php @@ -12,12 +12,12 @@ namespace App\Command; -use Doctrine\Persistence\ManagerRegistry; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; use App\Model\VersionIdCache; use App\Service\Locker; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; /** * @author Jordi Boggiano @@ -51,7 +51,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** @var int[] $ids */ $ids = array_map('intval', $ids); - $total = count($ids); + $total = \count($ids); $done = 0; while ($id = array_shift($ids)) { if (!$this->locker->lockPackageUpdate($id)) { diff --git a/src/Command/RegenerateMainPhpStatsCommand.php b/src/Command/RegenerateMainPhpStatsCommand.php index dda4337eb5..f1c7ec1a14 100644 --- a/src/Command/RegenerateMainPhpStatsCommand.php +++ b/src/Command/RegenerateMainPhpStatsCommand.php @@ -14,15 +14,15 @@ use App\Entity\Package; use App\Entity\PhpStat; +use App\Service\Locker; use App\Util\DoctrineTrait; use Doctrine\Persistence\ManagerRegistry; +use Psr\Log\LoggerInterface; +use Seld\Signal\SignalHandler; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Seld\Signal\SignalHandler; -use App\Service\Locker; -use Psr\Log\LoggerInterface; -use Symfony\Component\Console\Command\Command; class RegenerateMainPhpStatsCommand extends Command { diff --git a/src/Command/RunWorkersCommand.php b/src/Command/RunWorkersCommand.php index 2367f7e5eb..313c34e5fb 100644 --- a/src/Command/RunWorkersCommand.php +++ b/src/Command/RunWorkersCommand.php @@ -12,14 +12,14 @@ namespace App\Command; +use App\Service\QueueWorker; use App\Util\Killswitch; use Monolog\Logger; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\LockableTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Command\Command; -use App\Service\QueueWorker; use Symfony\Component\Lock\Exception\LockReleasingException; class RunWorkersCommand extends Command @@ -53,7 +53,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ini_set('memory_limit', '1G'); - if (!$this->lock('packagist_run_' . $input->getOption('worker-id'))) { + if (!$this->lock('packagist_run_'.$input->getOption('worker-id'))) { if ($input->getOption('verbose')) { $output->writeln('Aborting, another of the same worker is still active'); } diff --git a/src/Command/SymlinkMetadataMirrorCommand.php b/src/Command/SymlinkMetadataMirrorCommand.php index 686ddba687..d8ccd7ece1 100644 --- a/src/Command/SymlinkMetadataMirrorCommand.php +++ b/src/Command/SymlinkMetadataMirrorCommand.php @@ -25,7 +25,7 @@ public function __construct( private string $webDir, private string $metadataDir, /** @phpstan-var AwsMetadata */ - private array $awsMetadata + private array $awsMetadata, ) { parent::__construct(); } diff --git a/src/Command/UnfreezePackageCommand.php b/src/Command/UnfreezePackageCommand.php index 16c61d56a5..fe0fbbba6b 100644 --- a/src/Command/UnfreezePackageCommand.php +++ b/src/Command/UnfreezePackageCommand.php @@ -12,10 +12,10 @@ namespace App\Command; -use App\Service\Scheduler; -use Doctrine\Persistence\ManagerRegistry; use App\Entity\Package; use App\Model\ProviderManager; +use App\Service\Scheduler; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; diff --git a/src/Command/UpdatePackagesCommand.php b/src/Command/UpdatePackagesCommand.php index 8104e7e017..55a0ae5522 100644 --- a/src/Command/UpdatePackagesCommand.php +++ b/src/Command/UpdatePackagesCommand.php @@ -12,10 +12,10 @@ namespace App\Command; -use Doctrine\Persistence\ManagerRegistry; use App\Entity\Package; use App\Service\Locker; use App\Service\Scheduler; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; diff --git a/src/Command/UpdateSecurityAdvisoriesCommand.php b/src/Command/UpdateSecurityAdvisoriesCommand.php index 4b04f27b9b..fdf7cc1951 100644 --- a/src/Command/UpdateSecurityAdvisoriesCommand.php +++ b/src/Command/UpdateSecurityAdvisoriesCommand.php @@ -45,8 +45,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int { $source = $input->getArgument('source'); $sources = [GitHubSecurityAdvisoriesSource::SOURCE_NAME, FriendsOfPhpSecurityAdvisoriesSource::SOURCE_NAME]; - if (!in_array($source, $sources, true)) { - $output->writeln('source must be one of ' . implode(', ', $sources)); + if (!\in_array($source, $sources, true)) { + $output->writeln('source must be one of '.implode(', ', $sources)); return self::INVALID; } diff --git a/src/Command/UploadMetadataToCdnCommand.php b/src/Command/UploadMetadataToCdnCommand.php index a05dea1091..1cb04ec7a9 100644 --- a/src/Command/UploadMetadataToCdnCommand.php +++ b/src/Command/UploadMetadataToCdnCommand.php @@ -60,7 +60,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $batch = []; } if (($processed % 10000) === 0) { - echo 'Processed '.$processed.PHP_EOL; + echo 'Processed '.$processed.\PHP_EOL; } } @@ -68,7 +68,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->uploadBatch($batch); } - echo PHP_EOL.'Done'.PHP_EOL; + echo \PHP_EOL.'Done'.\PHP_EOL; return 0; } @@ -87,7 +87,7 @@ private function uploadBatch(array $batch): void $pkgWithDevFlag = $match[1]; $pkgName = str_replace('~dev', '', $pkgWithDevFlag); if (!$this->providerManager->packageExists($pkgName)) { - echo 'Skip uploading '.$pkgName.' metadata as the package does not seem to exist anymore'.PHP_EOL; + echo 'Skip uploading '.$pkgName.' metadata as the package does not seem to exist anymore'.\PHP_EOL; continue; } $relativePath = 'p2/'.$pkgWithDevFlag.'.json'; @@ -112,11 +112,11 @@ private function uploadBatch(array $batch): void } catch (\Throwable $e) { $response->cancel(); - echo 'Failed to upload '.$response->getInfo('user_data')['path'].PHP_EOL; + echo 'Failed to upload '.$response->getInfo('user_data')['path'].\PHP_EOL; } } - if ($successful === count($responses)) { + if ($successful === \count($responses)) { echo '.'; } } diff --git a/src/Controller/ApiController.php b/src/Controller/ApiController.php index 345106ff45..e0a0a70630 100644 --- a/src/Controller/ApiController.php +++ b/src/Controller/ApiController.php @@ -24,6 +24,8 @@ use App\Service\Scheduler; use App\Util\UserAgentParser; use Composer\Pcre\Preg; +use Graze\DogStatsD\Client as StatsDClient; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; @@ -31,10 +33,8 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Attribute\Route; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; -use Graze\DogStatsD\Client as StatsDClient; -use Psr\Log\LoggerInterface; use Symfony\Component\Routing\RouterInterface; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -90,12 +90,12 @@ public function createPackageAction(Request $request, ProviderManager $providerM $payload = json_decode($request->getContent(), true); } - if (!$payload || !is_array($payload)) { + if (!$payload || !\is_array($payload)) { return new JsonResponse(['status' => 'error', 'message' => 'Missing payload parameter'], 406); } - if (isset($payload['repository']['url']) && is_string($payload['repository']['url'])) { // supported for BC + if (isset($payload['repository']['url']) && \is_string($payload['repository']['url'])) { // supported for BC $url = $payload['repository']['url']; - } elseif (isset($payload['repository']) && is_string($payload['repository'])) { + } elseif (isset($payload['repository']) && \is_string($payload['repository'])) { $url = $payload['repository']; } else { return new JsonResponse(['status' => 'error', 'message' => '{repository: string} expected in payload'], 406); @@ -106,11 +106,11 @@ public function createPackageAction(Request $request, ProviderManager $providerM return new JsonResponse(['status' => 'error', 'message' => 'Missing or invalid username/apiToken in request'], 406); } - $package = new Package; + $package = new Package(); $package->addMaintainer($user); $package->setRepository($url); $errors = $validator->validate($package, groups: ['Default', 'Create']); - if (count($errors) > 0) { + if (\count($errors) > 0) { $errorArray = []; foreach ($errors as $error) { $errorArray[$error->getPropertyPath()] = $error->getMessage(); @@ -148,7 +148,7 @@ public function updatePackageAction(Request $request, string $githubWebhookSecre $payload = json_decode($request->getContent(), true); } - if (!$payload || !is_array($payload)) { + if (!$payload || !\is_array($payload)) { return new JsonResponse(['status' => 'error', 'message' => 'Missing payload parameter'], 406); } @@ -156,14 +156,14 @@ public function updatePackageAction(Request $request, string $githubWebhookSecre $urlRegex = self::REGEXES['gitlab']; $url = $payload['project']['git_http_url']; $remoteId = null; - } elseif (isset($payload['repository']) && is_string($payload['repository'])) { // anything hook + } elseif (isset($payload['repository']) && \is_string($payload['repository'])) { // anything hook $urlRegex = self::REGEXES['any']; $url = $payload['repository']; $remoteId = null; - } elseif (isset($payload['repository']['url']) && is_string($payload['repository']['url'])) { // github hook + } elseif (isset($payload['repository']['url']) && \is_string($payload['repository']['url'])) { // github hook $urlRegex = self::REGEXES['any']; $url = $payload['repository']['url']; - $remoteId = isset($payload['repository']['id']) && (is_string($payload['repository']['id']) || is_int($payload['repository']['id'])) ? $payload['repository']['id'] : null; + $remoteId = isset($payload['repository']['id']) && (\is_string($payload['repository']['id']) || \is_int($payload['repository']['id'])) ? $payload['repository']['id'] : null; } elseif (isset($payload['repository']['links']['html']['href'])) { // bitbucket push event payload $urlRegex = self::REGEXES['bitbucket_push']; $url = $payload['repository']['links']['html']['href']; @@ -191,7 +191,7 @@ public function editPackageAction(Request $request, Package $package, ValidatorI return new JsonResponse(['status' => 'error', 'message' => 'Missing or invalid username/apiToken in request'], 406); } if (!$package->getMaintainers()->contains($user)) { - throw new AccessDeniedException; + throw new AccessDeniedException(); } $statsd->increment('edit_package_api'); @@ -201,14 +201,14 @@ public function editPackageAction(Request $request, Package $package, ValidatorI $payload = json_decode($request->getContent(), true); } - if (!isset($payload['repository']) || !is_string($payload['repository'])) { + if (!isset($payload['repository']) || !\is_string($payload['repository'])) { return new JsonResponse(['status' => 'error', 'message' => '{repository: string} expected in request body'], 406); } $package->setRepository($payload['repository']); - $errors = $validator->validate($package, null, ["Update"]); - if (count($errors) > 0) { + $errors = $validator->validate($package, null, ['Update']); + if (\count($errors) > 0) { $errorArray = []; foreach ($errors as $error) { $errorArray[$error->getPropertyPath()] = $error->getMessage(); @@ -254,7 +254,7 @@ public function trackDownloadsAction(Request $request, StatsDClient $statsd, str return !isset($item['name'], $item['version']); }; - if (!is_array($contents) || !isset($contents['downloads']) || !is_array($contents['downloads']) || array_filter($contents['downloads'], $invalidInputs)) { + if (!\is_array($contents) || !isset($contents['downloads']) || !\is_array($contents['downloads']) || array_filter($contents['downloads'], $invalidInputs)) { return new JsonResponse(['status' => 'error', 'message' => 'Invalid request format, must be a json object containing a downloads key filled with an array of name/version objects'], 200); } @@ -347,7 +347,7 @@ public function securityAdvisoryAction(Request $request, ProviderManager $provid return $resp; } - $packageNames = array_filter((array) $request->get('packages'), static fn ($name) => is_string($name) && $name !== ''); + $packageNames = array_filter((array) $request->get('packages'), static fn ($name) => \is_string($name) && $name !== ''); if ((!$request->query->has('updatedSince') && !$request->get('packages')) || (!$packageNames && $request->get('packages'))) { return new JsonResponse(['status' => 'error', 'message' => 'Missing array of package names as the "packages" parameter'], 400); } @@ -367,7 +367,7 @@ public function securityAdvisoryAction(Request $request, ProviderManager $provid // Ensure known packages are returned even if no advisory is present to ensure they do not get retried by composer in lower prio repos // Do a max of 1000 packages to prevent abuse - $packagesToCheck = array_slice($packageNames, 0, 1000); + $packagesToCheck = \array_slice($packageNames, 0, 1000); $packageExists = $providerManager->packagesExist($packagesToCheck); foreach ($packagesToCheck as $name) { @@ -409,7 +409,7 @@ protected function getDefaultPackageAndVersionId(string $name): array|false /** * Perform the package update * - * @param string $url the repository's URL (deducted from the request) + * @param string $url the repository's URL (deducted from the request) * @param value-of $urlRegex the regex used to split the user packages into domain and path */ protected function receiveUpdateRequest(Request $request, string $url, string $urlRegex, string|int|null $remoteId, string $githubWebhookSecret): JsonResponse @@ -506,13 +506,13 @@ protected function receiveUpdateRequest(Request $request, string $url, string $u */ protected function findUser(Request $request, ApiType $apiType = ApiType::Unsafe): ?User { - $username = $request->request->has('username') ? - $request->request->get('username') : - $request->query->get('username'); + $username = $request->request->has('username') + ? $request->request->get('username') + : $request->query->get('username'); - $apiToken = $request->request->has('apiToken') ? - $request->request->get('apiToken') : - $request->query->get('apiToken'); + $apiToken = $request->request->has('apiToken') + ? $request->request->get('apiToken') + : $request->query->get('apiToken'); if (!$apiToken || !$username) { return null; @@ -539,6 +539,7 @@ protected function findUser(Request $request, ApiType $apiType = ApiType::Unsafe * Find a user package given by its full URL * * @param value-of $urlRegex + * * @return list */ protected function findPackagesByUrl(User $user, string $url, string $urlRegex, string|int|null $remoteId): array @@ -577,6 +578,7 @@ protected function findPackagesByUrl(User $user, string $url, string $urlRegex, /** * @param User|null $user If provided it means the request came with a user's API token and not the packagist-configured secret, so we cannot be sure it is a request coming directly from github + * * @return Package[] the packages found */ protected function findGitHubPackagesByRepository(string $path, string $remoteId, string $source, ?User $user = null): array diff --git a/src/Controller/ChangePasswordController.php b/src/Controller/ChangePasswordController.php index eb65061bd9..806260ec56 100644 --- a/src/Controller/ChangePasswordController.php +++ b/src/Controller/ChangePasswordController.php @@ -15,12 +15,12 @@ use App\Entity\User; use App\Form\ChangePasswordFormType; use App\Security\UserNotifier; -use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\CurrentUser; +use Symfony\Component\Security\Http\Attribute\IsGranted; class ChangePasswordController extends Controller { diff --git a/src/Controller/Controller.php b/src/Controller/Controller.php index 4d6f853ae8..51b1fe9592 100644 --- a/src/Controller/Controller.php +++ b/src/Controller/Controller.php @@ -12,11 +12,11 @@ namespace App\Controller; -use Doctrine\Persistence\ManagerRegistry; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use App\Entity\Package; use App\Model\DownloadManager; use App\Model\FavoriteManager; +use Doctrine\Persistence\ManagerRegistry; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; @@ -37,6 +37,7 @@ public function setDeps(ManagerRegistry $doctrine): void /** * @param array $packages + * * @return array{downloads: array, favers: array} */ protected function getPackagesMetadata(FavoriteManager $favMgr, DownloadManager $dlMgr, iterable $packages): array @@ -53,7 +54,7 @@ protected function getPackagesMetadata(FavoriteManager $favMgr, DownloadManager $ids[] = $package->getId(); // fetch one by one to avoid re-fetching the github stars as we already have them on the package object $favorites[$package->getId()] = $favMgr->getFaverCount($package); - } elseif (is_array($package)) { + } elseif (\is_array($package)) { $ids[] = $package['id']; // fetch all in one query if we do not have objects $search = true; @@ -75,11 +76,11 @@ protected function getPackagesMetadata(FavoriteManager $favMgr, DownloadManager protected function blockAbusers(Request $req): ?JsonResponse { if (str_contains((string) $req->headers->get('User-Agent'), 'Bytespider; spider-feedback@bytedance.com')) { - return new JsonResponse("Please respect noindex/nofollow meta tags, and email contact@packagist.org to get unblocked once this is resolved", 429, ['Retry-After' => 31536000]); + return new JsonResponse('Please respect noindex/nofollow meta tags, and email contact@packagist.org to get unblocked once this is resolved', 429, ['Retry-After' => 31536000]); } if ($req->getClientIp() === '18.190.1.42') { - return new JsonResponse("Please use the updatedSince flag to fetch new security advisories, and email contact@packagist.org to get unblocked once this is resolved", 429, ['Retry-After' => 31536000]); + return new JsonResponse('Please use the updatedSince flag to fetch new security advisories, and email contact@packagist.org to get unblocked once this is resolved', 429, ['Retry-After' => 31536000]); } $abusers = [ @@ -96,8 +97,8 @@ protected function blockAbusers(Request $req): ?JsonResponse '2a02:4780:d:5838::1', '82.180.155.159', ]; - if (in_array($req->getClientIp(), $abusers, true)) { - return new JsonResponse("Please use a proper user-agent with contact information or get in touch before abusing the API", 429, ['Retry-After' => 31536000]); + if (\in_array($req->getClientIp(), $abusers, true)) { + return new JsonResponse('Please use a proper user-agent with contact information or get in touch before abusing the API', 429, ['Retry-After' => 31536000]); } return null; diff --git a/src/Controller/ExploreController.php b/src/Controller/ExploreController.php index 682a76d634..261deb9dab 100644 --- a/src/Controller/ExploreController.php +++ b/src/Controller/ExploreController.php @@ -12,20 +12,20 @@ namespace App\Controller; +use App\Entity\Package; +use App\Entity\Version; use App\Model\DownloadManager; use App\Model\FavoriteManager; use Doctrine\DBAL\ConnectionException; -use App\Entity\Package; -use App\Entity\Version; use Pagerfanta\Adapter\FixedAdapter; use Pagerfanta\Pagerfanta; +use Predis\Client as RedisClient; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Predis\Client as RedisClient; -use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; #[Route(path: '/explore')] class ExploreController extends Controller diff --git a/src/Controller/FeedController.php b/src/Controller/FeedController.php index cba8998333..9f09a8d2cf 100644 --- a/src/Controller/FeedController.php +++ b/src/Controller/FeedController.php @@ -12,16 +12,16 @@ namespace App\Controller; -use Doctrine\ORM\QueryBuilder; use App\Entity\Package; use App\Entity\Version; +use Doctrine\ORM\QueryBuilder; +use Laminas\Feed\Writer\Entry; +use Laminas\Feed\Writer\Feed; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Laminas\Feed\Writer\Entry; -use Laminas\Feed\Writer\Feed; -use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; /** * @author Rafael Dohms @@ -120,6 +120,7 @@ public function packageAction(Request $req, string $package): Response /** * Limits a query to the desired number of results + * * @return iterable|iterable */ protected function getLimitedResults(QueryBuilder $queryBuilder): iterable diff --git a/src/Controller/GitHubLoginController.php b/src/Controller/GitHubLoginController.php index e908fc2def..38f0ba5de8 100644 --- a/src/Controller/GitHubLoginController.php +++ b/src/Controller/GitHubLoginController.php @@ -36,7 +36,7 @@ class GitHubLoginController extends Controller public function connect(ClientRegistry $clientRegistry): RedirectResponse { $user = $this->getUser(); - if (!is_object($user)) { + if (!\is_object($user)) { throw $this->createAccessDeniedException('This user does not have access to this section.'); } @@ -116,7 +116,7 @@ public function connectCheck(Request $request, ClientRegistry $clientRegistry, S $userNotifier->notifyChange($user->getEmail(), 'A GitHub account ('.$ghUser->getNickname().') has been connected to your Packagist.org account.'); $this->addFlash('success', 'You have connected your GitHub account ('.$ghUser->getNickname().') to your Packagist.org account.'); - } catch (IdentityProviderException | InvalidStateException $e) { + } catch (IdentityProviderException|InvalidStateException $e) { $this->addFlash('error', 'Failed OAuth Login: '.$e->getMessage()); } diff --git a/src/Controller/HealthCheckController.php b/src/Controller/HealthCheckController.php index 29fcf08402..16702e0eb0 100644 --- a/src/Controller/HealthCheckController.php +++ b/src/Controller/HealthCheckController.php @@ -12,18 +12,18 @@ namespace App\Controller; +use App\HealthCheck\MetadataDirCheck; +use App\HealthCheck\RedisHealthCheck; +use Laminas\Diagnostics\Check; use Laminas\Diagnostics\Result\Collection; use Laminas\Diagnostics\Result\ResultInterface; -use Symfony\Component\Routing\Attribute\Route; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Laminas\Diagnostics\Check; use Laminas\Diagnostics\Runner\Runner; -use App\HealthCheck\RedisHealthCheck; -use App\HealthCheck\MetadataDirCheck; use Predis\Client; use Psr\Log\LoggerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Routing\Attribute\Route; class HealthCheckController { @@ -53,11 +53,11 @@ public function healthCheckAction(Request $req): Response $runner = new Runner(); - $dbhost = (string) parse_url($this->dbUrl, PHP_URL_HOST); - $dbname = trim((string) parse_url($this->dbUrl, PHP_URL_PATH), '/'); - $dbuser = (string) parse_url($this->dbUrl, PHP_URL_USER); - $dbpass = (string) parse_url($this->dbUrl, PHP_URL_PASS); - $dbport = (string) parse_url($this->dbUrl, PHP_URL_PORT); + $dbhost = (string) parse_url($this->dbUrl, \PHP_URL_HOST); + $dbname = trim((string) parse_url($this->dbUrl, \PHP_URL_PATH), '/'); + $dbuser = (string) parse_url($this->dbUrl, \PHP_URL_USER); + $dbpass = (string) parse_url($this->dbUrl, \PHP_URL_PASS); + $dbport = (string) parse_url($this->dbUrl, \PHP_URL_PORT); if ($dbport === '') { $dbport = '3306'; } @@ -96,10 +96,10 @@ private function logResults(Collection $results, string $msg): void $result = $results[$checker]; return [ - 'checker' => get_class($checker), + 'checker' => $checker::class, 'message' => $result->getMessage(), 'details' => $result->getData(), - 'result' => strtoupper(str_replace('ZendDiagnostics\\Result\\', '', get_class($result))), + 'result' => strtoupper(str_replace('ZendDiagnostics\\Result\\', '', $result::class)), ]; }, iterator_to_array($results))); } diff --git a/src/Controller/InternalController.php b/src/Controller/InternalController.php index fe56f5b722..c72a62d476 100644 --- a/src/Controller/InternalController.php +++ b/src/Controller/InternalController.php @@ -51,9 +51,9 @@ public function updateMetadataAction(Request $req): Response throw new \RuntimeException('Failed gzencoding '.$contents); } - $path = $this->metadataDir . '/' . $path.'.gz'; - if (!is_dir(dirname($path))) { - mkdir(dirname($path), recursive: true); + $path = $this->metadataDir.'/'.$path.'.gz'; + if (!is_dir(\dirname($path))) { + mkdir(\dirname($path), recursive: true); } file_put_contents($path.'.tmp', $gzipped); touch($path.'.tmp', $filemtime); diff --git a/src/Controller/PackageController.php b/src/Controller/PackageController.php index fb7aeae976..22c9e43648 100644 --- a/src/Controller/PackageController.php +++ b/src/Controller/PackageController.php @@ -13,65 +13,63 @@ namespace App\Controller; use App\Entity\Dependent; -use App\Entity\PackageFreezeReason; -use App\Entity\PackageRepository; -use App\Entity\PhpStat; -use App\Security\Voter\PackageActions; -use App\SecurityAdvisory\GitHubSecurityAdvisoriesSource; -use App\Util\Killswitch; -use App\Model\DownloadManager; -use App\Model\FavoriteManager; -use Composer\MetadataMinifier\MetadataMinifier; -use Composer\Package\Version\VersionParser; -use Composer\Pcre\Preg; -use Composer\Semver\Constraint\Constraint; -use Composer\Semver\Constraint\MatchNoneConstraint; -use Composer\Semver\Constraint\MultiConstraint; -use DateTimeImmutable; -use Doctrine\ORM\NoResultException; use App\Entity\Download; use App\Entity\Job; use App\Entity\Package; +use App\Entity\PackageFreezeReason; +use App\Entity\PackageRepository; +use App\Entity\PhpStat; use App\Entity\SecurityAdvisory; use App\Entity\SecurityAdvisoryRepository; -use App\Entity\Version; -use App\Entity\Vendor; use App\Entity\User; +use App\Entity\Vendor; +use App\Entity\Version; use App\Form\Model\MaintainerRequest; use App\Form\Type\AbandonedType; use App\Form\Type\AddMaintainerRequestType; use App\Form\Type\PackageType; use App\Form\Type\RemoveMaintainerRequestType; +use App\Model\DownloadManager; +use App\Model\FavoriteManager; use App\Model\PackageManager; use App\Model\ProviderManager; +use App\Security\Voter\PackageActions; +use App\SecurityAdvisory\GitHubSecurityAdvisoriesSource; +use App\Service\GitHubUserMigrationWorker; +use App\Service\Scheduler; +use App\Util\Killswitch; +use Composer\MetadataMinifier\MetadataMinifier; +use Composer\Package\Version\VersionParser; +use Composer\Pcre\Preg; +use Composer\Semver\Constraint\Constraint; +use Composer\Semver\Constraint\MatchNoneConstraint; +use Composer\Semver\Constraint\MultiConstraint; +use Doctrine\ORM\NoResultException; use Pagerfanta\Adapter\FixedAdapter; use Pagerfanta\Pagerfanta; +use Predis\Client as RedisClient; use Predis\Connection\ConnectionException; +use Psr\Log\LoggerInterface; use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\MapQueryParameter; +use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; -use App\Service\GitHubUserMigrationWorker; -use App\Service\Scheduler; use Symfony\Component\Routing\RouterInterface; -use Predis\Client as RedisClient; -use Psr\Log\LoggerInterface; -use Symfony\Component\Form\FormError; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; -use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; -use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Security\Http\Attribute\CurrentUser; use Symfony\Component\Security\Http\Attribute\IsGranted; -use UnexpectedValueException; use Webmozart\Assert\Assert; /** @@ -101,14 +99,16 @@ public function allAction(): RedirectResponse public function listAction( Request $req, PackageRepository $repo, - #[MapQueryParameter] ?string $type = null, - #[MapQueryParameter] ?string $vendor = null, + #[MapQueryParameter] + ?string $type = null, + #[MapQueryParameter] + ?string $vendor = null, ): JsonResponse { $queryParams = $req->query->all(); $fields = (array) ($queryParams['fields'] ?? []); // support single or multiple fields $fields = array_intersect($fields, ['repository', 'type', 'abandoned']); - if (count($fields) > 0) { + if (\count($fields) > 0) { $filters = array_filter([ 'type' => $type, 'vendor' => $vendor, @@ -159,7 +159,7 @@ public function updatedSinceAction(Request $req, RedisClient $redis): JsonRespon } try { - $since = new DateTimeImmutable('@'.$since); + $since = new \DateTimeImmutable('@'.$since); } catch (\Exception $e) { return new JsonResponse(['error' => 'Invalid "since" query parameter, make sure you store the timestamp returned and re-use it in the next query. Use '.$this->generateUrl('updated_packages', ['since' => time() - 180], UrlGeneratorInterface::ABSOLUTE_URL).' to initialize it.'], 400); } @@ -207,7 +207,7 @@ public function metadataChangesAction(Request $req, RedisClient $redis): JsonRes } } - if (count($actions) > 100_000) { + if (\count($actions) > 100_000) { return new JsonResponse(['actions' => [['type' => 'resync', 'time' => floor($now / 10000), 'package' => '*']], 'timestamp' => $now]); } @@ -217,7 +217,7 @@ public function metadataChangesAction(Request $req, RedisClient $redis): JsonRes #[Route(path: '/packages/submit', name: 'submit')] public function submitPackageAction(Request $req, GitHubUserMigrationWorker $githubUserMigrationWorker, RouterInterface $router, LoggerInterface $logger, MailerInterface $mailer, string $mailFromEmail, #[CurrentUser] User $user): Response { - $package = new Package; + $package = new Package(); $package->addMaintainer($user); $form = $this->createForm(PackageType::class, $package, [ 'action' => $this->generateUrl('submit'), @@ -256,7 +256,7 @@ public function submitPackageAction(Request $req, GitHubUserMigrationWorker $git #[Route(path: '/packages/fetch-info', name: 'submit.fetch_info', defaults: ['_format' => 'json'])] public function fetchInfoAction(Request $req, RouterInterface $router, #[CurrentUser] User $user): JsonResponse { - $package = new Package; + $package = new Package(); $package->addMaintainer($user); $form = $this->createForm(PackageType::class, $package); @@ -283,7 +283,7 @@ public function fetchInfoAction(Request $req, RouterInterface $router, #[Current if ($form->isSubmitted()) { $errors = []; - if (count($form->getErrors())) { + if (\count($form->getErrors())) { foreach ($form->getErrors() as $error) { if ($error instanceof FormError) { $errors[] = $error->getMessage(); @@ -291,7 +291,7 @@ public function fetchInfoAction(Request $req, RouterInterface $router, #[Current } } foreach ($form->all() as $child) { - if (count($child->getErrors())) { + if (\count($child->getErrors())) { foreach ($child->getErrors() as $error) { if ($error instanceof FormError) { $errors[] = $error->getMessage(); @@ -372,7 +372,7 @@ public function viewProvidersAction(Request $req, string $name, RedisClient $red try { $trendiness = []; foreach ($providers as $package) { - /** @var Package $package */ + /* @var Package $package */ $trendiness[$package->getId()] = (int) $redis->zscore('downloads:trending', (string) $package->getId()); } usort($providers, static function (Package $a, Package $b) use ($trendiness) { @@ -438,7 +438,7 @@ public function viewSpamAction(Request $req, CsrfTokenManagerInterface $csrfToke foreach ($packages as $pkg) { $dls = $data['meta']['downloads'][$pkg['id']] ?? 0; $vendor = Preg::replace('{/.*$}', '', $pkg['name']); - if ($dls > 10 && !in_array($vendor, $verified, true)) { + if ($dls > 10 && !\in_array($vendor, $verified, true)) { $vendorRepo->verify($vendor); $this->addFlash('success', 'Marked '.$vendor.' with '.$dls.' downloads.'); $verified[] = $vendor; @@ -575,13 +575,13 @@ public function viewPackageAction(Request $req, string $name, CsrfTokenManagerIn } $data['downloads'] = $this->downloadManager->getDownloads($package); $data['favers'] = $this->favoriteManager->getFaverCount($package); - } catch (\RuntimeException | ConnectionException $e) { + } catch (\RuntimeException|ConnectionException $e) { $data['downloads'] = null; $data['favers'] = null; } if (empty($data['versions'])) { - $data['versions'] = new \stdClass; + $data['versions'] = new \stdClass(); } $response = new JsonResponse(['package' => $data]); @@ -600,7 +600,7 @@ public function viewPackageAction(Request $req, string $name, CsrfTokenManagerIn usort($versions, Package::class.'::sortVersions'); - if (count($versions)) { + if (\count($versions)) { $versionRepo = $this->getEM()->getRepository(Version::class); // load the default branch version as it is used to display the latest available source.* and homepage info @@ -660,7 +660,7 @@ public function viewPackageAction(Request $req, string $name, CsrfTokenManagerIn if ($user) { $data['is_favorite'] = $this->favoriteManager->isMarked($user, $package); } - } catch (\RuntimeException | ConnectionException) { + } catch (\RuntimeException|ConnectionException) { } $data['dependents'] = Killswitch::isEnabled(Killswitch::PAGE_DETAILS_ENABLED) && Killswitch::isEnabled(Killswitch::LINKS_ENABLED) ? $repo->getDependentCount($package->getName()) : 0; @@ -669,7 +669,7 @@ public function viewPackageAction(Request $req, string $name, CsrfTokenManagerIn if (Killswitch::isEnabled(Killswitch::PAGE_DETAILS_ENABLED)) { $securityAdvisoryRepository = $this->getEM()->getRepository(SecurityAdvisory::class); $securityAdvisories = $securityAdvisoryRepository->getPackageSecurityAdvisories($package->getName()); - $data['securityAdvisories'] = count($securityAdvisories); + $data['securityAdvisories'] = \count($securityAdvisories); $data['hasVersionSecurityAdvisories'] = []; $versionParser = new VersionParser(); $affectedVersionsConstraint = new MatchNoneConstraint(); @@ -677,7 +677,7 @@ public function viewPackageAction(Request $req, string $name, CsrfTokenManagerIn try { $advisoryConstraint = $versionParser->parseConstraints($advisory['affectedVersions']); $affectedVersionsConstraint = MultiConstraint::create([$affectedVersionsConstraint, $advisoryConstraint], false); - } catch (UnexpectedValueException) { + } catch (\UnexpectedValueException) { // ignore parsing errors, advisory must be invalid } } @@ -859,7 +859,7 @@ public function updatePackageAction(Request $req, string $name, #[CurrentUser] U } if (null !== $autoUpdated) { - $package->setAutoUpdated(filter_var($autoUpdated, FILTER_VALIDATE_BOOLEAN) ? Package::AUTO_MANUAL_HOOK : 0); + $package->setAutoUpdated(filter_var($autoUpdated, \FILTER_VALIDATE_BOOLEAN) ? Package::AUTO_MANUAL_HOOK : 0); $this->getEM()->flush(); } @@ -985,7 +985,7 @@ public function editAction(Request $req, #[MapEntity] Package $package, #[Curren { $this->denyAccessUnlessGranted(PackageActions::Edit->value, $package); - $form = $this->createFormBuilder($package, ["validation_groups" => ["Update"]]) + $form = $this->createFormBuilder($package, ['validation_groups' => ['Update']]) ->add('repository', TextType::class) ->setMethod('POST') ->setAction($this->generateUrl('edit_package', ['name' => $package->getName()])) @@ -1002,7 +1002,7 @@ public function editAction(Request $req, #[MapEntity] Package $package, #[Curren $em->persist($package); $em->flush(); - $this->addFlash("success", "Changes saved."); + $this->addFlash('success', 'Changes saved.'); return $this->redirectToRoute('view_package', ['name' => $package->getName()]); } @@ -1024,8 +1024,8 @@ public function abandonAction(Request $request, #[MapEntity] Package $package, # $package->setAbandoned(true); $package->setReplacementPackage(str_replace('https://packagist.org/packages/', '', (string) $form->get('replacement')->getData())); $package->setIndexedAt(null); - $package->setCrawledAt(new DateTimeImmutable()); - $package->setUpdatedAt(new DateTimeImmutable()); + $package->setCrawledAt(new \DateTimeImmutable()); + $package->setUpdatedAt(new \DateTimeImmutable()); $package->setDumpedAt(null); $package->setDumpedAtV2(null); @@ -1049,8 +1049,8 @@ public function unabandonAction(#[MapEntity] Package $package, #[CurrentUser] ?U $package->setAbandoned(false); $package->setReplacementPackage(null); $package->setIndexedAt(null); - $package->setCrawledAt(new DateTimeImmutable()); - $package->setUpdatedAt(new DateTimeImmutable()); + $package->setCrawledAt(new \DateTimeImmutable()); + $package->setUpdatedAt(new \DateTimeImmutable()); $package->setDumpedAt(null); $package->setDumpedAtV2(null); @@ -1089,7 +1089,7 @@ public function statsAction(Request $req, string $name): Response if ($req->getRequestFormat() === 'json') { $data['versions'] = array_map(static function ($version) { - /** @var Version $version */ + /* @var Version $version */ return $version->getVersion(); }, $data['versions']); @@ -1152,7 +1152,7 @@ public function phpStatsAction(Request $req, #[MapEntity] Package $package): Res $label = 'All'; } elseif (str_ends_with($version['version'], '.9999999')) { $label = Preg::replace('{\.9999999$}', '.x-dev', $version['version']); - } elseif (in_array($version['depth'], [PhpStat::DEPTH_MINOR, PhpStat::DEPTH_MAJOR], true)) { + } elseif (\in_array($version['depth'], [PhpStat::DEPTH_MINOR, PhpStat::DEPTH_MAJOR], true)) { $label = $version['version'].'.*'; } else { $label = $version['version']; @@ -1204,14 +1204,14 @@ public function versionPhpStatsAction(Request $req, string $name, string $type, } if ($from = $req->query->get('from')) { - $from = new DateTimeImmutable($from); + $from = new \DateTimeImmutable($from); } else { $from = $this->guessPhpStatsStartDate($package); } if ($to = $req->query->get('to')) { - $to = new DateTimeImmutable($to); + $to = new \DateTimeImmutable($to); } else { - $to = new DateTimeImmutable('today 00:00:00'); + $to = new \DateTimeImmutable('today 00:00:00'); } $average = $req->query->get('average', $this->guessStatsAverage($from, $to)); @@ -1223,7 +1223,7 @@ public function versionPhpStatsAction(Request $req, string $name, string $type, $datePoints = $this->createDatePoints($from, $to, $average); $series = []; - $totals = array_fill(0, count($datePoints), 0); + $totals = array_fill(0, \count($datePoints), 0); $index = 0; foreach ($datePoints as $label => $values) { @@ -1233,7 +1233,7 @@ public function versionPhpStatsAction(Request $req, string $name, string $type, $value += $seriesData[$valueKey] ?? 0; } // average the value over the datapoints in this current label - $value = (int) ceil($value / count($values)); + $value = (int) ceil($value / \count($values)); $series[$seriesName][] = $value; $totals[$index] += $value; @@ -1253,12 +1253,12 @@ public function versionPhpStatsAction(Request $req, string $name, string $type, // delete last datapoint or two if they are still 0 as the nightly job syncing the data in mysql may not have run yet for ($i = 0; $i < 2; $i++) { - if (0 === $totals[count($totals) - 1]) { - unset($totals[count($totals) - 1]); + if (0 === $totals[\count($totals) - 1]) { + unset($totals[\count($totals) - 1]); end($datePoints); unset($datePoints[key($datePoints)]); foreach ($series as $seriesName => $data) { - unset($series[$seriesName][count($data) - 1]); + unset($series[$seriesName][\count($data) - 1]); } } } @@ -1315,7 +1315,7 @@ public function dependentsAction(Request $req, string $name): Response } $orderBy = $req->query->get('order_by', 'name'); - if (!in_array($orderBy, ['name', 'downloads'], true)) { + if (!\in_array($orderBy, ['name', 'downloads'], true)) { throw new BadRequestHttpException('Invalid order_by parameter provided'); } @@ -1439,10 +1439,10 @@ public function majorVersionStatsAction(Request $req, #[MapEntity] Package $pack #[Route(path: '/packages/{name:package}/stats/{version}.json', name: 'version_stats', requirements: ['name' => '[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+?', 'version' => '.+?'])] public function versionStatsAction(Request $req, #[MapEntity] Package $package, string $version): JsonResponse { - $normalizer = new VersionParser; + $normalizer = new VersionParser(); try { $normVersion = $normalizer->normalize($version); - } catch (UnexpectedValueException $e) { + } catch (\UnexpectedValueException $e) { return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_BAD_REQUEST); } @@ -1461,14 +1461,14 @@ public function versionStatsAction(Request $req, #[MapEntity] Package $package, private function computeStats(Request $req, Package $package, ?Version $version = null, ?string $majorVersion = null): JsonResponse { if ($from = $req->query->get('from')) { - $from = new DateTimeImmutable($from); + $from = new \DateTimeImmutable($from); } else { $from = $this->guessStatsStartDate($version ?: $package); } if ($to = $req->query->get('to')) { - $to = new DateTimeImmutable($to); + $to = new \DateTimeImmutable($to); } else { - $to = new DateTimeImmutable('-2days 00:00:00'); + $to = new \DateTimeImmutable('-2days 00:00:00'); } $average = $req->query->get('average', $this->guessStatsAverage($from, $to)); @@ -1501,7 +1501,7 @@ private function computeStats(Request $req, Package $package, ?Version $version $value += $data[$valueKey] ?? 0; } } - $series[$seriesName][] = ceil($value / count($values)); + $series[$seriesName][] = ceil($value / \count($values)); } } @@ -1545,7 +1545,7 @@ public function securityAdvisoriesAction(Request $request, string $name): Respon foreach ($securityAdvisories as $advisory) { try { $affectedVersionConstraint = $versionParser->parseConstraints($advisory->getAffectedVersions()); - } catch (UnexpectedValueException) { + } catch (\UnexpectedValueException) { // ignore parsing errors, advisory must be invalid continue; } @@ -1560,7 +1560,7 @@ public function securityAdvisoriesAction(Request $request, string $name): Respon } $data['securityAdvisories'] = $securityAdvisories; - $data['count'] = count($securityAdvisories); + $data['count'] = \count($securityAdvisories); return $this->render('package/security_advisories.html.twig', $data); } @@ -1577,7 +1577,7 @@ public function securityAdvisoryAction(Request $request, string $id): Response $securityAdvisories = array_filter([$repo->findOneBy(['packagistAdvisoryId' => $id])]); } - if (0 === count($securityAdvisories)) { + if (0 === \count($securityAdvisories)) { throw new NotFoundHttpException(); } @@ -1655,7 +1655,7 @@ private function getPackageByName(Request $req, string $name): Package|Response /** * @return array */ - private function createDatePoints(DateTimeImmutable $from, DateTimeImmutable $to, string $average): array + private function createDatePoints(\DateTimeImmutable $from, \DateTimeImmutable $to, string $average): array { $interval = $this->getStatsInterval($average); @@ -1666,7 +1666,7 @@ private function createDatePoints(DateTimeImmutable $from, DateTimeImmutable $to $nextDataPointLabel = $from->format($dateFormat); if ($average === 'monthly') { - $nextDataPoint = new DateTimeImmutable('first day of ' . $from->format('Y-m')); + $nextDataPoint = new \DateTimeImmutable('first day of '.$from->format('Y-m')); $nextDataPoint = $nextDataPoint->modify($interval); } else { $nextDataPoint = $from->modify($interval); @@ -1686,17 +1686,17 @@ private function createDatePoints(DateTimeImmutable $from, DateTimeImmutable $to return $datePoints; } - private function guessStatsStartDate(Package|Version $packageOrVersion): DateTimeImmutable + private function guessStatsStartDate(Package|Version $packageOrVersion): \DateTimeImmutable { if ($packageOrVersion instanceof Package) { - $date = DateTimeImmutable::createFromInterface($packageOrVersion->getCreatedAt()); + $date = \DateTimeImmutable::createFromInterface($packageOrVersion->getCreatedAt()); } elseif ($packageOrVersion->getReleasedAt()) { - $date = DateTimeImmutable::createFromInterface($packageOrVersion->getReleasedAt()); + $date = \DateTimeImmutable::createFromInterface($packageOrVersion->getReleasedAt()); } else { throw new \LogicException('Version with release date expected'); } - $statsRecordDate = new DateTimeImmutable('2012-04-13 00:00:00'); + $statsRecordDate = new \DateTimeImmutable('2012-04-13 00:00:00'); if ($date < $statsRecordDate) { $date = $statsRecordDate; } @@ -1704,11 +1704,11 @@ private function guessStatsStartDate(Package|Version $packageOrVersion): DateTim return $date->setTime(0, 0, 0); } - private function guessPhpStatsStartDate(Package $package): DateTimeImmutable + private function guessPhpStatsStartDate(Package $package): \DateTimeImmutable { - $date = DateTimeImmutable::createFromInterface($package->getCreatedAt()); + $date = \DateTimeImmutable::createFromInterface($package->getCreatedAt()); - $statsRecordDate = new DateTimeImmutable('2021-05-18 00:00:00'); + $statsRecordDate = new \DateTimeImmutable('2021-05-18 00:00:00'); if ($date < $statsRecordDate) { $date = $statsRecordDate; } @@ -1716,10 +1716,10 @@ private function guessPhpStatsStartDate(Package $package): DateTimeImmutable return $date->setTime(0, 0, 0); } - private function guessStatsAverage(DateTimeImmutable $from, ?DateTimeImmutable $to = null): string + private function guessStatsAverage(\DateTimeImmutable $from, ?\DateTimeImmutable $to = null): string { if ($to === null) { - $to = new DateTimeImmutable('-2 days'); + $to = new \DateTimeImmutable('-2 days'); } if ($from < $to->modify('-48months')) { $average = 'monthly'; diff --git a/src/Controller/ProfileController.php b/src/Controller/ProfileController.php index 28a89096be..02bd79ed41 100644 --- a/src/Controller/ProfileController.php +++ b/src/Controller/ProfileController.php @@ -25,9 +25,9 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Security\Http\Attribute\CurrentUser; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class ProfileController extends Controller { @@ -44,7 +44,7 @@ public function myProfile(Request $req, FavoriteManager $favMgr, DownloadManager 'githubSync' => $lastGithubSync, ]; - if (!count($packages)) { + if (!\count($packages)) { $data['deleteForm'] = $this->createFormBuilder([])->getForm()->createView(); } $data['rotateApiCsrfToken'] = $csrfTokenManager->getToken('rotate_api'); @@ -69,7 +69,7 @@ public function publicProfile(Request $req, #[VarName('name')] User $user, Favor if ($this->isGranted('ROLE_ANTISPAM')) { $data['spammerForm'] = $this->createFormBuilder([])->getForm()->createView(); } - if (!count($packages) && ($this->isGranted('ROLE_ADMIN') || $loggedUser?->getId() === $user->getId())) { + if (!\count($packages) && ($this->isGranted('ROLE_ADMIN') || $loggedUser?->getId() === $user->getId())) { $data['deleteForm'] = $this->createFormBuilder([])->getForm()->createView(); } @@ -135,7 +135,7 @@ public function editAction(Request $request, UserNotifier $userNotifier): Respon ]); if (!empty($diffs)) { - $reason = sprintf('Your %s has been changed', implode(' and ', $diffs)); + $reason = \sprintf('Your %s has been changed', implode(' and ', $diffs)); if ($oldEmail !== $user->getEmail()) { $userNotifier->notifyChange($oldEmail, $reason); diff --git a/src/Controller/RegistrationController.php b/src/Controller/RegistrationController.php index e7358c325c..e4677c1151 100644 --- a/src/Controller/RegistrationController.php +++ b/src/Controller/RegistrationController.php @@ -13,10 +13,10 @@ namespace App\Controller; use App\Entity\User; +use App\Entity\UserRepository; use App\Form\RegistrationFormType; -use App\Security\EmailVerifier; use App\Security\BruteForceLoginFormAuthenticator; -use App\Entity\UserRepository; +use App\Security\EmailVerifier; use App\Security\UserChecker; use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Component\HttpFoundation\Request; @@ -61,7 +61,7 @@ public function register(Request $request, UserPasswordHasherInterface $password $this->emailVerifier->sendEmailConfirmation( 'register_confirm_email', $user, - (new TemplatedEmail()) + new TemplatedEmail() ->from(new Address($mailFromEmail, $mailFromName)) ->to($user->getEmail()) ->subject('Please confirm your email') diff --git a/src/Controller/ResetPasswordController.php b/src/Controller/ResetPasswordController.php index cb7f3f55dd..c76f0dffd7 100644 --- a/src/Controller/ResetPasswordController.php +++ b/src/Controller/ResetPasswordController.php @@ -147,7 +147,7 @@ private function processSendingPasswordResetEmail(string $userEmail, MailerInter $this->getEM()->flush(); } - $email = (new TemplatedEmail()) + $email = new TemplatedEmail() ->from(new Address($this->mailFromEmail, $this->mailFromName)) ->to($user->getEmail()) ->subject('Your password reset request') diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index a2d69776bc..7f36843b0f 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -13,39 +13,39 @@ namespace App\Controller; use App\Attribute\VarName; -use App\Entity\TemporaryTwoFactorUser; -use App\Model\FavoriteManager; use App\Entity\Package; -use App\Entity\Version; +use App\Entity\TemporaryTwoFactorUser; use App\Entity\User; +use App\Entity\Version; use App\Entity\VersionRepository; use App\Form\Model\EnableTwoFactorRequest; use App\Form\Type\EnableTwoFactorAuthType; +use App\Model\FavoriteManager; use App\Model\PackageManager; use App\Model\ProviderManager; use App\Model\RedisAdapter; use App\Security\TwoFactorAuthManager; use App\Service\Scheduler; +use Endroid\QrCode\Builder\Builder; +use Endroid\QrCode\Encoding\Encoding; use Endroid\QrCode\ErrorCorrectionLevel; use Endroid\QrCode\RoundBlockSizeMode; use Endroid\QrCode\Writer\SvgWriter; use Pagerfanta\Pagerfanta; +use Predis\Client as RedisClient; use Psr\Log\LoggerInterface; use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Totp\TotpAuthenticatorInterface; use Symfony\Bridge\Doctrine\Attribute\MapEntity; -use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Predis\Client as RedisClient; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Security\Http\Attribute\CurrentUser; +use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\Security\Http\Event\LogoutEvent; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -use Endroid\QrCode\Builder\Builder; -use Endroid\QrCode\Encoding\Encoding; /** * @author Jordi Boggiano @@ -138,7 +138,7 @@ public function markSpammerAction(Request $req, #[VarName('name')] User $user): } return $this->redirect( - $this->generateUrl("user_profile", ["name" => $user->getUsername()]) + $this->generateUrl('user_profile', ['name' => $user->getUsername()]) ); } @@ -192,9 +192,12 @@ public function postFavoriteAction(Request $req, #[VarName('name')] User $user, #[IsGranted('ROLE_USER')] #[Route(path: '/users/{name}/favorites/{package}', name: 'user_remove_fav', defaults: ['_format' => 'json'], requirements: ['package' => '[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+?'], methods: ['DELETE'])] public function deleteFavoriteAction( - #[VarName('name')] User $user, - #[CurrentUser] User $loggedUser, - #[MapEntity(mapping: ['package' => 'name'])] Package $package, + #[VarName('name')] + User $user, + #[CurrentUser] + User $loggedUser, + #[MapEntity(mapping: ['package' => 'name'])] + Package $package, FavoriteManager $favoriteManager, ): Response { if ($user->getId() !== $loggedUser->getId()) { @@ -214,7 +217,7 @@ public function deleteUserAction(#[VarName('name')] User $user, #[CurrentUser] U throw $this->createAccessDeniedException('You cannot delete this user'); } - if (count($user->getPackages()) > 0) { + if (\count($user->getPackages()) > 0) { throw $this->createAccessDeniedException('The user has packages so it can not be deleted'); } diff --git a/src/Controller/WebController.php b/src/Controller/WebController.php index 766fa320e5..9237a5af3b 100644 --- a/src/Controller/WebController.php +++ b/src/Controller/WebController.php @@ -13,21 +13,21 @@ namespace App\Controller; use Algolia\AlgoliaSearch\Exceptions\AlgoliaException; -use App\Entity\Version; use App\Entity\Package; use App\Entity\PhpStat; +use App\Entity\Version; use App\Search\Algolia; use App\Search\Query; use App\Util\Killswitch; +use Predis\Client as RedisClient; use Predis\Connection\ConnectionException; use Psr\Cache\CacheItemInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Attribute\Route; -use Predis\Client as RedisClient; use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Contracts\Cache\CacheInterface; /** @@ -59,10 +59,10 @@ public function search(Request $req): RedirectResponse|Response public function searchApi(Request $req, Algolia $algolia): JsonResponse { $blockList = ['2400:6180:100:d0::83b:b001', '34.235.38.170']; - if (in_array($req->getClientIp(), $blockList, true)) { - return (new JsonResponse([ + if (\in_array($req->getClientIp(), $blockList, true)) { + return new JsonResponse([ 'error' => 'Too many requests, reach out to contact@packagist.org', - ], 400))->setCallback($req->query->get('callback')); + ], 400)->setCallback($req->query->get('callback')); } try { @@ -74,22 +74,22 @@ public function searchApi(Request $req, Algolia $algolia): JsonResponse $req->query->getInt('page', 1) ); } catch (\InvalidArgumentException $e) { - return (new JsonResponse([ + return new JsonResponse([ 'status' => 'error', 'message' => $e->getMessage(), - ], 400))->setCallback($req->query->get('callback')); + ], 400)->setCallback($req->query->get('callback')); } try { $result = $algolia->search($query); } catch (AlgoliaException) { - return (new JsonResponse([ + return new JsonResponse([ 'status' => 'error', 'message' => 'Could not connect to the search server', - ], 500))->setCallback($req->query->get('callback')); + ], 500)->setCallback($req->query->get('callback')); } - $response = (new JsonResponse($result))->setCallback($req->query->get('callback')); + $response = new JsonResponse($result)->setCallback($req->query->get('callback')); $response->setSharedMaxAge(300); $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true'); @@ -109,8 +109,8 @@ public function statsAction(RedisClient $redis): Response $chart = ['versions' => [], 'packages' => [], 'months' => []]; // prepare x axis - $date = new \DateTime($packages[0]['year'] . '-' . $packages[0]['month'] . '-01'); - $now = new \DateTime; + $date = new \DateTime($packages[0]['year'].'-'.$packages[0]['month'].'-01'); + $now = new \DateTime(); while ($date < $now) { $chart['months'][] = $month = $date->format('Y-m'); $date->modify('+1month'); @@ -120,24 +120,24 @@ public function statsAction(RedisClient $redis): Response $count = 0; foreach ($packages as $dataPoint) { $count += $dataPoint['count']; - $chart['packages'][$dataPoint['year'] . '-' . str_pad((string) $dataPoint['month'], 2, '0', STR_PAD_LEFT)] = $count; + $chart['packages'][$dataPoint['year'].'-'.str_pad((string) $dataPoint['month'], 2, '0', \STR_PAD_LEFT)] = $count; } $count = 0; foreach ($versions as $dataPoint) { - $yearMonth = $dataPoint['year'] . '-' . str_pad((string) $dataPoint['month'], 2, '0', STR_PAD_LEFT); + $yearMonth = $dataPoint['year'].'-'.str_pad((string) $dataPoint['month'], 2, '0', \STR_PAD_LEFT); $count += $dataPoint['count']; - if (in_array($yearMonth, $chart['months'])) { + if (\in_array($yearMonth, $chart['months'])) { $chart['versions'][$yearMonth] = $count; } } // fill gaps at the end of the chart - if (count($chart['months']) > count($chart['packages'])) { - $chart['packages'] += array_fill(0, count($chart['months']) - count($chart['packages']), !empty($chart['packages']) ? max($chart['packages']) : 0); + if (\count($chart['months']) > \count($chart['packages'])) { + $chart['packages'] += array_fill(0, \count($chart['months']) - \count($chart['packages']), !empty($chart['packages']) ? max($chart['packages']) : 0); } - if (count($chart['months']) > count($chart['versions'])) { - $chart['versions'] += array_fill(0, count($chart['months']) - count($chart['versions']), !empty($chart['versions']) ? max($chart['versions']) : 0); + if (\count($chart['months']) > \count($chart['versions'])) { + $chart['versions'] += array_fill(0, \count($chart['months']) - \count($chart['versions']), !empty($chart['versions']) ? max($chart['versions']) : 0); } $downloadsStartDate = '2012-04-13'; @@ -212,7 +212,7 @@ public function phpStatsAction(Request $req, CacheInterface $cache): Response $type = $req->query->getInt('platform', 0) > 0 ? 'phpplatform' : 'php'; - [$dailyData, $monthlyData] = $cache->get('php-statistics-' . $type, function (CacheItemInterface $item) use ($versions, $type) { + [$dailyData, $monthlyData] = $cache->get('php-statistics-'.$type, function (CacheItemInterface $item) use ($versions, $type) { $item->expiresAfter(1800); return [ @@ -251,7 +251,7 @@ public function statsTotalsAction(RedisClient $redis): Response return new JsonResponse(['totals' => $totals], 200); } - private function checkForQueryMatch(Request $req): RedirectResponse|null + private function checkForQueryMatch(Request $req): ?RedirectResponse { $q = $req->query->has('q') ? $req->query->get('q') : $req->query->get('query'); diff --git a/src/Entity/AuditRecord.php b/src/Entity/AuditRecord.php index fcb84ba367..ab130482c3 100644 --- a/src/Entity/AuditRecord.php +++ b/src/Entity/AuditRecord.php @@ -13,7 +13,6 @@ namespace App\Entity; use App\Audit\AuditRecordType; -use DateTimeImmutable; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Uid\Ulid; @@ -31,7 +30,7 @@ class AuditRecord public readonly Ulid $id; #[ORM\Column] - public readonly DateTimeImmutable $datetime; + public readonly \DateTimeImmutable $datetime; private function __construct( #[ORM\Column] @@ -41,39 +40,39 @@ private function __construct( #[ORM\Column(type: Types::JSON)] public readonly array $attributes, #[ORM\Column(nullable: true)] - public readonly int|null $userId = null, + public readonly ?int $userId = null, #[ORM\Column(nullable: true)] - public readonly string|null $vendor = null, + public readonly ?string $vendor = null, #[ORM\Column(nullable: true)] - public readonly int|null $packageId = null, + public readonly ?int $packageId = null, ) { $this->id = new Ulid(); - $this->datetime = new DateTimeImmutable(); + $this->datetime = new \DateTimeImmutable(); } - public static function packageCreated(Package $package, User|null $user): self + public static function packageCreated(Package $package, ?User $user): self { return new self(AuditRecordType::PackageCreated, ['name' => $package->getName(), 'repository' => $package->getRepository(), 'actor' => self::getUserData($user)], $user?->getId(), $package->getVendor(), $package->getId()); } - public static function packageDeleted(Package $package, User|null $user): self + public static function packageDeleted(Package $package, ?User $user): self { return new self(AuditRecordType::PackageDeleted, ['name' => $package->getName(), 'repository' => $package->getRepository(), 'actor' => self::getUserData($user, 'automation')], $user?->getId(), $package->getVendor(), $package->getId()); } - public static function canonicalUrlChange(Package $package, User|null $user, string $oldRepository): self + public static function canonicalUrlChange(Package $package, ?User $user, string $oldRepository): self { return new self(AuditRecordType::CanonicalUrlChange, ['name' => $package->getName(), 'repository_from' => $oldRepository, 'repository_to' => $package->getRepository(), 'actor' => self::getUserData($user)], $user?->getId(), $package->getVendor(), $package->getId()); } - public static function versionDeleted(Version $version, User|null $user): self + public static function versionDeleted(Version $version, ?User $user): self { $package = $version->getPackage(); return new self(AuditRecordType::VersionDeleted, ['name' => $package->getName(), 'version' => $version->getVersion(), 'actor' => self::getUserData($user, 'automation')], $user?->getId(), $package->getVendor(), $package->getId()); } - public static function versionReferenceChange(Version $version, string|null $oldSourceReference, string|null $oldDistReference): self + public static function versionReferenceChange(Version $version, ?string $oldSourceReference, ?string $oldDistReference): self { $package = $version->getPackage(); @@ -88,7 +87,7 @@ public static function versionReferenceChange(Version $version, string|null $old /** * @return array{id: int, username: string}|string */ - private static function getUserData(User|null $user, string $fallbackString = 'unknown'): array|string + private static function getUserData(?User $user, string $fallbackString = 'unknown'): array|string { if ($user === null) { return $fallbackString; diff --git a/src/Entity/AuditRecordRepository.php b/src/Entity/AuditRecordRepository.php index 91da4fa115..7a83308cca 100644 --- a/src/Entity/AuditRecordRepository.php +++ b/src/Entity/AuditRecordRepository.php @@ -13,8 +13,8 @@ namespace App\Entity; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; -use Doctrine\Persistence\ManagerRegistry; use Doctrine\DBAL\Types\Types; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Bridge\Doctrine\Types\UlidType; /** diff --git a/src/Entity/Download.php b/src/Entity/Download.php index fe811c4c43..1d7fd76fc0 100644 --- a/src/Entity/Download.php +++ b/src/Entity/Download.php @@ -12,7 +12,6 @@ namespace App\Entity; -use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: 'App\Entity\DownloadRepository')] @@ -46,10 +45,10 @@ class Download public int $total = 0; #[ORM\Column(type: 'datetime_immutable')] - public DateTimeImmutable $lastUpdated; + public \DateTimeImmutable $lastUpdated; #[ORM\ManyToOne(targetEntity: 'App\Entity\Package', inversedBy: 'downloads')] - public Package|null $package = null; + public ?Package $package = null; public function computeSum(): void { @@ -105,12 +104,12 @@ public function getTotal(): int return $this->total; } - public function setLastUpdated(DateTimeImmutable $lastUpdated): void + public function setLastUpdated(\DateTimeImmutable $lastUpdated): void { $this->lastUpdated = $lastUpdated; } - public function getLastUpdated(): DateTimeImmutable + public function getLastUpdated(): \DateTimeImmutable { return $this->lastUpdated; } @@ -120,7 +119,7 @@ public function setPackage(Package $package): void $this->package = $package; } - public function getPackage(): Package|null + public function getPackage(): ?Package { return $this->package; } diff --git a/src/Entity/DownloadRepository.php b/src/Entity/DownloadRepository.php index eecbd82fba..e560669ef0 100644 --- a/src/Entity/DownloadRepository.php +++ b/src/Entity/DownloadRepository.php @@ -48,7 +48,7 @@ public function findDataByMajorVersion(Package $package, int $majorVersion): arr $stmt = $this->getEntityManager()->getConnection() ->executeQuery( $sql, - ['package' => $package->getId(), 'versionType' => Download::TYPE_VERSION, 'majorVersion' => $majorVersion . '.%'] + ['package' => $package->getId(), 'versionType' => Download::TYPE_VERSION, 'majorVersion' => $majorVersion.'.%'] ); $result = $stmt->fetchAllAssociative(); $stmt->free(); diff --git a/src/Entity/Job.php b/src/Entity/Job.php index 90f5f9c2c4..d6f3567a3d 100644 --- a/src/Entity/Job.php +++ b/src/Entity/Job.php @@ -12,7 +12,6 @@ namespace App\Entity; -use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; /** @@ -65,19 +64,19 @@ class Job private ?array $result = null; #[ORM\Column(type: 'datetime_immutable')] - private DateTimeImmutable $createdAt; + private \DateTimeImmutable $createdAt; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $startedAt = null; + private ?\DateTimeImmutable $startedAt = null; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $completedAt = null; + private ?\DateTimeImmutable $completedAt = null; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $executeAfter = null; + private ?\DateTimeImmutable $executeAfter = null; #[ORM\Column(type: 'integer', nullable: true)] - private int|null $packageId = null; + private ?int $packageId = null; /** * @param T $payload @@ -87,12 +86,12 @@ public function __construct(string $id, string $type, array $payload) $this->id = $id; $this->type = $type; $this->payload = $payload; - $this->createdAt = new DateTimeImmutable(); + $this->createdAt = new \DateTimeImmutable(); } public function start(): void { - $this->startedAt = new DateTimeImmutable(); + $this->startedAt = new \DateTimeImmutable(); $this->status = self::STATUS_STARTED; } @@ -102,11 +101,11 @@ public function start(): void public function complete(array $result): void { $this->result = $result; - $this->completedAt = new DateTimeImmutable(); + $this->completedAt = new \DateTimeImmutable(); $this->status = $result['status']; } - public function reschedule(DateTimeImmutable $when): void + public function reschedule(\DateTimeImmutable $when): void { $this->status = self::STATUS_QUEUED; $this->startedAt = null; @@ -118,12 +117,12 @@ public function getId(): string return $this->id; } - public function setPackageId(int|null $packageId): void + public function setPackageId(?int $packageId): void { $this->packageId = $packageId; } - public function getPackageId(): int|null + public function getPackageId(): ?int { return $this->packageId; } @@ -165,32 +164,32 @@ public function getResult(): ?array return $this->result; } - public function setCreatedAt(DateTimeImmutable $createdAt): void + public function setCreatedAt(\DateTimeImmutable $createdAt): void { $this->createdAt = $createdAt; } - public function getCreatedAt(): DateTimeImmutable + public function getCreatedAt(): \DateTimeImmutable { return $this->createdAt; } - public function getStartedAt(): DateTimeImmutable|null + public function getStartedAt(): ?\DateTimeImmutable { return $this->startedAt; } - public function setExecuteAfter(DateTimeImmutable|null $executeAfter): void + public function setExecuteAfter(?\DateTimeImmutable $executeAfter): void { $this->executeAfter = $executeAfter; } - public function getExecuteAfter(): DateTimeImmutable|null + public function getExecuteAfter(): ?\DateTimeImmutable { return $this->executeAfter; } - public function getCompletedAt(): DateTimeImmutable|null + public function getCompletedAt(): ?\DateTimeImmutable { return $this->completedAt; } diff --git a/src/Entity/Package.php b/src/Entity/Package.php index 336bf344f9..a047cf9956 100644 --- a/src/Entity/Package.php +++ b/src/Entity/Package.php @@ -14,25 +14,24 @@ use App\Service\UpdaterWorker; use App\Util\HttpDownloaderOptionsFactory; +use App\Validator\Copyright; use App\Validator\PopularPackageSafety; use App\Validator\TypoSquatters; -use App\Validator\Copyright; use App\Validator\UniquePackage; use App\Validator\ValidPackageRepository; use App\Validator\VendorWritable; use Composer\Factory; use Composer\IO\NullIO; use Composer\Pcre\Preg; +use Composer\Repository\Vcs\GitHubDriver; use Composer\Repository\Vcs\VcsDriverInterface; use Composer\Repository\VcsRepository; +use Composer\Util\HttpDownloader; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Selectable; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; -use Composer\Repository\Vcs\GitHubDriver; -use Composer\Util\HttpDownloader; -use DateTimeImmutable; enum PackageFreezeReason: string { @@ -42,7 +41,7 @@ enum PackageFreezeReason: string public function translationKey(): string { - return 'freezing_reasons.' . $this->value; + return 'freezing_reasons.'.$this->value; } public function isSpam(): bool @@ -63,6 +62,7 @@ public function isRemoteIdMismatch(): bool /** * @author Jordi Boggiano + * * @phpstan-import-type VersionArray from Version */ #[ORM\Entity(repositoryClass: 'App\Entity\PackageRepository')] @@ -105,28 +105,28 @@ class Package private string $vendor = ''; #[ORM\Column(nullable: true)] - private string|null $type = null; + private ?string $type = null; #[ORM\Column(type: 'text', nullable: true)] - private string|null $description = null; + private ?string $description = null; #[ORM\Column(type: 'string', nullable: true)] - private string|null $language = null; + private ?string $language = null; #[ORM\Column(type: 'text', nullable: true)] - private string|null $readme = null; + private ?string $readme = null; #[ORM\Column(type: 'integer', nullable: true, name: 'github_stars')] - private int|null $gitHubStars = null; + private ?int $gitHubStars = null; #[ORM\Column(type: 'integer', nullable: true, name: 'github_watches')] - private int|null $gitHubWatches = null; + private ?int $gitHubWatches = null; #[ORM\Column(type: 'integer', nullable: true, name: 'github_forks')] - private int|null $gitHubForks = null; + private ?int $gitHubForks = null; #[ORM\Column(type: 'integer', nullable: true, name: 'github_open_issues')] - private int|null $gitHubOpenIssues = null; + private ?int $gitHubOpenIssues = null; /** * @var Collection&Selectable @@ -146,22 +146,22 @@ class Package private string $repository; #[ORM\Column(type: 'datetime_immutable')] - private DateTimeImmutable $createdAt; + private \DateTimeImmutable $createdAt; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $updatedAt = null; + private ?\DateTimeImmutable $updatedAt = null; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $crawledAt = null; + private ?\DateTimeImmutable $crawledAt = null; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $indexedAt = null; + private ?\DateTimeImmutable $indexedAt = null; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $dumpedAt = null; + private ?\DateTimeImmutable $dumpedAt = null; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $dumpedAtV2 = null; + private ?\DateTimeImmutable $dumpedAtV2 = null; /** * @var Collection&Selectable @@ -170,7 +170,7 @@ class Package private Collection $downloads; #[ORM\Column(type: 'string', nullable: true)] - private string|null $remoteId = null; + private ?string $remoteId = null; /** * @var int one of self::AUTO_* @@ -182,7 +182,7 @@ class Package private bool $abandoned = false; #[ORM\Column(type: 'string', length: 255, nullable: true)] - private string|null $replacementPackage = null; + private ?string $replacementPackage = null; #[ORM\Column(type: 'boolean', options: ['default' => false])] private bool $updateFailureNotified = false; @@ -191,39 +191,41 @@ class Package * If set, the content is the reason for being marked suspicious */ #[ORM\Column(type: 'string', length: 255, nullable: true)] - private string|null $suspect = null; + private ?string $suspect = null; /** * If set, the content is the reason for being frozen */ #[ORM\Column(nullable: true)] - private PackageFreezeReason|null $frozen = null; + private ?PackageFreezeReason $frozen = null; /** * @internal - * @var true|null|VcsDriverInterface + * + * @var true|VcsDriverInterface|null */ public VcsDriverInterface|bool|null $vcsDriver = true; /** * @internal */ - public string|null $vcsDriverError = null; + public ?string $vcsDriverError = null; /** * @var array|null lookup table for versions */ - private array|null $cachedVersions = null; + private ?array $cachedVersions = null; public function __construct() { $this->versions = new ArrayCollection(); $this->maintainers = new ArrayCollection(); $this->downloads = new ArrayCollection(); - $this->createdAt = new DateTimeImmutable(); + $this->createdAt = new \DateTimeImmutable(); } /** * @param VersionRepository|array $versionRepo Version repo or an already array-ified version dataset + * * @return array{ * name: string, * description: string|null, @@ -247,7 +249,7 @@ public function toArray(VersionRepository|array $versionRepo, bool $serializeFor $maintainers[] = $maintainer->toArray(); } - if (is_array($versionRepo)) { + if (\is_array($versionRepo)) { $versions = $versionRepo; } else { $versions = []; @@ -313,7 +315,7 @@ public function getVendor(): string /** * @return array|null Vendor and package name */ - public function getGitHubComponents(): array|null + public function getGitHubComponents(): ?array { if (Preg::isMatchStrictGroups('{^(?:git://|git@|https?://)github.com[:/]([^/]+)/(.+?)(?:\.git|/)?$}i', $this->getRepository(), $match)) { return $match; @@ -325,7 +327,7 @@ public function getGitHubComponents(): array|null /** * @return array|null Vendor and package name */ - public function getGitLabComponents(): array|null + public function getGitLabComponents(): ?array { if (Preg::isMatchStrictGroups('{^(?:git://|git@|https?://)gitlab.com[:/]([^/]+)/(.+?)(?:\.git|/)?$}i', $this->getRepository(), $match)) { return $match; @@ -352,12 +354,12 @@ public function getPackageName(): string return Preg::replace('{^[^/]*/}', '', $this->name); } - public function setDescription(string|null $description): void + public function setDescription(?string $description): void { $this->description = $description; } - public function getDescription(): string|null + public function getDescription(): ?string { return $this->description; } @@ -367,7 +369,7 @@ public function setLanguage(string $language): void $this->language = $language; } - public function getLanguage(): string|null + public function getLanguage(): ?string { return $this->language; } @@ -394,76 +396,76 @@ public function getOptimizedReadme(): string return str_replace([' $query + * * @return list */ private function getPackageNamesForQuery(Query $query): array { $names = []; foreach ($query->getScalarResult() as $row) { - if (!is_array($row) || !isset($row['name']) || !is_string($row['name'])) { + if (!\is_array($row) || !isset($row['name']) || !\is_string($row['name'])) { throw new \LogicException('Excepted rows with a name field, got '.json_encode($row)); } $names[] = $row['name']; } - sort($names, SORT_STRING | SORT_FLAG_CASE); + sort($names, \SORT_STRING | \SORT_FLAG_CASE); return $names; } @@ -290,7 +292,7 @@ public function getStalePackagesForDumpingV2(): array } /** - * @return iterable + * @return iterable */ public function iterateStaleDownloadCountPackageIds(): iterable { @@ -300,12 +302,12 @@ public function iterateStaleDownloadCountPackageIds(): iterable ->leftJoin('p.downloads', 'd') ->where('((d.type = :type AND d.lastUpdated < :time) OR d.lastUpdated IS NULL)') ->setParameter('type', Download::TYPE_PACKAGE) - ->setParameter('time', new DateTimeImmutable('-20hours')) + ->setParameter('time', new \DateTimeImmutable('-20hours')) ->getQuery() ->getResult(); foreach ($res as $row) { - yield ['id' => (int) $row['id'], 'lastUpdated' => is_null($row['lastUpdated']) ? new DateTimeImmutable($row['createdAt']->format('r')) : new DateTimeImmutable($row['lastUpdated']->format('r'))]; + yield ['id' => (int) $row['id'], 'lastUpdated' => null === $row['lastUpdated'] ? new \DateTimeImmutable($row['createdAt']->format('r')) : new \DateTimeImmutable($row['lastUpdated']->format('r'))]; } } @@ -333,7 +335,7 @@ public function getPartialPackageByNameWithVersions(string $name): Package $versions = []; $reflId = new \ReflectionProperty(Version::class, 'id'); foreach ($qb->getQuery()->getArrayResult() as $row) { - $versions[] = $v = new Version; + $versions[] = $v = new Version(); $reflId->setValue($v, $row['id']); $v->setName($pkg->getName()); $v->setPackage($pkg); @@ -365,8 +367,9 @@ public function getPackageByName(string $name): Package } /** - * @param list|null $ids + * @param list|null $ids * @param array $filters + * * @return Package[] */ public function getPackagesWithVersions(?array $ids = null, array $filters = []): array @@ -390,6 +393,7 @@ public function getPackagesWithVersions(?array $ids = null, array $filters = []) /** * @param int[] $ids + * * @return array */ public function getGitHubStars(array $ids): array @@ -488,6 +492,7 @@ public function getSuspectPackages(int $offset = 0, int $limit = 15): array /** * @param string $name Package name to find the dependents of * @param int|null $type One of Dependent::TYPE_* + * * @return int<0, max> */ public function getDependentCount(string $name, ?int $type = null): int @@ -503,9 +508,10 @@ 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 string $name Package name to find the dependents of + * @param int|null $type One of Dependent::TYPE_* * @param 'downloads'|'name' $orderBy + * * @return list */ public function getDependents(string $name, int $offset = 0, int $limit = 15, string $orderBy = 'name', ?int $type = null): array diff --git a/src/Entity/PhpStat.php b/src/Entity/PhpStat.php index 13838387e1..a24ea34ea5 100644 --- a/src/Entity/PhpStat.php +++ b/src/Entity/PhpStat.php @@ -14,7 +14,6 @@ use Composer\Pcre\Preg; use Doctrine\ORM\Mapping as ORM; -use DateTimeImmutable; #[ORM\Entity(repositoryClass: 'App\Entity\PhpStatRepository')] #[ORM\Table(name: 'php_stat')] @@ -71,7 +70,7 @@ class PhpStat public array $data; #[ORM\Column(type: 'datetime_immutable', name: 'last_updated')] - public DateTimeImmutable $lastUpdated; + public \DateTimeImmutable $lastUpdated; #[ORM\Id] #[ORM\ManyToOne(targetEntity: 'App\Entity\Package')] @@ -98,7 +97,7 @@ public function __construct(Package $package, int $type, string $version) } $this->data = []; - $this->lastUpdated = new DateTimeImmutable(); + $this->lastUpdated = new \DateTimeImmutable(); } /** @@ -148,12 +147,12 @@ public function getData(): array return $this->data; } - public function setLastUpdated(DateTimeImmutable $lastUpdated): void + public function setLastUpdated(\DateTimeImmutable $lastUpdated): void { $this->lastUpdated = $lastUpdated; } - public function getLastUpdated(): DateTimeImmutable + public function getLastUpdated(): \DateTimeImmutable { return $this->lastUpdated; } diff --git a/src/Entity/PhpStatRepository.php b/src/Entity/PhpStatRepository.php index ce74f8fa34..cb02d146fe 100644 --- a/src/Entity/PhpStatRepository.php +++ b/src/Entity/PhpStatRepository.php @@ -16,7 +16,6 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; use Predis\Client; -use DateTimeImmutable; /** * @extends ServiceEntityRepository @@ -118,7 +117,7 @@ public function deletePackageStats(Package $package): void /** * @param array $keys */ - public function transferStatsToDb(int $packageId, array $keys, DateTimeImmutable $now, DateTimeImmutable $updateDateForMajor): void + public function transferStatsToDb(int $packageId, array $keys, \DateTimeImmutable $now, \DateTimeImmutable $updateDateForMajor): void { $package = $this->getEntityManager()->getRepository(Package::class)->find($packageId); // package was deleted in the meantime, abort @@ -166,7 +165,7 @@ public function transferStatsToDb(int $packageId, array $keys, DateTimeImmutable /** * @param non-empty-array $keys array of keys => dl count */ - private function createDbRecordsForKeys(Package $package, array $keys, DateTimeImmutable $now): bool + private function createDbRecordsForKeys(Package $package, array $keys, \DateTimeImmutable $now): bool { reset($keys); $info = $this->getKeyInfo($package, key($keys)); @@ -183,9 +182,9 @@ private function createDbRecordsForKeys(Package $package, array $keys, DateTimeI /** * @param non-empty-array $keys array of keys => dl count - * @param PhpStat::TYPE_* $type + * @param PhpStat::TYPE_* $type */ - private function createOrUpdateRecord(Package $package, int $type, string $version, array $keys, DateTimeImmutable $now): ?PhpStat + private function createOrUpdateRecord(Package $package, int $type, string $version, array $keys, \DateTimeImmutable $now): ?PhpStat { $record = $this->getEntityManager()->getRepository(PhpStat::class)->findOneBy(['package' => $package, 'type' => $type, 'version' => $version]); $newRecord = !$record; @@ -225,7 +224,7 @@ private function createOrUpdateRecord(Package $package, int $type, string $versi /** * @param PhpStat::TYPE_* $type */ - public function createOrUpdateMainRecord(Package $package, int $type, DateTimeImmutable $now, DateTimeImmutable $updateDate): void + public function createOrUpdateMainRecord(Package $package, int $type, \DateTimeImmutable $now, \DateTimeImmutable $updateDate): void { $minorPhpVersions = $this->getEntityManager()->getConnection()->fetchFirstColumn( 'SELECT DISTINCT stats.php_minor AS php_minor @@ -234,7 +233,7 @@ public function createOrUpdateMainRecord(Package $package, int $type, DateTimeIm ['package' => $package->getId(), 'type' => $type, 'exact' => PhpStat::DEPTH_EXACT, 'major' => PhpStat::DEPTH_MAJOR] ); - $minorPhpVersions = array_filter($minorPhpVersions, static fn ($version) => is_string($version)); + $minorPhpVersions = array_filter($minorPhpVersions, static fn ($version) => \is_string($version)); if (!$minorPhpVersions) { return; } @@ -254,7 +253,7 @@ public function createOrUpdateMainRecord(Package $package, int $type, DateTimeIm 'SELECT '.implode(', ', $sumQueries).' FROM php_stat p WHERE p.package_id = :package AND p.type = :type AND p.depth IN (:exact, :major)', ['package' => $package->getId(), 'type' => $type, 'exact' => PhpStat::DEPTH_EXACT, 'major' => PhpStat::DEPTH_MAJOR] ); - assert(is_array($sums)); + \assert(\is_array($sums)); foreach ($minorPhpVersions as $index => $version) { if (is_numeric($sums[$index]) && $sums[$index] > 0) { diff --git a/src/Entity/SecurityAdvisory.php b/src/Entity/SecurityAdvisory.php index cc4e5b573f..bbe67cbfcb 100644 --- a/src/Entity/SecurityAdvisory.php +++ b/src/Entity/SecurityAdvisory.php @@ -15,13 +15,12 @@ use App\SecurityAdvisory\AdvisoryIdGenerator; use App\SecurityAdvisory\AdvisoryParser; use App\SecurityAdvisory\FriendsOfPhpSecurityAdvisoriesSource; +use App\SecurityAdvisory\RemoteSecurityAdvisory; use App\SecurityAdvisory\Severity; -use DateTimeImmutable; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Selectable; use Doctrine\ORM\Mapping as ORM; -use App\SecurityAdvisory\RemoteSecurityAdvisory; #[ORM\Entity(repositoryClass: 'App\Entity\SecurityAdvisoryRepository')] #[ORM\Table(name: 'security_advisory')] @@ -51,10 +50,10 @@ class SecurityAdvisory private string $title; #[ORM\Column(type: 'string', nullable: true)] - private string|null $link = null; + private ?string $link = null; #[ORM\Column(type: 'string', nullable: true)] - private string|null $cve = null; + private ?string $cve = null; #[ORM\Column(type: 'text')] private string $affectedVersions; @@ -63,16 +62,16 @@ class SecurityAdvisory private string $source; #[ORM\Column(type: 'datetime_immutable')] - private DateTimeImmutable $reportedAt; + private \DateTimeImmutable $reportedAt; #[ORM\Column(type: 'datetime_immutable')] - private DateTimeImmutable $updatedAt; + private \DateTimeImmutable $updatedAt; #[ORM\Column(type: 'string', nullable: true)] - private string|null $composerRepository = null; + private ?string $composerRepository = null; #[ORM\Column(nullable: true)] - private Severity|null $severity = null; + private ?Severity $severity = null; /** * @var Collection&Selectable @@ -87,7 +86,7 @@ public function __construct(RemoteSecurityAdvisory $advisory, string $source) $this->source = $source; $this->assignPackagistAdvisoryId(); - $this->updatedAt = new DateTimeImmutable(); + $this->updatedAt = new \DateTimeImmutable(); $this->copyAdvisory($advisory, true); $this->addSource($advisory->id, $source, $advisory->severity); @@ -97,27 +96,27 @@ public function updateAdvisory(RemoteSecurityAdvisory $advisory): void { $this->findSecurityAdvisorySource($advisory->source)?->update($advisory); - $now = new DateTimeImmutable(); + $now = new \DateTimeImmutable(); $allSeverities = $this->sources->map(static fn (SecurityAdvisorySource $source) => $source->getSeverity())->toArray(); - if ($advisory->severity && (!$this->severity || !in_array($this->severity, $allSeverities, true))) { + if ($advisory->severity && (!$this->severity || !\in_array($this->severity, $allSeverities, true))) { $this->updatedAt = $now; $this->severity = $advisory->severity; } - if (!in_array($advisory->source, [null, $this->source], true)) { + if (!\in_array($advisory->source, [null, $this->source], true)) { return; } if ( - $this->remoteId !== $advisory->id || - $this->packageName !== $advisory->packageName || - $this->title !== $advisory->title || - $this->link !== $advisory->link || - $this->cve !== $advisory->cve || - $this->affectedVersions !== $advisory->affectedVersions || - $this->reportedAt != $advisory->date || - $this->composerRepository !== $advisory->composerRepository || - ($this->severity !== $advisory->severity && $advisory->severity) + $this->remoteId !== $advisory->id + || $this->packageName !== $advisory->packageName + || $this->title !== $advisory->title + || $this->link !== $advisory->link + || $this->cve !== $advisory->cve + || $this->affectedVersions !== $advisory->affectedVersions + || $this->reportedAt != $advisory->date + || $this->composerRepository !== $advisory->composerRepository + || ($this->severity !== $advisory->severity && $advisory->severity) ) { $this->updatedAt = $now; } @@ -217,7 +216,7 @@ public function calculateDifferenceScore(RemoteSecurityAdvisory $advisory): int $score += $increase; } - if ($advisory->link !== $this->getLink() && !in_array($this->getLink(), $advisory->references, true)) { + if ($advisory->link !== $this->getLink() && !\in_array($this->getLink(), $advisory->references, true)) { $score++; } @@ -260,7 +259,7 @@ public function hasSources(): bool return !$this->sources->isEmpty(); } - public function addSource(string $remoteId, string $source, Severity|null $severity): void + public function addSource(string $remoteId, string $source, ?Severity $severity): void { if (null === $this->getSourceRemoteId($source)) { $this->sources->add(new SecurityAdvisorySource($this, $remoteId, $source, $severity)); diff --git a/src/Entity/SecurityAdvisoryRepository.php b/src/Entity/SecurityAdvisoryRepository.php index d823f0898f..b008caae38 100644 --- a/src/Entity/SecurityAdvisoryRepository.php +++ b/src/Entity/SecurityAdvisoryRepository.php @@ -32,11 +32,12 @@ public function __construct( /** * @param string[] $packageNames + * * @return SecurityAdvisory[] */ public function getPackageAdvisoriesWithSources(array $packageNames, string $sourceName): array { - if (count($packageNames) === 0) { + if (\count($packageNames) === 0) { return []; } @@ -51,7 +52,7 @@ public function getPackageAdvisoriesWithSources(array $packageNames, string $sou ->getQuery() ->getResult(); - if ($sourceName !== FriendsOfPhpSecurityAdvisoriesSource::SOURCE_NAME || count($advisories) > 0) { + if ($sourceName !== FriendsOfPhpSecurityAdvisoriesSource::SOURCE_NAME || \count($advisories) > 0) { return $advisories; } @@ -123,12 +124,13 @@ public function getPackageSecurityAdvisories(string $name): array /** * @param string[] $packageNames + * * @return array, reportedAt: string, composerRepository: string|null}>> An array of packageName => advisoryId => advisory-data */ public function searchSecurityAdvisories(array $packageNames, int $updatedSince): array { $packageNames = array_values(array_unique($packageNames)); - $filterByNames = count($packageNames) > 0; + $filterByNames = \count($packageNames) > 0; $useCache = $filterByNames; $advisories = []; @@ -142,21 +144,21 @@ public function searchSecurityAdvisories(array $packageNames, int $updatedSince) // cache as false means the name does not have any advisories if ($advisoryCache[$index] !== 'false') { - $advisories[$name] = json_decode($advisoryCache[$index], true, JSON_THROW_ON_ERROR); + $advisories[$name] = json_decode($advisoryCache[$index], true, \JSON_THROW_ON_ERROR); } } } // check if we still need to query SQL - $filterByNames = count($packageNames) > 0; + $filterByNames = \count($packageNames) > 0; } if (!$useCache || $filterByNames) { $sql = 'SELECT s.packagistAdvisoryId as advisoryId, s.packageName, s.remoteId, s.title, s.link, s.cve, s.affectedVersions, s.source, s.reportedAt, s.composerRepository, sa.source sourceSource, sa.remoteId sourceRemoteId, s.severity FROM security_advisory s INNER JOIN security_advisory_source sa ON sa.securityAdvisory_id=s.id - WHERE s.updatedAt >= :updatedSince '. - ($filterByNames ? ' AND s.packageName IN (:packageNames)' : '') + WHERE s.updatedAt >= :updatedSince ' + .($filterByNames ? ' AND s.packageName IN (:packageNames)' : '') .' ORDER BY '.($filterByNames ? 's.reportedAt DESC, ' : '').'s.id DESC'; $params = ['updatedSince' => date('Y-m-d H:i:s', $updatedSince)]; @@ -185,7 +187,7 @@ public function searchSecurityAdvisories(array $packageNames, int $updatedSince) $cacheData = []; foreach ($packageNames as $name) { // Cache for 7 days with a random 1-hour variance, the cache is busted by SecurityAdvisoryUpdateListener when advisories change - $this->redisCache->setex('sec-adv:'.$name, 604800 + random_int(0, 3600), isset($advisories[$name]) ? json_encode($advisories[$name], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : 'false'); + $this->redisCache->setex('sec-adv:'.$name, 604800 + random_int(0, 3600), isset($advisories[$name]) ? json_encode($advisories[$name], \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE) : 'false'); } } } @@ -195,11 +197,12 @@ public function searchSecurityAdvisories(array $packageNames, int $updatedSince) /** * @param string[] $packageNames + * * @return array> */ public function getAdvisoryIdsAndVersions(array $packageNames): array { - $filterByNames = count($packageNames) > 0; + $filterByNames = \count($packageNames) > 0; $sql = 'SELECT s.packagistAdvisoryId as advisoryId, s.packageName, s.affectedVersions FROM security_advisory s diff --git a/src/Entity/SecurityAdvisorySource.php b/src/Entity/SecurityAdvisorySource.php index 7bb4d29c66..4ddc347f2b 100644 --- a/src/Entity/SecurityAdvisorySource.php +++ b/src/Entity/SecurityAdvisorySource.php @@ -35,9 +35,9 @@ class SecurityAdvisorySource private string $source; #[ORM\Column(nullable: true)] - private Severity|null $severity; + private ?Severity $severity; - public function __construct(SecurityAdvisory $securityAdvisory, string $remoteId, string $source, Severity|null $severity) + public function __construct(SecurityAdvisory $securityAdvisory, string $remoteId, string $source, ?Severity $severity) { $this->securityAdvisory = $securityAdvisory; $this->remoteId = $remoteId; diff --git a/src/Entity/Tag.php b/src/Entity/Tag.php index 1b0d4ed5e0..eefa5ee274 100644 --- a/src/Entity/Tag.php +++ b/src/Entity/Tag.php @@ -49,7 +49,7 @@ public function __construct(string $name) /** * @throws \Doctrine\ORM\NoResultException */ - public static function getByName(EntityManager $em, string $name, bool $create = false): Tag + public static function getByName(EntityManager $em, string $name, bool $create = false): self { try { $qb = $em->createQueryBuilder(); @@ -89,7 +89,7 @@ public function getName(): string public function isDev(): bool { // see Composer\Command\RequireCommand - return in_array(strtolower($this->name), ['dev', 'testing', 'static analysis'], true); + return \in_array(strtolower($this->name), ['dev', 'testing', 'static analysis'], true); } public function addVersions(Version $versions): void diff --git a/src/Entity/User.php b/src/Entity/User.php index d6cdd133ea..9201ac036a 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -13,7 +13,6 @@ namespace App\Entity; use App\Validator\NotReservedWord; -use Deprecated; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Selectable; @@ -23,12 +22,11 @@ use Scheb\TwoFactorBundle\Model\Totp\TotpConfigurationInterface; use Scheb\TwoFactorBundle\Model\Totp\TwoFactorInterface; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Security\Core\User\EquatableInterface; use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; -use Symfony\Component\Validator\Constraints as Assert; -use Symfony\Component\Security\Core\User\EquatableInterface; use Symfony\Component\Security\Core\User\UserInterface; -use DateTimeImmutable; +use Symfony\Component\Validator\Constraints as Assert; #[ORM\Entity(repositoryClass: 'App\Entity\UserRepository')] #[ORM\Table(name: 'fos_user')] @@ -79,19 +77,19 @@ class User implements UserInterface, TwoFactorInterface, BackupCodeInterface, Eq * The salt to use for hashing. */ #[ORM\Column(type: 'string', nullable: true)] - private string|null $salt = null; + private ?string $salt = null; #[ORM\Column(type: 'datetime_immutable', name: 'last_login', nullable: true)] - private DateTimeImmutable|null $lastLogin = null; + private ?\DateTimeImmutable $lastLogin = null; /** * Random string sent to the user email address in order to verify it. */ #[ORM\Column(type: 'string', name: 'confirmation_token', length: 180, nullable: true, unique: true)] - private string|null $confirmationToken = null; + private ?string $confirmationToken = null; #[ORM\Column(type: 'datetime_immutable', name: 'password_requested_at', nullable: true)] - private DateTimeImmutable|null $passwordRequestedAt = null; + private ?\DateTimeImmutable $passwordRequestedAt = null; /** * @var Collection&Selectable @@ -100,7 +98,7 @@ class User implements UserInterface, TwoFactorInterface, BackupCodeInterface, Eq private Collection $packages; #[ORM\Column(type: 'datetime_immutable')] - private DateTimeImmutable $createdAt; + private \DateTimeImmutable $createdAt; #[ORM\Column(type: 'string', length: 40)] private string $apiToken; @@ -109,22 +107,22 @@ class User implements UserInterface, TwoFactorInterface, BackupCodeInterface, Eq private string $safeApiToken; #[ORM\Column(type: 'string', length: 255, nullable: true)] - private string|null $githubId = null; + private ?string $githubId = null; #[ORM\Column(type: 'string', length: 255, nullable: true)] - private string|null $githubToken = null; + private ?string $githubToken = null; #[ORM\Column(type: 'string', length: 255, nullable: true)] - private string|null $githubScope = null; + private ?string $githubScope = null; #[ORM\Column(type: 'boolean', options: ['default' => true])] private bool $failureNotifications = true; #[ORM\Column(name: 'totpSecret', type: 'string', nullable: true)] - private string|null $totpSecret = null; + private ?string $totpSecret = null; #[ORM\Column(type: 'string', length: 8, nullable: true)] - private string|null $backupCode = null; + private ?string $backupCode = null; #[ORM\Column(type: 'smallint', options: ['unsigned' => true, 'default' => 0])] private int $sessionBuster = 0; @@ -132,7 +130,7 @@ class User implements UserInterface, TwoFactorInterface, BackupCodeInterface, Eq public function __construct() { $this->packages = new ArrayCollection(); - $this->createdAt = new DateTimeImmutable(); + $this->createdAt = new \DateTimeImmutable(); $this->initializeApiToken(); $this->initializeSafeApiToken(); } @@ -166,7 +164,7 @@ public function getPackages(): Collection return $this->packages; } - public function getCreatedAt(): DateTimeImmutable + public function getCreatedAt(): \DateTimeImmutable { return $this->createdAt; } @@ -191,12 +189,12 @@ public function getSafeApiToken(): string return $this->safeApiToken; } - public function getGithubId(): string|null + public function getGithubId(): ?string { return $this->githubId; } - public function getGithubUsername(): string|null + public function getGithubUsername(): ?string { if ($this->githubId) { if (!$this->githubToken) { @@ -215,27 +213,27 @@ public function getGithubUsername(): string|null return null; } - public function setGithubId(string|null $githubId): void + public function setGithubId(?string $githubId): void { $this->githubId = $githubId; } - public function getGithubToken(): string|null + public function getGithubToken(): ?string { return $this->githubToken; } - public function setGithubToken(string|null $githubToken): void + public function setGithubToken(?string $githubToken): void { $this->githubToken = $githubToken; } - public function getGithubScope(): string|null + public function getGithubScope(): ?string { return $this->githubScope; } - public function setGithubScope(string|null $githubScope): void + public function setGithubScope(?string $githubScope): void { $this->githubScope = $githubScope; } @@ -260,7 +258,7 @@ public function getGravatarUrl(): string return 'https://www.gravatar.com/avatar/'.hash('md5', strtolower($this->getEmail())).'?d=identicon'; } - public function setTotpSecret(string|null $secret): void + public function setTotpSecret(?string $secret): void { $this->totpSecret = $secret; $this->invalidateAllSessions(); @@ -310,7 +308,7 @@ public function addRole(string $role): void return; } - if (!in_array($role, $this->roles, true)) { + if (!\in_array($role, $this->roles, true)) { $this->roles[] = $role; } } @@ -346,14 +344,14 @@ public function __unserialize(array $data): void $this->enabled, $this->id, $this->email, - $this->emailCanonical + $this->emailCanonical, ] = $data; // session_buster might not be available yet in the session $this->sessionBuster = $data['session_buster'] ?? 0; } - #[Deprecated] + #[\Deprecated] public function eraseCredentials(): void { } @@ -382,7 +380,7 @@ public function getUsernameCanonical(): string return $this->usernameCanonical; } - public function getSalt(): string|null + public function getSalt(): ?string { return $this->salt; } @@ -397,12 +395,12 @@ public function getEmailCanonical(): string return $this->emailCanonical; } - public function getPassword(): string|null + public function getPassword(): ?string { return $this->password; } - public function getLastLogin(): DateTimeImmutable|null + public function getLastLogin(): ?\DateTimeImmutable { return $this->lastLogin; } @@ -422,7 +420,7 @@ public function getRoles(): array public function hasRole(string $role): bool { - return in_array(strtoupper($role), $this->getRoles(), true); + return \in_array(strtoupper($role), $this->getRoles(), true); } public function isEnabled(): bool @@ -449,7 +447,7 @@ public function setUsernameCanonical(string $usernameCanonical): void $this->usernameCanonical = mb_strtolower($usernameCanonical); } - public function setSalt(string|null $salt): void + public function setSalt(?string $salt): void { $this->salt = $salt; } @@ -475,12 +473,12 @@ public function setPassword(string $password): void $this->password = $password; } - public function setLastLogin(DateTimeImmutable|null $time = null): void + public function setLastLogin(?\DateTimeImmutable $time = null): void { $this->lastLogin = $time; } - public function setPasswordRequestedAt(DateTimeImmutable|null $date = null): void + public function setPasswordRequestedAt(?\DateTimeImmutable $date = null): void { $this->passwordRequestedAt = $date; } @@ -494,7 +492,7 @@ public function resetPasswordRequest(): void /** * Gets the timestamp that the user requested a password reset. */ - public function getPasswordRequestedAt(): DateTimeImmutable|null + public function getPasswordRequestedAt(): ?\DateTimeImmutable { return $this->passwordRequestedAt; } @@ -513,7 +511,7 @@ public function setRoles(array $roles): void public function isEqualTo(UserInterface $user): bool { - if (!$user instanceof User) { + if (!$user instanceof self) { return false; } @@ -550,7 +548,7 @@ public function initializeSafeApiToken(): void $this->safeApiToken = bin2hex(random_bytes(20)); } - public function getConfirmationToken(): string|null + public function getConfirmationToken(): ?string { return $this->confirmationToken; } @@ -567,7 +565,7 @@ public function clearConfirmationToken(): void public function isPasswordRequestExpired(int $ttl): bool { - return !$this->getPasswordRequestedAt() instanceof DateTimeImmutable || $this->getPasswordRequestedAt()->getTimestamp() + $ttl <= time(); + return !$this->getPasswordRequestedAt() instanceof \DateTimeImmutable || $this->getPasswordRequestedAt()->getTimestamp() + $ttl <= time(); } public function getSessionBuster(): int diff --git a/src/Entity/UserRepository.php b/src/Entity/UserRepository.php index e3ad74dfeb..6b16df6ca5 100644 --- a/src/Entity/UserRepository.php +++ b/src/Entity/UserRepository.php @@ -19,6 +19,7 @@ /** * @author Jordi Boggiano + * * @extends ServiceEntityRepository */ class UserRepository extends ServiceEntityRepository diff --git a/src/Entity/VendorRepository.php b/src/Entity/VendorRepository.php index 0ef6bdb4c3..ea7f1e68ba 100644 --- a/src/Entity/VendorRepository.php +++ b/src/Entity/VendorRepository.php @@ -17,6 +17,7 @@ /** * @author Jordi Boggiano + * * @extends ServiceEntityRepository */ class VendorRepository extends ServiceEntityRepository diff --git a/src/Entity/Version.php b/src/Entity/Version.php index ebc0d640a9..7f40f4ad2b 100644 --- a/src/Entity/Version.php +++ b/src/Entity/Version.php @@ -19,10 +19,10 @@ use Doctrine\Common\Collections\Selectable; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; -use DateTimeImmutable; /** * @author Jordi Boggiano + * * @phpstan-type VersionArray array{ * name: string, * description: string, @@ -71,13 +71,13 @@ class Version private string $name; #[ORM\Column(type: 'text', nullable: true)] - private string|null $description = null; + private ?string $description = null; #[ORM\Column(nullable: true)] - private string|null $type = null; + private ?string $type = null; #[ORM\Column(nullable: true)] - private string|null $targetDir = null; + private ?string $targetDir = null; /** * @var array @@ -96,11 +96,11 @@ class Version #[ORM\ManyToOne(targetEntity: Package::class, inversedBy: 'versions')] #[Assert\Type(type: Package::class)] - private Package|null $package; + private ?Package $package; #[ORM\Column(nullable: true)] #[Assert\Url] - private string|null $homepage = null; + private ?string $homepage = null; #[ORM\Column] #[Assert\NotBlank] @@ -160,13 +160,13 @@ class Version * @var array{type: string|null, url: string|null, reference: string|null}|null */ #[ORM\Column(type: 'json', nullable: true)] - private array|null $source = null; + private ?array $source = null; /** * @var array{type: string|null, url: string|null, reference: string|null, shasum: string|null}|null */ #[ORM\Column(type: 'json', nullable: true)] - private array|null $dist = null; + private ?array $dist = null; /** * @var array{psr-0?: array, psr-4?: array, classmap?: list, files?: list} @@ -178,25 +178,25 @@ class Version * @var array|null */ #[ORM\Column(type: 'json', nullable: true)] - private array|null $binaries = null; + private ?array $binaries = null; /** * @var array */ #[ORM\Column(type: 'json', nullable: true)] - private array|null $includePaths = null; + private ?array $includePaths = null; /** * @var array{issues?: string, forum?: string, wiki?: string, source?: string, email?: string, irc?: string, docs?: string, rss?: string, chat?: string, security?: string}|null */ #[ORM\Column(type: 'json', nullable: true)] - private array|null $support = null; + private ?array $support = null; /** * @var array|null */ #[ORM\Column(type: 'json', nullable: true)] - private array|null $funding = null; + private ?array $funding = null; /** * @var array @@ -208,22 +208,22 @@ class Version * @var array{priority?: int, configure-options?: list}|null */ #[ORM\Column(type: 'json', options: ['default' => null], nullable: true)] - private array|null $phpExt = null; + private ?array $phpExt = null; #[ORM\Column(name: 'defaultBranch', type: 'boolean', options: ['default' => false])] private bool $isDefaultBranch = false; #[ORM\Column(type: 'datetime_immutable')] - private DateTimeImmutable $createdAt; + private \DateTimeImmutable $createdAt; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $softDeletedAt = null; + private ?\DateTimeImmutable $softDeletedAt = null; #[ORM\Column(type: 'datetime_immutable')] - private DateTimeImmutable $updatedAt; + private \DateTimeImmutable $updatedAt; #[ORM\Column(type: 'datetime_immutable', nullable: true)] - private DateTimeImmutable|null $releasedAt = null; + private ?\DateTimeImmutable $releasedAt = null; public function __construct() { @@ -234,12 +234,13 @@ public function __construct() $this->provide = new ArrayCollection(); $this->devRequire = new ArrayCollection(); $this->suggest = new ArrayCollection(); - $this->createdAt = new DateTimeImmutable; - $this->updatedAt = new DateTimeImmutable; + $this->createdAt = new \DateTimeImmutable(); + $this->updatedAt = new \DateTimeImmutable(); } /** * @param VersionData $versionData + * * @return VersionArray */ public function toArray(array $versionData, bool $serializeForApi = false): array @@ -339,6 +340,7 @@ public function toArray(array $versionData, bool $serializeForApi = false): arra /** * @param VersionData $versionData + * * @return VersionArray */ public function toV2Array(array $versionData): array @@ -348,14 +350,14 @@ public function toV2Array(array $versionData): array if (isset($array['support'])) { ksort($array['support']); } - if (isset($array['php-ext']['configure-options']) && is_array($array['php-ext']['configure-options'])) { + if (isset($array['php-ext']['configure-options']) && \is_array($array['php-ext']['configure-options'])) { usort($array['php-ext']['configure-options'], static fn ($a, $b) => ($a['name'] ?? '') <=> ($b['name'] ?? '')); } return $array; } - public function equals(Version $version): bool + public function equals(self $version): bool { return strtolower($version->getName()) === strtolower($this->getName()) && strtolower($version->getNormalizedVersion()) === strtolower($this->getNormalizedVersion()); @@ -378,6 +380,7 @@ public function getName(): string /** * @param VersionData|null $versionData + * * @return list */ public function getNames(?array $versionData = null): array @@ -407,22 +410,22 @@ public function getNames(?array $versionData = null): array return array_keys($names); } - public function setDescription(string|null $description): void + public function setDescription(?string $description): void { $this->description = $description; } - public function getDescription(): string|null + public function getDescription(): ?string { return $this->description; } - public function setHomepage(string|null $homepage): void + public function setHomepage(?string $homepage): void { $this->homepage = $homepage; } - public function getHomepage(): string|null + public function getHomepage(): ?string { return $this->homepage; } @@ -471,7 +474,7 @@ public function getLicense(): array /** * @param PackageSource $source */ - public function setSource(array|null $source): void + public function setSource(?array $source): void { $this->source = $source; } @@ -479,7 +482,7 @@ public function setSource(array|null $source): void /** * @return PackageSource */ - public function getSource(): array|null + public function getSource(): ?array { return $this->source; } @@ -487,7 +490,7 @@ public function getSource(): array|null /** * @param PackageDist $dist */ - public function setDist(array|null $dist): void + public function setDist(?array $dist): void { $this->dist = $dist; } @@ -495,7 +498,7 @@ public function setDist(array|null $dist): void /** * @return PackageDist */ - public function getDist(): array|null + public function getDist(): ?array { return $this->dist; } @@ -519,7 +522,7 @@ public function getAutoload(): array /** * @param array|null $binaries */ - public function setBinaries(array|null $binaries): void + public function setBinaries(?array $binaries): void { $this->binaries = $binaries; } @@ -527,7 +530,7 @@ public function setBinaries(array|null $binaries): void /** * @return array|null */ - public function getBinaries(): array|null + public function getBinaries(): ?array { return $this->binaries; } @@ -535,7 +538,7 @@ public function getBinaries(): array|null /** * @param array|null $paths */ - public function setIncludePaths(array|null $paths): void + public function setIncludePaths(?array $paths): void { $this->includePaths = $paths; } @@ -543,7 +546,7 @@ public function setIncludePaths(array|null $paths): void /** * @return array|null */ - public function getIncludePaths(): array|null + public function getIncludePaths(): ?array { return $this->includePaths; } @@ -551,7 +554,7 @@ public function getIncludePaths(): array|null /** * @param array{issues?: string, forum?: string, wiki?: string, source?: string, email?: string, irc?: string, docs?: string, rss?: string, chat?: string, security?: string}|null $support */ - public function setSupport(array|null $support): void + public function setSupport(?array $support): void { $this->support = $support; } @@ -559,7 +562,7 @@ public function setSupport(array|null $support): void /** * @return array{issues?: string, forum?: string, wiki?: string, source?: string, email?: string, irc?: string, docs?: string, rss?: string, chat?: string, security?: string}|null */ - public function getSupport(): array|null + public function getSupport(): ?array { return $this->support; } @@ -567,7 +570,7 @@ public function getSupport(): array|null /** * @param array|null $funding */ - public function setFunding(array|null $funding): void + public function setFunding(?array $funding): void { $this->funding = $funding; } @@ -582,6 +585,7 @@ public function getFunding(): ?array /** * Get funding, sorted to help the V2 metadata compression algo + * * @return array|null */ public function getFundingSorted(): ?array @@ -592,8 +596,8 @@ public function getFundingSorted(): ?array $funding = $this->funding; usort($funding, static function ($a, $b) { - $keyA = ($a['type'] ?? '') . ($a['url'] ?? ''); - $keyB = ($b['type'] ?? '') . ($b['url'] ?? ''); + $keyA = ($a['type'] ?? '').($a['url'] ?? ''); + $keyB = ($b['type'] ?? '').($b['url'] ?? ''); return $keyA <=> $keyB; }); @@ -601,22 +605,22 @@ public function getFundingSorted(): ?array return $funding; } - public function setCreatedAt(DateTimeImmutable $createdAt): void + public function setCreatedAt(\DateTimeImmutable $createdAt): void { $this->createdAt = $createdAt; } - public function getCreatedAt(): DateTimeImmutable + public function getCreatedAt(): \DateTimeImmutable { return $this->createdAt; } - public function setReleasedAt(DateTimeImmutable|null $releasedAt): void + public function setReleasedAt(?\DateTimeImmutable $releasedAt): void { $this->releasedAt = $releasedAt; } - public function getReleasedAt(): DateTimeImmutable|null + public function getReleasedAt(): ?\DateTimeImmutable { return $this->releasedAt; } @@ -628,7 +632,7 @@ public function setPackage(Package $package): void public function getPackage(): Package { - assert($this->package instanceof Package); + \assert($this->package instanceof Package); return $this->package; } @@ -654,22 +658,22 @@ public function hasDevTag(): bool return false; } - public function setUpdatedAt(DateTimeImmutable $updatedAt): void + public function setUpdatedAt(\DateTimeImmutable $updatedAt): void { $this->updatedAt = $updatedAt; } - public function getUpdatedAt(): DateTimeImmutable + public function getUpdatedAt(): \DateTimeImmutable { return $this->updatedAt; } - public function setSoftDeletedAt(DateTimeImmutable|null $softDeletedAt): void + public function setSoftDeletedAt(?\DateTimeImmutable $softDeletedAt): void { $this->softDeletedAt = $softDeletedAt; } - public function getSoftDeletedAt(): DateTimeImmutable|null + public function getSoftDeletedAt(): ?\DateTimeImmutable { return $this->softDeletedAt; } @@ -693,7 +697,7 @@ public function setAuthors(array $authors): void /** * @return array{priority?: int, configure-options?: list}|null */ - public function getPhpExt(): array|null + public function getPhpExt(): ?array { return $this->phpExt; } @@ -701,7 +705,7 @@ public function getPhpExt(): array|null /** * @param array{priority?: int, configure-options?: list}|null $phpExt */ - public function setPhpExt(array|null $phpExt): void + public function setPhpExt(?array $phpExt): void { $this->phpExt = $phpExt; } @@ -716,22 +720,22 @@ public function setIsDefaultBranch(bool $isDefaultBranch): void $this->isDefaultBranch = $isDefaultBranch; } - public function setType(string|null $type): void + public function setType(?string $type): void { $this->type = $type; } - public function getType(): string|null + public function getType(): ?string { return $this->type; } - public function setTargetDir(string|null $targetDir): void + public function setTargetDir(?string $targetDir): void { $this->targetDir = $targetDir; } - public function getTargetDir(): string|null + public function getTargetDir(): ?string { return $this->targetDir; } @@ -872,7 +876,7 @@ public function getVersionAlias(): string $extra = $this->getExtra(); if (isset($extra['branch-alias'][$this->getVersion()])) { - $parser = new VersionParser; + $parser = new VersionParser(); $version = $parser->normalizeBranch(str_replace('-dev', '', $extra['branch-alias'][$this->getVersion()])); return Preg::replace('{(\.9{7})+}', '.x', $version); diff --git a/src/Entity/VersionRepository.php b/src/Entity/VersionRepository.php index eaa3fcf75e..df6be5e9d0 100644 --- a/src/Entity/VersionRepository.php +++ b/src/Entity/VersionRepository.php @@ -13,17 +13,19 @@ namespace App\Entity; use App\Model\VersionIdCache; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; -use Predis\Client; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; +use Predis\Client; /** * @author Jordi Boggiano + * * @extends ServiceEntityRepository + * * @phpstan-import-type VersionArray from Version */ class VersionRepository extends ServiceEntityRepository @@ -68,6 +70,7 @@ public function remove(Version $version): void /** * @param Version[] $versions + * * @return Version[] */ public function refreshVersions(array $versions): array @@ -92,8 +95,9 @@ public function refreshVersions(array $versions): array } /** - * @param Version[] $versions + * @param Version[] $versions * @param VersionData $versionData + * * @return array */ public function detachToArray(array $versions, array $versionData, bool $serializeForApi = false): array @@ -109,6 +113,7 @@ public function detachToArray(array $versions, array $versionData, bool $seriali /** * @param int[] $versionIds + * * @return VersionData */ public function getVersionData(array $versionIds): array @@ -198,7 +203,7 @@ public function getFullVersion(int $versionId): Version /** * Returns the latest versions released * - * @param string $vendor optional vendor filter + * @param string $vendor optional vendor filter * @param string $package optional vendor/package filter */ public function getQueryBuilderForLatestVersionWithPackage(?string $vendor = null, ?string $package = null): QueryBuilder @@ -233,7 +238,7 @@ public function getQueryBuilderForLatestVersionWithPackage(?string $vendor = nul public function getLatestReleases(int $count = 10): array { if ($cached = $this->redisCache->get('new_releases')) { - return json_decode($cached, true, flags: JSON_THROW_ON_ERROR); + return json_decode($cached, true, flags: \JSON_THROW_ON_ERROR); } $qb = $this->getEntityManager()->createQueryBuilder(); @@ -246,7 +251,7 @@ public function getLatestReleases(int $count = 10): array ->setParameter('now', date('Y-m-d H:i:s')); $res = $qb->getQuery()->getResult(); - $this->redisCache->setex('new_releases', 600, json_encode($res, JSON_THROW_ON_ERROR)); + $this->redisCache->setex('new_releases', 600, json_encode($res, \JSON_THROW_ON_ERROR)); return $res; } diff --git a/src/EventListener/LogoutListener.php b/src/EventListener/LogoutListener.php index f5142981cc..1cb93d0bfc 100644 --- a/src/EventListener/LogoutListener.php +++ b/src/EventListener/LogoutListener.php @@ -13,10 +13,10 @@ namespace App\EventListener; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\Security\Core\Exception\LogoutException; -use Symfony\Component\HttpFoundation\RedirectResponse; class LogoutListener { diff --git a/src/EventListener/OriginListener.php b/src/EventListener/OriginListener.php index a6f39adfa1..5a7c89f1a6 100644 --- a/src/EventListener/OriginListener.php +++ b/src/EventListener/OriginListener.php @@ -51,12 +51,12 @@ public function onRequest(RequestEvent $event): void } // valid origin - if ($event->getRequest()->headers->get('Origin') === 'https://' . $this->packagistHost) { + if ($event->getRequest()->headers->get('Origin') === 'https://'.$this->packagistHost) { return; } // valid as well with HTTP in dev - if ('dev' === $this->environment && $event->getRequest()->headers->get('Origin') === 'http://' . $this->packagistHost) { + if ('dev' === $this->environment && $event->getRequest()->headers->get('Origin') === 'http://'.$this->packagistHost) { return; } diff --git a/src/EventListener/PackageListener.php b/src/EventListener/PackageListener.php index 24a268e79e..174e5d7918 100644 --- a/src/EventListener/PackageListener.php +++ b/src/EventListener/PackageListener.php @@ -18,8 +18,8 @@ use App\Util\DoctrineTrait; use Doctrine\Bundle\DoctrineBundle\Attribute\AsEntityListener; use Doctrine\ORM\EntityManager; -use Doctrine\Persistence\Event\LifecycleEventArgs; use Doctrine\ORM\Event\PreUpdateEventArgs; +use Doctrine\Persistence\Event\LifecycleEventArgs; use Doctrine\Persistence\ManagerRegistry; use Symfony\Bundle\SecurityBundle\Security; @@ -80,7 +80,7 @@ public function postUpdate(Package $package, LifecycleEventArgs $event): void } } - private function getUser(): User|null + private function getUser(): ?User { $user = $this->security->getUser(); diff --git a/src/EventListener/RequestStatsListener.php b/src/EventListener/RequestStatsListener.php index 0e07ed0355..7f05a9a6a4 100644 --- a/src/EventListener/RequestStatsListener.php +++ b/src/EventListener/RequestStatsListener.php @@ -23,7 +23,7 @@ class RequestStatsListener { - private float|null $pageTiming = null; + private ?float $pageTiming = null; public function __construct( private Client $statsd, diff --git a/src/EventListener/SecurityAdvisoryUpdateListener.php b/src/EventListener/SecurityAdvisoryUpdateListener.php index 600fc62c41..3cd94c9a13 100644 --- a/src/EventListener/SecurityAdvisoryUpdateListener.php +++ b/src/EventListener/SecurityAdvisoryUpdateListener.php @@ -73,7 +73,7 @@ public function flushChangesToPackages(): void $this->packagesToMarkStale = []; $redisKeys = array_map(static fn ($pkg) => 'sec-adv:'.$pkg, $packageNames); - while (count($redisKeys) > 0) { + while (\count($redisKeys) > 0) { $keys = array_splice($redisKeys, 0, 1000); $this->redisCache->del($keys); } diff --git a/src/EventListener/VersionListener.php b/src/EventListener/VersionListener.php index cc3f05141f..527e96ca1c 100644 --- a/src/EventListener/VersionListener.php +++ b/src/EventListener/VersionListener.php @@ -77,7 +77,7 @@ public function postUpdate(Version $version, LifecycleEventArgs $event): void } } - private function getUser(): User|null + private function getUser(): ?User { $user = $this->security->getUser(); diff --git a/src/Form/EventSubscriber/FormBruteForceSubscriber.php b/src/Form/EventSubscriber/FormBruteForceSubscriber.php index 4dca141fbe..386405f02a 100644 --- a/src/Form/EventSubscriber/FormBruteForceSubscriber.php +++ b/src/Form/EventSubscriber/FormBruteForceSubscriber.php @@ -31,12 +31,12 @@ public function onPostSubmit(FormEvent $event): void if ($form->isRoot() && $form instanceof Form) { foreach ($form->getErrors(true) as $error) { - $recaptchaMessage = (new Recaptcha2)->message; + $recaptchaMessage = new Recaptcha2()->message; $cause = $error->getCause(); if ( $cause instanceof ConstraintViolation && ( - $cause->getCode() === RateLimitingRecaptcha::INVALID_RECAPTCHA_ERROR || - $error->getMessage() === $recaptchaMessage + $cause->getCode() === RateLimitingRecaptcha::INVALID_RECAPTCHA_ERROR + || $error->getMessage() === $recaptchaMessage )) { $form->clearErrors(true); $error->getOrigin()?->addError($error); diff --git a/src/Form/Type/AbandonedType.php b/src/Form/Type/AbandonedType.php index 369347768a..2059b5ebf3 100644 --- a/src/Form/Type/AbandonedType.php +++ b/src/Form/Type/AbandonedType.php @@ -38,9 +38,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ); } - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'package'; diff --git a/src/Form/Type/AddMaintainerRequestType.php b/src/Form/Type/AddMaintainerRequestType.php index 53c9c8cf83..9e874e3c2c 100644 --- a/src/Form/Type/AddMaintainerRequestType.php +++ b/src/Form/Type/AddMaintainerRequestType.php @@ -34,9 +34,6 @@ public function configureOptions(OptionsResolver $resolver): void ]); } - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'add_maintainer_form'; diff --git a/src/Form/Type/PackageType.php b/src/Form/Type/PackageType.php index 429d275ab7..031d59c9ef 100644 --- a/src/Form/Type/PackageType.php +++ b/src/Form/Type/PackageType.php @@ -41,9 +41,6 @@ public function configureOptions(OptionsResolver $resolver): void ]); } - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'package'; diff --git a/src/Form/Type/ProfileFormType.php b/src/Form/Type/ProfileFormType.php index af7a02d292..0958e05f56 100644 --- a/src/Form/Type/ProfileFormType.php +++ b/src/Form/Type/ProfileFormType.php @@ -16,14 +16,14 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\EmailType; +use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Validator\Constraints\UserPassword; use Symfony\Component\Validator\Constraints\NotBlank; -use Symfony\Component\Form\Extension\Core\Type\PasswordType; /** * @extends AbstractType @@ -70,9 +70,6 @@ public function configureOptions(OptionsResolver $resolver): void ]); } - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'packagist_user_profile'; diff --git a/src/HealthCheck/MetadataDirCheck.php b/src/HealthCheck/MetadataDirCheck.php index 8b62560e20..dbcc4fa4a6 100644 --- a/src/HealthCheck/MetadataDirCheck.php +++ b/src/HealthCheck/MetadataDirCheck.php @@ -1,4 +1,4 @@ -awsMetadata['primary']) { - $packagesJson = __DIR__ . '/../../web/packages.json'; + $packagesJson = __DIR__.'/../../web/packages.json'; if (!file_exists($packagesJson)) { return new Failure($packagesJson.' not found on primary server'); @@ -47,7 +47,7 @@ public function check(): ResultInterface return new Success('Primary server metadata has been dumped'); } - $packagesJson = __DIR__ . '/../../web/packages.json'; + $packagesJson = __DIR__.'/../../web/packages.json'; if (!file_exists($packagesJson)) { return new Failure($packagesJson.' not found'); } @@ -60,8 +60,8 @@ public function check(): ResultInterface if (substr($fileContent, 0, 1) !== '{') { return new Failure($packagesJson.' does not look like it has json in it'); } - $metaDir = __DIR__ . '/../../web/p'; - $metaV2Dir = __DIR__ . '/../../web/p2'; + $metaDir = __DIR__.'/../../web/p'; + $metaV2Dir = __DIR__.'/../../web/p2'; if (!is_dir($metaDir)) { return new Failure($metaDir.' not found'); } diff --git a/src/HealthCheck/RedisHealthCheck.php b/src/HealthCheck/RedisHealthCheck.php index 90d99fed39..26e97feadb 100644 --- a/src/HealthCheck/RedisHealthCheck.php +++ b/src/HealthCheck/RedisHealthCheck.php @@ -1,4 +1,4 @@ - ['safe_label' => true, 'translation_domain' => false], ]); $menu->addChild($this->translator->trans('menu.logout'), [ - 'label' => '' . $this->translator->trans('menu.logout'), + 'label' => ''.$this->translator->trans('menu.logout'), 'uri' => $this->logoutUrlGenerator->getLogoutPath(), 'extras' => ['safe_label' => true, 'translation_domain' => false], ]); @@ -63,34 +63,34 @@ public function createProfileMenu(): ItemInterface private function addProfileMenu(ItemInterface $menu): void { $menu->addChild($this->translator->trans('menu.profile'), [ - 'label' => '' . $this->translator->trans('menu.profile'), + 'label' => ''.$this->translator->trans('menu.profile'), 'route' => 'my_profile', 'extras' => ['safe_label' => true, 'translation_domain' => false], ]); $menu->addChild($this->translator->trans('menu.settings'), [ - 'label' => '' . $this->translator->trans('menu.settings'), + 'label' => ''.$this->translator->trans('menu.settings'), 'route' => 'edit_profile', 'extras' => ['safe_label' => true, 'translation_domain' => false], ]); $menu->addChild($this->translator->trans('menu.change_password'), [ - 'label' => '' . $this->translator->trans('menu.change_password'), + 'label' => ''.$this->translator->trans('menu.change_password'), 'route' => 'change_password', 'extras' => ['safe_label' => true, 'translation_domain' => false], ]); $menu->addChild($this->translator->trans('menu.configure_2fa'), [ - 'label' => '' . $this->translator->trans('menu.configure_2fa'), + 'label' => ''.$this->translator->trans('menu.configure_2fa'), 'route' => 'user_2fa_configure', 'routeParameters' => ['name' => $this->username], 'extras' => ['safe_label' => true, 'translation_domain' => false], ]); $menu->addChild($this->translator->trans('menu.my_packages'), [ - 'label' => '' . $this->translator->trans('menu.my_packages'), + 'label' => ''.$this->translator->trans('menu.my_packages'), 'route' => 'user_packages', 'routeParameters' => ['name' => $this->username], 'extras' => ['safe_label' => true, 'translation_domain' => false], ]); $menu->addChild($this->translator->trans('menu.my_favorites'), [ - 'label' => '' . $this->translator->trans('menu.my_favorites'), + 'label' => ''.$this->translator->trans('menu.my_favorites'), 'route' => 'user_favorites', 'routeParameters' => ['name' => $this->username], 'extras' => ['safe_label' => true, 'translation_domain' => false], diff --git a/src/Model/DownloadManager.php b/src/Model/DownloadManager.php index 8da29c409e..0c30be33a2 100644 --- a/src/Model/DownloadManager.php +++ b/src/Model/DownloadManager.php @@ -12,15 +12,14 @@ namespace App\Model; -use Composer\Pcre\Preg; -use Doctrine\DBAL\ArrayParameterType; -use Doctrine\Persistence\ManagerRegistry; +use App\Entity\Download; use App\Entity\Package; use App\Entity\Version; -use App\Entity\Download; use App\Util\DoctrineTrait; +use Composer\Pcre\Preg; +use Doctrine\DBAL\ArrayParameterType; +use Doctrine\Persistence\ManagerRegistry; use Predis\Client; -use DateTimeImmutable; /** * Manages the download counts for packages. @@ -109,13 +108,14 @@ public function getTotalDownloads(Package|int $package): int $package = $package->getId(); } - return (int) $this->redis->get('dl:' . $package) ?: 0; + return (int) $this->redis->get('dl:'.$package) ?: 0; } /** * Gets total download counts for multiple package IDs. * * @param array $packageIds + * * @return array a map of package ID to download count */ public function getPackagesDownloads(array $packageIds): array @@ -184,14 +184,14 @@ public function addDownloads(array $jobs, string $ip, string $phpMinor, string $ $args[] = $month; $args[] = $throttleExpiry; - /** @phpstan-ignore-next-line method.notFound */ + /* @phpstan-ignore-next-line method.notFound */ $this->redis->downloadsIncr(...$args); } /** * @param string[] $keys */ - public function transferDownloadsToDb(int $packageId, array $keys, DateTimeImmutable $now): void + public function transferDownloadsToDb(int $packageId, array $keys, \DateTimeImmutable $now): void { $package = $this->getEM()->getRepository(Package::class)->find($packageId); // package was deleted in the meantime, abort @@ -245,16 +245,16 @@ public function transferDownloadsToDb(int $packageId, array $keys, DateTimeImmut } /** - * @param array $keys array of keys => dl count - * @param list $validVersionIds + * @param array $keys array of keys => dl count + * @param list $validVersionIds */ - private function createDbRecordsForKeys(Package $package, array $keys, array $validVersionIds, DateTimeImmutable $now): void + private function createDbRecordsForKeys(Package $package, array $keys, array $validVersionIds, \DateTimeImmutable $now): void { reset($keys); [$id, $type] = $this->getKeyInfo((string) key($keys)); // skip if the version was deleted in the meantime - if ($type === Download::TYPE_VERSION && !in_array($id, $validVersionIds, true)) { + if ($type === Download::TYPE_VERSION && !\in_array($id, $validVersionIds, true)) { return; } @@ -282,7 +282,7 @@ private function createDbRecordsForKeys(Package $package, array $keys, array $va } // only store records for packages or for versions that have had downloads to avoid storing empty records - if (!$isNewRecord || $type === Download::TYPE_PACKAGE || count($record->getData()) > 0) { + if (!$isNewRecord || $type === Download::TYPE_PACKAGE || \count($record->getData()) > 0) { $this->getEM()->persist($record); } diff --git a/src/Model/FavoriteManager.php b/src/Model/FavoriteManager.php index eaaebdac07..7a7d2f3823 100644 --- a/src/Model/FavoriteManager.php +++ b/src/Model/FavoriteManager.php @@ -26,7 +26,7 @@ class FavoriteManager public function __construct( private Client $redis, private PackageRepository $packageRepo, - private UserRepository $userRepo + private UserRepository $userRepo, ) { } @@ -79,6 +79,7 @@ public function getFaverCount(Package $package): int /** * @param array $packageIds + * * @return array */ public function getFaverCounts(array $packageIds): array diff --git a/src/Model/PackageManager.php b/src/Model/PackageManager.php index 9843071d22..b1a171c389 100644 --- a/src/Model/PackageManager.php +++ b/src/Model/PackageManager.php @@ -13,27 +13,27 @@ namespace App\Model; use Algolia\AlgoliaSearch\Exceptions\AlgoliaException; +use Algolia\AlgoliaSearch\SearchClient; use App\Entity\Dependent; +use App\Entity\Download; +use App\Entity\EmptyReferenceCache; +use App\Entity\Package; use App\Entity\PhpStat; use App\Entity\User; -use App\Service\CdnClient; -use Doctrine\Persistence\ManagerRegistry; -use App\Entity\Package; use App\Entity\Version; -use App\Entity\Download; -use App\Entity\EmptyReferenceCache; -use Psr\Log\LoggerInterface; +use App\Service\CdnClient; +use App\Service\GitHubUserMigrationWorker; use Composer\Pcre\Preg; -use Algolia\AlgoliaSearch\SearchClient; +use Doctrine\Persistence\ManagerRegistry; use Predis\Client; -use App\Service\GitHubUserMigrationWorker; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Twig\Environment; -use Symfony\Component\Mailer\MailerInterface; -use Symfony\Component\Mime\Address; -use Symfony\Component\Mime\Email; /** * @author Jordi Boggiano @@ -72,7 +72,7 @@ public function deletePackage(Package $package): void if ($token && $this->githubWorker->deleteWebHook($token, $package)) { break; } - } catch (TransportExceptionInterface | DecodingExceptionInterface | HttpExceptionInterface $e) { + } catch (TransportExceptionInterface|DecodingExceptionInterface|HttpExceptionInterface $e) { // ignore } } @@ -179,12 +179,12 @@ public function notifyUpdateFailure(Package $package, \Exception $e, ?string $de $body = $this->twig->render('email/update_failed.txt.twig', [ 'package' => $package, - 'exception' => get_class($e), + 'exception' => $e::class, 'exceptionMessage' => $e->getMessage(), 'details' => $details, ]); - $message = (new Email()) + $message = new Email() ->subject($package->getName().' failed to update, invalid composer.json data') ->from(new Address($this->options['from'], $this->options['fromName'])) ->to(...array_values($recipients)) @@ -196,7 +196,7 @@ public function notifyUpdateFailure(Package $package, \Exception $e, ?string $de try { $this->mailer->send($message); } catch (\Symfony\Component\Mailer\Exception\TransportExceptionInterface $e) { - $this->logger->error('['.get_class($e).'] '.$e->getMessage()); + $this->logger->error('['.$e::class.'] '.$e->getMessage()); return false; } @@ -220,8 +220,8 @@ public function notifyNewMaintainer(User $user, Package $package): bool 'package_name' => $package->getName(), ]); - $message = (new Email) - ->subject('You have been added to ' . $package->getName() . ' as a maintainer') + $message = new Email() + ->subject('You have been added to '.$package->getName().' as a maintainer') ->from(new Address($this->options['from'], $this->options['fromName'])) ->to((string) $user->getEmail()) ->text($body) @@ -232,7 +232,7 @@ public function notifyNewMaintainer(User $user, Package $package): bool try { $this->mailer->send($message); } catch (\Symfony\Component\Mailer\Exception\TransportExceptionInterface $e) { - $this->logger->error('['.get_class($e).'] '.$e->getMessage()); + $this->logger->error('['.$e::class.'] '.$e->getMessage()); return false; } diff --git a/src/Model/ProviderManager.php b/src/Model/ProviderManager.php index 4fbb757394..3a72559bdc 100644 --- a/src/Model/ProviderManager.php +++ b/src/Model/ProviderManager.php @@ -12,8 +12,8 @@ namespace App\Model; -use App\Entity\PackageRepository; use App\Entity\Package; +use App\Entity\PackageRepository; use Predis\Client; class ProviderManager @@ -33,11 +33,12 @@ public function packageExists(string $name): bool * Check if multiple packages exist in the registry * * @param string[] $names Package names to check + * * @return array Associative array of package name => exists */ public function packagesExist(array $names): array { - if (0 === count($names)) { + if (0 === \count($names)) { return []; } @@ -79,7 +80,7 @@ public function getPackageNames(): array } $names = $this->redis->smembers('set:packages'); - sort($names, SORT_STRING | SORT_FLAG_CASE); + sort($names, \SORT_STRING | \SORT_FLAG_CASE); return $names; } diff --git a/src/Model/RedisAdapter.php b/src/Model/RedisAdapter.php index 84a77f63fa..35c186d27c 100644 --- a/src/Model/RedisAdapter.php +++ b/src/Model/RedisAdapter.php @@ -18,6 +18,7 @@ /** * @author Jordi Boggiano + * * @template-implements AdapterInterface */ class RedisAdapter implements AdapterInterface diff --git a/src/Model/VersionIdCache.php b/src/Model/VersionIdCache.php index 3ba65457c2..9348b27652 100644 --- a/src/Model/VersionIdCache.php +++ b/src/Model/VersionIdCache.php @@ -24,6 +24,7 @@ public function __construct(private Client $redis) /** * @param array $payload + * * @return array */ public function augmentDownloadPayloadWithIds(array $payload): array diff --git a/src/Package/SymlinkDumper.php b/src/Package/SymlinkDumper.php index 07902d4391..0e039b8c89 100644 --- a/src/Package/SymlinkDumper.php +++ b/src/Package/SymlinkDumper.php @@ -12,19 +12,19 @@ namespace App\Package; +use App\Entity\Package; use App\Entity\PackageFreezeReason; +use App\Entity\Version; use Composer\Pcre\Preg; -use Doctrine\DBAL\ArrayParameterType; -use Seld\Signal\SignalHandler; -use Symfony\Component\Filesystem\Filesystem; use Composer\Util\Filesystem as ComposerFilesystem; +use Doctrine\DBAL\ArrayParameterType; use Doctrine\Persistence\ManagerRegistry; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Component\Finder\Finder; -use App\Entity\Version; -use App\Entity\Package; use Graze\DogStatsD\Client as StatsDClient; use Monolog\Logger; +use Seld\Signal\SignalHandler; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Finder\Finder; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Webmozart\Assert\Assert; /** @@ -40,30 +40,35 @@ class SymlinkDumper /** * Data cache + * * @var array */ private array $rootFile; /** * Data cache + * * @var array */ private array $listings = []; /** * Data cache + * * @var array */ private array $individualFiles = []; /** * Modified times of individual files + * * @var array */ private array $individualFilesMtime = []; /** * Stores all the disk writes to be replicated in the second build dir after the symlink has been swapped + * * @var array|false */ private array|bool $writeLog = []; @@ -76,7 +81,8 @@ public function __construct( private string $buildDir, /** * Generate compressed files. - * @var int 0 disabled, 9 maximum. + * + * @var int 0 disabled, 9 maximum */ private int $compress, private StatsDClient $statsd, @@ -85,7 +91,7 @@ public function __construct( $webDir = realpath($webDir); Assert::string($webDir); $this->webDir = $webDir; - $this->cfs = new ComposerFilesystem; + $this->cfs = new ComposerFilesystem(); } /** @@ -121,8 +127,8 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal $oldBuildDir = realpath($buildDirB); } - assert(is_string($buildDir)); - assert(is_string($oldBuildDir)); + \assert(\is_string($buildDir)); + \assert(\is_string($oldBuildDir)); // copy existing stuff for smooth BC transition if ($initialRun && !$force) { @@ -132,7 +138,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal throw new \RuntimeException('Run this again with --force the first time around to make sure it dumps all packages'); } if ($verbose) { - echo 'Copying existing files'.PHP_EOL; + echo 'Copying existing files'.\PHP_EOL; } foreach ([$buildDir, $oldBuildDir] as $dir) { @@ -141,8 +147,8 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal } if ($verbose) { - echo 'Web dir is '.$webDir.'/p ('.realpath($webDir.'/p').')'.PHP_EOL; - echo 'Build dir is '.$buildDir.PHP_EOL; + echo 'Web dir is '.$webDir.'/p ('.realpath($webDir.'/p').')'.\PHP_EOL; + echo 'Build dir is '.$buildDir.\PHP_EOL; } // clean the build dir to start over if we are re-dumping everything @@ -151,7 +157,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal $this->writeLog = false; if ($verbose) { - echo 'Cleaning up existing files'.PHP_EOL; + echo 'Cleaning up existing files'.\PHP_EOL; } if (!$this->clearDirectory($buildDir)) { return false; @@ -166,12 +172,12 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal $modifiedIndividualFiles = []; // make sure huge packages get processed first to avoid blowing out memory usage later - if (in_array(300981, $packageIds, true)) { + if (\in_array(300981, $packageIds, true)) { unset($packageIds[array_search(300981, $packageIds, true)]); $packageIds = array_merge([300981], $packageIds); } - $total = count($packageIds); + $total = \count($packageIds); $current = 0; $step = 50; while ($packageIds) { @@ -179,7 +185,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal $packages = $this->getEM()->getRepository(Package::class)->getPackagesWithVersions(array_splice($packageIds, 0, $step)); if ($verbose) { - echo '['.sprintf('%'.strlen((string) $total).'d', $current).'/'.$total.'] Processing '.$step.' packages ('.(memory_get_usage(true) / 1024 / 1024).' MB RAM)'.PHP_EOL; + echo '['.\sprintf('%'.\strlen((string) $total).'d', $current).'/'.$total.'] Processing '.$step.' packages ('.(memory_get_usage(true) / 1024 / 1024).' MB RAM)'.\PHP_EOL; } $current += $step; @@ -218,7 +224,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal } $versionData = $versionRepo->getVersionData($versionIds); foreach ($package->getVersions() as $version) { - foreach (array_slice($version->getNames($versionData), 0, 150) as $versionName) { + foreach (\array_slice($version->getNames($versionData), 0, 150) as $versionName) { if (!Preg::isMatch('{^[A-Za-z0-9_-][A-Za-z0-9_.-]*/[A-Za-z0-9_-][A-Za-z0-9_.-]*$}', $versionName) || strpos($versionName, '..')) { continue; } @@ -232,18 +238,18 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal } // store affected files to clean up properly in the next update - $this->filesystem->mkdir(dirname($buildDir.'/'.$name)); - $this->writeFileNonAtomic($buildDir.'/'.$name.'.files', json_encode(array_keys($affectedFiles), JSON_THROW_ON_ERROR)); + $this->filesystem->mkdir(\dirname($buildDir.'/'.$name)); + $this->writeFileNonAtomic($buildDir.'/'.$name.'.files', json_encode(array_keys($affectedFiles), \JSON_THROW_ON_ERROR)); $dumpTimeUpdates[$dumpTime->format('Y-m-d H:i:s')][] = $package->getId(); if ($verbose) { - echo '['.sprintf('%'.strlen((string) $total).'d', $current).'/'.$total.'] Processing '.$package->getName().' ('.(memory_get_usage(true) / 1024 / 1024).' MB RAM)'.PHP_EOL; + echo '['.\sprintf('%'.\strlen((string) $total).'d', $current).'/'.$total.'] Processing '.$package->getName().' ('.(memory_get_usage(true) / 1024 / 1024).' MB RAM)'.\PHP_EOL; } if (memory_get_usage(true) / 1024 / 1024 > 8000) { if ($verbose) { - echo 'Memory usage too high, stopping here.'.PHP_EOL; + echo 'Memory usage too high, stopping here.'.\PHP_EOL; } $packageIds = []; break; @@ -260,7 +266,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal if ($current % 250 === 0 || !$packageIds || memory_get_usage() > 1024 * 1024 * 1024) { if ($verbose) { - echo 'Dumping individual files'.PHP_EOL; + echo 'Dumping individual files'.\PHP_EOL; } $this->dumpIndividualFiles($buildDir); } @@ -268,7 +274,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal // prepare individual files listings if ($verbose) { - echo 'Preparing individual files listings'.PHP_EOL; + echo 'Preparing individual files listings'.\PHP_EOL; } $individualHashedListings = []; $finder = Finder::create()->files()->ignoreVCS(true)->name('*.json')->in($buildDir)->depth('1'); @@ -280,7 +286,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal continue; } - $key = basename(dirname($file)).'/'.basename($file); + $key = basename(\dirname($file)).'/'.basename($file); if ($force && !isset($modifiedIndividualFiles[$key])) { continue; } @@ -297,10 +303,10 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal $rootFile = $buildDir.'/packages.json'; $this->rootFile = ['packages' => []]; $this->rootFile['notify-batch'] = $this->router->generate('track_download_batch', [], UrlGeneratorInterface::ABSOLUTE_URL); - $this->rootFile['providers-url'] = $this->router->generate('home', []) . 'p/%package%$%hash%.json'; - $this->rootFile['metadata-url'] = $this->router->generate('home', []) . 'p2/%package%.json'; + $this->rootFile['providers-url'] = $this->router->generate('home', []).'p/%package%$%hash%.json'; + $this->rootFile['metadata-url'] = $this->router->generate('home', []).'p2/%package%.json'; $this->rootFile['metadata-changes-url'] = $this->router->generate('metadata_changes', [], UrlGeneratorInterface::ABSOLUTE_URL); - $this->rootFile['search'] = $this->router->generate('search_api', [], UrlGeneratorInterface::ABSOLUTE_URL) . '?q=%query%&type=%type%'; + $this->rootFile['search'] = $this->router->generate('search_api', [], UrlGeneratorInterface::ABSOLUTE_URL).'?q=%query%&type=%type%'; $this->rootFile['list'] = $this->router->generate('list', [], UrlGeneratorInterface::ABSOLUTE_URL); $this->rootFile['security-advisories'] = [ 'metadata' => true, // whether advisories are part of the metadata v2 files @@ -311,7 +317,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal $this->rootFile['warning-versions'] = '<1.99'; if ($verbose) { - echo 'Dumping individual listings'.PHP_EOL; + echo 'Dumping individual listings'.\PHP_EOL; } // dump listings to build dir @@ -322,7 +328,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal } if ($verbose) { - echo 'Dumping root'.PHP_EOL; + echo 'Dumping root'.\PHP_EOL; } $this->dumpRootFile($rootFile); } catch (\Exception $e) { @@ -333,7 +339,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal try { if ($verbose) { - echo 'Putting new files in production'.PHP_EOL; + echo 'Putting new files in production'.\PHP_EOL; } // move away old files for BC update @@ -350,7 +356,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal try { if ($initialRun || !is_link($webDir.'/packages.json') || $force) { if ($verbose) { - echo 'Writing/linking the packages.json'.PHP_EOL; + echo 'Writing/linking the packages.json'.\PHP_EOL; } if (file_exists($webDir.'/packages.json')) { unlink($webDir.'/packages.json'); @@ -358,7 +364,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal if (file_exists($webDir.'/packages.json.gz')) { unlink($webDir.'/packages.json.gz'); } - if (defined('PHP_WINDOWS_VERSION_BUILD')) { + if (\defined('PHP_WINDOWS_VERSION_BUILD')) { $sourcePath = $buildDir.'/packages.json'; if (!copy($sourcePath, $webDir.'/packages.json')) { throw new \RuntimeException('Could not copy the packages.json file'); @@ -386,7 +392,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal // clean the old build dir if we re-dumped everything if ($force) { if ($verbose) { - echo 'Cleaning up old build dir'.PHP_EOL; + echo 'Cleaning up old build dir'.\PHP_EOL; } if (!$this->clearDirectory($oldBuildDir)) { throw new \RuntimeException('Unrecoverable inconsistent state (old build dir could not be cleared), run with --force again to retry'); @@ -396,18 +402,18 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal // copy state to old active dir if ($force) { if ($verbose) { - echo 'Copying new contents to old build dir to sync up'.PHP_EOL; + echo 'Copying new contents to old build dir to sync up'.\PHP_EOL; } $this->cloneDir($buildDir, $oldBuildDir); } else { if ($verbose) { - echo 'Replaying write log in old build dir'.PHP_EOL; + echo 'Replaying write log in old build dir'.\PHP_EOL; } $this->copyWriteLog($buildDir, $oldBuildDir); } if ($verbose) { - echo 'Updating package dump times'.PHP_EOL; + echo 'Updating package dump times'.\PHP_EOL; } $maxDumpTime = 0; @@ -494,8 +500,8 @@ public function gc(): void $buildDirs = [realpath($this->buildDir.'/a'), realpath($this->buildDir.'/b')]; shuffle($buildDirs); - assert(is_string($buildDirs[0])); - assert(is_string($buildDirs[1])); + \assert(\is_string($buildDirs[0])); + \assert(\is_string($buildDirs[1])); $this->cleanOldFiles($buildDirs[0], $buildDirs[1], $safeFiles); } @@ -514,7 +520,7 @@ private function cleanOldFiles(string $buildDir, string $oldBuildDir, array $saf foreach ($vendorFiles as $file) { $file = (string) $file; - $key = strtr(str_replace($buildDir.DIRECTORY_SEPARATOR, '', $file), '\\', '/'); + $key = strtr(str_replace($buildDir.\DIRECTORY_SEPARATOR, '', $file), '\\', '/'); if (!isset($safeFiles[$key])) { unlink($file); if (file_exists($altDirFile = str_replace($buildDir, $oldBuildDir, $file))) { @@ -528,7 +534,7 @@ private function cleanOldFiles(string $buildDir, string $oldBuildDir, array $saf $finder = Finder::create()->depth(0)->files()->name('provider-*.json')->ignoreVCS(true)->in($buildDir)->date('until 10minutes ago'); foreach ($finder as $provider) { $path = (string) $provider; - $key = strtr(str_replace($buildDir.DIRECTORY_SEPARATOR, '', $path), '\\', '/'); + $key = strtr(str_replace($buildDir.\DIRECTORY_SEPARATOR, '', $path), '\\', '/'); if (!isset($safeFiles[$key])) { unlink($path); if (file_exists($path.'.gz')) { @@ -569,14 +575,14 @@ private function dumpRootFile(string $file): void ksort($this->rootFile['packages'][$package]); } - $json = json_encode($this->rootFile, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); + $json = json_encode($this->rootFile, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR); $time = time(); $this->writeFile($file, $json, $time); if ($this->compress) { $encoded = gzencode($json, $this->compress); - assert(is_string($encoded)); - $this->writeFile($file . '.gz', $encoded, $time); + \assert(\is_string($encoded)); + $this->writeFile($file.'.gz', $encoded, $time); } } @@ -590,17 +596,17 @@ private function dumpListing(string $path): array // sort files to make hash consistent ksort($this->listings[$key]['providers']); - $json = json_encode($this->listings[$key], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); + $json = json_encode($this->listings[$key], \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR); $hash = hash('sha256', $json); - $path = substr($path, 0, -5) . '$' . $hash . '.json'; + $path = substr($path, 0, -5).'$'.$hash.'.json'; $time = time(); if (!file_exists($path)) { $this->writeFile($path, $json, $time); if ($this->compress) { $encoded = gzencode($json, $this->compress); - assert(is_string($encoded)); - $this->writeFile($path . '.gz', $encoded, $time); + \assert(\is_string($encoded)); + $this->writeFile($path.'.gz', $encoded, $time); } } @@ -641,17 +647,17 @@ private function dumpIndividualFile(string $path, string $key): void ksort($this->individualFiles[$key]['packages'][$package]); } - $this->filesystem->mkdir(dirname($path)); + $this->filesystem->mkdir(\dirname($path)); $flags = 0; - if (count($this->individualFiles[$key]['packages']) === 0) { - $flags = JSON_FORCE_OBJECT; + if (\count($this->individualFiles[$key]['packages']) === 0) { + $flags = \JSON_FORCE_OBJECT; } - $json = json_encode($this->individualFiles[$key], $flags | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); + $json = json_encode($this->individualFiles[$key], $flags | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR); $this->writeFile($path, $json, $this->individualFilesMtime[$key]); // write the hashed provider file - $hashedFile = substr($path, 0, -5) . '$' . hash('sha256', $json) . '.json'; + $hashedFile = substr($path, 0, -5).'$'.hash('sha256', $json).'.json'; $this->writeFile($hashedFile, $json); } @@ -663,7 +669,7 @@ private function dumpVersionToIndividualFile(Version $version, string $file, str $this->loadIndividualFile($file, $key); $data = $version->toArray($versionData); $data['uid'] = $version->getId(); - if (in_array($data['version_normalized'], ['dev-master', 'dev-default', 'dev-trunk'], true)) { + if (\in_array($data['version_normalized'], ['dev-master', 'dev-default', 'dev-trunk'], true)) { $data['version_normalized'] = '9999999-dev'; } $this->individualFiles[$key]['packages'][strtolower($version->getName())][$version->getVersion()] = $data; @@ -707,7 +713,7 @@ private function getTargetListingBlocks(int $now): array // monday last week $timestamp = strtotime('monday last week', $now); - assert(is_int($timestamp)); + \assert(\is_int($timestamp)); $blocks['latest'] = $timestamp; $month = date('n', $now); @@ -724,7 +730,7 @@ private function getTargetListingBlocks(int $now): array while ($year >= 2013) { $timestamp = strtotime($year.'-01-01'); - assert(is_int($timestamp)); + \assert(\is_int($timestamp)); $blocks[$year] = $timestamp; $year--; } @@ -748,7 +754,7 @@ private function getTargetListing(string $file): string } } - return "provider-archived.json"; + return 'provider-archived.json'; } private function writeFile(string $path, string $contents, ?int $mtime = null): void @@ -759,7 +765,7 @@ private function writeFile(string $path, string $contents, ?int $mtime = null): } rename($path.'.tmp', $path); - if (is_array($this->writeLog)) { + if (\is_array($this->writeLog)) { $this->writeLog[$path] = [$contents, $mtime]; } } @@ -768,7 +774,7 @@ private function writeFileNonAtomic(string $path, string $contents): void { file_put_contents($path, $contents); - if (is_array($this->writeLog)) { + if (\is_array($this->writeLog)) { $this->writeLog[$path] = [$contents, null]; } } @@ -780,7 +786,7 @@ private function copyWriteLog(string $from, string $to): void foreach ($this->writeLog as $path => $op) { $path = str_replace($from, $to, $path); - $this->filesystem->mkdir(dirname($path)); + $this->filesystem->mkdir(\dirname($path)); file_put_contents($path, $op[0]); if ($op[1] !== null) { touch($path, $op[1]); diff --git a/src/Package/Updater.php b/src/Package/Updater.php index 6f193e3aa3..510273772f 100644 --- a/src/Package/Updater.php +++ b/src/Package/Updater.php @@ -15,37 +15,36 @@ use App\Entity\ConflictLink; use App\Entity\Dependent; use App\Entity\DevRequireLink; +use App\Entity\Package; use App\Entity\PackageFreezeReason; use App\Entity\ProvideLink; use App\Entity\ReplaceLink; use App\Entity\RequireLink; +use App\Entity\SuggestLink; +use App\Entity\Tag; +use App\Entity\Version; +use App\Entity\VersionRepository; use App\HtmlSanitizer\ReadmeImageSanitizer; use App\HtmlSanitizer\ReadmeLinkSanitizer; +use App\Model\ProviderManager; +use App\Model\VersionIdCache; +use App\Service\VersionCache; use App\Util\HttpDownloaderOptionsFactory; use cebe\markdown\GithubMarkdown; +use Composer\Config; +use Composer\IO\IOInterface; use Composer\Package\AliasPackage; +use Composer\Package\CompletePackageInterface; use Composer\Pcre\Preg; -use Composer\Repository\VcsRepository; +use Composer\Repository\InvalidRepositoryException; use Composer\Repository\Vcs\GitHubDriver; use Composer\Repository\Vcs\GitLabDriver; use Composer\Repository\Vcs\VcsDriverInterface; -use Composer\Repository\InvalidRepositoryException; +use Composer\Repository\VcsRepository; use Composer\Util\ErrorHandler; use Composer\Util\HttpDownloader; -use Composer\Config; -use Composer\IO\IOInterface; -use App\Entity\Package; -use App\Entity\Tag; -use App\Entity\Version; -use App\Entity\VersionRepository; -use App\Entity\SuggestLink; -use App\Model\ProviderManager; -use App\Model\VersionIdCache; -use DateTimeImmutable; use Doctrine\DBAL\ArrayParameterType; use Doctrine\Persistence\ManagerRegistry; -use App\Service\VersionCache; -use Composer\Package\CompletePackageInterface; use Symfony\Component\HtmlSanitizer\HtmlSanitizer; use Symfony\Component\HtmlSanitizer\HtmlSanitizerAction; use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig; @@ -117,15 +116,15 @@ public function __destruct() /** * Update a project * - * @param VcsRepository $repository the repository instance used to update from - * @param int $flags a few of the constants of this class + * @param VcsRepository $repository the repository instance used to update from + * @param int $flags a few of the constants of this class * @param ExistingVersionsForUpdate|null $existingVersions */ public function update(IOInterface $io, Config $config, Package $package, VcsRepository $repository, int $flags = 0, ?array $existingVersions = null, ?VersionCache $versionCache = null): Package { $httpDownloader = new HttpDownloader($io, $config, HttpDownloaderOptionsFactory::getOptions()); - $deleteDate = new DateTimeImmutable('-1day'); + $deleteDate = new \DateTimeImmutable('-1day'); $em = $this->getEM(); $rootIdentifier = null; @@ -159,9 +158,9 @@ public function update(IOInterface $io, Config $config, Package $package, VcsRep if ($package->getRemoteId() !== $remoteId) { $package->freeze(PackageFreezeReason::RemoteIdMismatch); $em->flush(); - $io->writeError('Skipping update as the source repository has a remote id mismatch. Expected '.$package->getRemoteId().' but got ' . $remoteId.'.'); + $io->writeError('Skipping update as the source repository has a remote id mismatch. Expected '.$package->getRemoteId().' but got '.$remoteId.'.'); - $message = (new Email()) + $message = new Email() ->subject($package->getName().' frozen due to remote id mismatch') ->from(new Address($this->mailFromEmail)) ->to($this->mailFromEmail) @@ -235,14 +234,14 @@ public function update(IOInterface $io, Config $config, Package $package, VcsRep $lastProcessed = null; $idsToMarkUpdated = []; - /** @var int|null|false $dependentSuggesterSource Version id to use as dependent/suggester source */ + /** @var int|false|null $dependentSuggesterSource Version id to use as dependent/suggester source */ $dependentSuggesterSource = null; foreach ($versions as $version) { if ($version instanceof AliasPackage) { continue; } if (!$version instanceof CompletePackageInterface) { - throw new \LogicException('Received a package instance of type '.get_class($version).', expected a CompletePackageInterface instance'); + throw new \LogicException('Received a package instance of type '.$version::class.', expected a CompletePackageInterface instance'); } if (isset($processedVersions[strtolower($version->getVersion())])) { @@ -254,7 +253,7 @@ public function update(IOInterface $io, Config $config, Package $package, VcsRep $result = $this->updateInformation($io, $versionRepository, $package, $existingVersions, $version, $flags, $rootIdentifier); $versionId = false; if ($result['updated']) { - assert($result['object'] instanceof Version); + \assert($result['object'] instanceof Version); $em->flush(); // detach version once flushed to avoid gathering lots of data in memory @@ -294,7 +293,7 @@ public function update(IOInterface $io, Config $config, Package $package, VcsRep foreach ($existingVersions as $version) { if ( // soft-deleted versions are really purged after a day - (!is_null($version['softDeletedAt']) && new \DateTime($version['softDeletedAt']) < $deleteDate) + (null !== $version['softDeletedAt'] && new \DateTime($version['softDeletedAt']) < $deleteDate) // remove v1 normalized versions of dev-master/trunk/default immediately as they have been recreated as dev-master/trunk/default in a non-normalized way || ($version['normalizedVersion'] === '9999999-dev') ) { @@ -329,15 +328,15 @@ public function update(IOInterface $io, Config $config, Package $package, VcsRep } } catch (\Throwable $e) { } - $io->writeError('Updated from '.$package->getRepository().' using ' . $driver::class . $usingDetails); + $io->writeError('Updated from '.$package->getRepository().' using '.$driver::class.$usingDetails); // make sure the package exists in the package list if for some reason adding it on submit failed if (!$this->providerManager->packageExists($package->getName())) { $this->providerManager->insertPackage($package); } - $package->setUpdatedAt(new DateTimeImmutable()); - $package->setCrawledAt(new DateTimeImmutable()); + $package->setUpdatedAt(new \DateTimeImmutable()); + $package->setCrawledAt(new \DateTimeImmutable()); if ($flags & self::FORCE_DUMP) { $package->setDumpedAt(null); @@ -361,6 +360,7 @@ public function update(IOInterface $io, Config $config, Package $package, VcsRep * - object (Version instance if it was updated) * * @param ExistingVersionsForUpdate $existingVersions + * * @return array{updated: true, id: int|null, version: string, object: Version}|array{updated: false, id: int|null, version: string, object: null} */ private function updateInformation(IOInterface $io, VersionRepository $versionRepo, Package $package, array $existingVersions, CompletePackageInterface $data, int $flags, string $rootIdentifier): array @@ -378,7 +378,7 @@ private function updateInformation(IOInterface $io, VersionRepository $versionRe // update if the source reference has changed (re-tag or new commit on branch) ($source['reference'] ?? null) !== $data->getSourceReference() // or the source has some corrupted github private url - || (isset($source['url']) && is_string($source['url']) && Preg::isMatch('{^git@github.com:.*?\.git$}', $source['url'])) + || (isset($source['url']) && \is_string($source['url']) && Preg::isMatch('{^git@github.com:.*?\.git$}', $source['url'])) // or if the right flag is set || ($flags & self::UPDATE_EQUAL_REFS) // or if the package must be marked abandoned from composer.json @@ -425,15 +425,15 @@ private function updateInformation(IOInterface $io, VersionRepository $versionRe $version->setLicense($data->getLicense() ?: []); $version->setPackage($package); - $version->setUpdatedAt(new DateTimeImmutable()); + $version->setUpdatedAt(new \DateTimeImmutable()); $version->setSoftDeletedAt(null); - $version->setReleasedAt($data->getReleaseDate() === null ? null : DateTimeImmutable::createFromInterface($data->getReleaseDate())); + $version->setReleasedAt($data->getReleaseDate() === null ? null : \DateTimeImmutable::createFromInterface($data->getReleaseDate())); if ($data->getSourceType()) { $source['type'] = $data->getSourceType(); $source['url'] = $data->getSourceUrl(); // force public URLs even if the package somehow got downgraded to a GitDriver - if (is_string($source['url']) && Preg::isMatch('{^git@github.com:(?P.*?)\.git$}', $source['url'], $match)) { + if (\is_string($source['url']) && Preg::isMatch('{^git@github.com:(?P.*?)\.git$}', $source['url'], $match)) { $source['url'] = 'https://github.com/'.$match['repo']; } $source['reference'] = $data->getSourceReference(); @@ -494,7 +494,7 @@ private function updateInformation(IOInterface $io, VersionRepository $versionRe foreach ($existingTags as $tag) { $version->getTags()->removeElement($tag); } - } elseif (count($version->getTags())) { + } elseif (\count($version->getTags())) { $version->getTags()->clear(); } @@ -528,7 +528,7 @@ private function updateInformation(IOInterface $io, VersionRepository $versionRe $links = []; foreach ($data->{$opts['composer-getter']}() as $link) { $constraint = $link->getPrettyConstraint(); - if (false !== strpos($constraint, ',') && false !== strpos($constraint, '@')) { + if (str_contains($constraint, ',') && str_contains($constraint, '@')) { $constraint = Preg::replaceCallbackStrictGroups('{([><]=?\s*[^@]+?)@([a-z]+)}i', static function ($matches) { if ($matches[2] === 'stable') { return $matches[1]; @@ -554,7 +554,7 @@ private function updateInformation(IOInterface $io, VersionRepository $versionRe foreach ($links as $linkPackageName => $linkPackageVersion) { $class = $opts['entity']; - $link = new $class; + $link = new $class(); $link->setPackageName((string) $linkPackageName); $link->setPackageVersion($linkPackageVersion); $version->{$opts['setter']}($link); @@ -577,14 +577,14 @@ private function updateInformation(IOInterface $io, VersionRepository $versionRe } foreach ($suggests as $linkPackageName => $linkPackageVersion) { - $link = new SuggestLink; + $link = new SuggestLink(); $link->setPackageName($linkPackageName); $link->setPackageVersion($linkPackageVersion); $version->addSuggestLink($link); $link->setVersion($version); $em->persist($link); } - } elseif (count($version->getSuggest())) { + } elseif (\count($version->getSuggest())) { // clear existing suggests if present foreach ($version->getSuggest() as $link) { $em->remove($link); @@ -608,7 +608,7 @@ private function updateReadme(IOInterface $io, Package $package, VcsDriverInterf try { $composerInfo = $driver->getComposerInformation($driver->getRootIdentifier()); - if (isset($composerInfo['readme']) && is_string($composerInfo['readme'])) { + if (isset($composerInfo['readme']) && \is_string($composerInfo['readme'])) { $readmeFile = $composerInfo['readme']; } else { $readmeFile = 'README.md'; @@ -623,7 +623,7 @@ private function updateReadme(IOInterface $io, Package $package, VcsDriverInterf case '.txt': $source = $driver->getFileContent($readmeFile, $driver->getRootIdentifier()); if (!empty($source)) { - $package->setReadme('
' . htmlspecialchars($source) . '
'); + $package->setReadme('
'.htmlspecialchars($source).'
'); } break; @@ -646,7 +646,7 @@ private function updateReadme(IOInterface $io, Package $package, VcsDriverInterf } catch (\Exception $e) { // we ignore all errors for this minor function $io->write( - 'Can not update readme. Error: ' . $e->getMessage(), + 'Can not update readme. Error: '.$e->getMessage(), true, IOInterface::VERBOSE ); @@ -679,7 +679,7 @@ private function updateGitHubInfo(HttpDownloader $httpDownloader, Package $packa $package->setReadme($this->prepareReadme($readme, 'github.com', $owner, $repo)); } - if (!empty($repoData['language']) && is_string($repoData['language'])) { + if (!empty($repoData['language']) && \is_string($repoData['language'])) { $package->setLanguage($repoData['language']); } if (isset($repoData['stargazers_count']) && is_numeric($repoData['stargazers_count'])) { @@ -731,8 +731,8 @@ private function prepareReadme(string $readme, ?string $host = null, ?string $ow { // detect base path for github readme if file is located in a subfolder like docs/README.md $basePath = ''; - if ($host === 'github.com' && Preg::isMatchStrictGroups('{^
]+?data-path="([^"]+)"}', $readme, $match) && false !== strpos($match[1], '/')) { - $basePath = dirname($match[1]); + if ($host === 'github.com' && Preg::isMatchStrictGroups('{^
]+?data-path="([^"]+)"}', $readme, $match) && str_contains($match[1], '/')) { + $basePath = \dirname($match[1]); } if ($basePath) { $basePath .= '/'; @@ -792,9 +792,10 @@ private function prepareReadme(string $readme, ?string $host = null, ?string $ow /** * @phpstan-param string|null $str + * * @phpstan-return ($str is string ? string : null) */ - private function sanitize(string|null $str): string|null + private function sanitize(?string $str): ?string { if (null === $str) { return null; diff --git a/src/Package/V2Dumper.php b/src/Package/V2Dumper.php index 11f8df42fa..0c4ea9c4f0 100644 --- a/src/Package/V2Dumper.php +++ b/src/Package/V2Dumper.php @@ -14,22 +14,22 @@ use App\Audit\AuditRecordType; use App\Entity\AuditRecord; +use App\Entity\Package; use App\Entity\PackageFreezeReason; use App\Entity\SecurityAdvisory; +use App\Entity\Version; +use App\Model\ProviderManager; use App\Service\CdnClient; use App\Service\ReplicaClient; +use Composer\MetadataMinifier\MetadataMinifier; use Composer\Pcre\Preg; use Doctrine\DBAL\ArrayParameterType; -use Symfony\Component\Filesystem\Filesystem; -use Composer\MetadataMinifier\MetadataMinifier; use Doctrine\Persistence\ManagerRegistry; -use Symfony\Component\Finder\Finder; -use App\Entity\Version; -use App\Entity\Package; -use App\Model\ProviderManager; -use Predis\Client; use Graze\DogStatsD\Client as StatsDClient; use Monolog\Logger; +use Predis\Client; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Finder\Finder; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Webmozart\Assert\Assert; @@ -70,10 +70,10 @@ public function dumpRoot(bool $verbose = false): void ]; $rootFileContents['notify-batch'] = $this->router->generate('track_download_batch', [], UrlGeneratorInterface::ABSOLUTE_URL); - $rootFileContents['providers-url'] = $this->router->generate('home', []) . 'p/%package%$%hash%.json'; - $rootFileContents['metadata-url'] = str_replace('https://', 'https://repo.', $this->router->generate('home', [], UrlGeneratorInterface::ABSOLUTE_URL)) . 'p2/%package%.json'; + $rootFileContents['providers-url'] = $this->router->generate('home', []).'p/%package%$%hash%.json'; + $rootFileContents['metadata-url'] = str_replace('https://', 'https://repo.', $this->router->generate('home', [], UrlGeneratorInterface::ABSOLUTE_URL)).'p2/%package%.json'; $rootFileContents['metadata-changes-url'] = $this->router->generate('metadata_changes', [], UrlGeneratorInterface::ABSOLUTE_URL); - $rootFileContents['search'] = $this->router->generate('search_api', [], UrlGeneratorInterface::ABSOLUTE_URL) . '?q=%query%&type=%type%'; + $rootFileContents['search'] = $this->router->generate('search_api', [], UrlGeneratorInterface::ABSOLUTE_URL).'?q=%query%&type=%type%'; $rootFileContents['list'] = $this->router->generate('list', [], UrlGeneratorInterface::ABSOLUTE_URL); $rootFileContents['security-advisories'] = [ 'metadata' => true, // whether advisories are part of the metadata v2 files @@ -106,9 +106,9 @@ public function dumpRoot(bool $verbose = false): void ]; if ($verbose) { - echo 'Dumping root'.PHP_EOL; + echo 'Dumping root'.\PHP_EOL; } - $this->dumpRootFile($rootFile, json_encode($rootFileContents, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR)); + $this->dumpRootFile($rootFile, json_encode($rootFileContents, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR)); $this->statsd->increment('packagist.metadata_dump_root'); } @@ -139,19 +139,19 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal } if ($verbose) { - echo 'Web dir is '.$webDir.'/p2 ('.realpath($webDir.'/p2').')'.PHP_EOL; - echo 'Build v2 dir is '.$buildDirV2.PHP_EOL; + echo 'Web dir is '.$webDir.'/p2 ('.realpath($webDir.'/p2').')'.\PHP_EOL; + echo 'Build v2 dir is '.$buildDirV2.\PHP_EOL; } $dumpTimeUpdates = []; $versionRepo = $this->getEM()->getRepository(Version::class); - $total = count($packageIds); + $total = \count($packageIds); $current = 0; $step = 50; while ($packageIds) { - $dumpTime = new \DateTime; + $dumpTime = new \DateTime(); $idBatch = array_splice($packageIds, 0, $step); $this->logger->debug('Dumping package ids', ['ids' => $idBatch]); $packages = $this->getEM()->getRepository(Package::class)->getPackagesWithVersions($idBatch); @@ -160,7 +160,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal $advisories = $this->getEM()->getRepository(SecurityAdvisory::class)->getAdvisoryIdsAndVersions($packageNames); if ($verbose) { - echo '['.sprintf('%'.strlen((string) $total).'d', $current).'/'.$total.'] Processing '.$step.' packages'.PHP_EOL; + echo '['.\sprintf('%'.\strlen((string) $total).'d', $current).'/'.$total.'] Processing '.$step.' packages'.\PHP_EOL; } $current += $step; @@ -196,7 +196,7 @@ public function dump(array $packageIds, bool $force = false, bool $verbose = fal } if ($verbose) { - echo 'Updating package dump times'.PHP_EOL; + echo 'Updating package dump times'.\PHP_EOL; } $maxDumpTime = 0; @@ -273,8 +273,8 @@ private function dumpRootFile(string $file, string $json): void $this->writeFileAtomic($file, $json, $filemtime); $encoded = gzencode($json, 8); - assert(is_string($encoded)); - $this->writeFileAtomic($file . '.gz', $encoded, $filemtime); + \assert(\is_string($encoded)); + $this->writeFileAtomic($file.'.gz', $encoded, $filemtime); $this->purgeCdn('packages.json'); } @@ -289,7 +289,7 @@ private function writeFileAtomic(string $path, string $contents, ?int $mtime = n } /** - * @param mixed[] $versionData + * @param mixed[] $versionData * @param array $advisories */ private function dumpPackageToV2File(string $dir, Package $package, array $versionData, array $advisories): void @@ -316,17 +316,17 @@ private function dumpPackageToV2File(string $dir, Package $package, array $versi /** * @param array|null $advisories - * @param array $versions - * @param VersionData $versionData + * @param array $versions + * @param VersionData $versionData */ - private function dumpVersionsToV2File(Package $package, string $name, string $dir, string $filename, string $packageName, array $versions, array $versionData, bool $forceDump, array|null $advisories = null): void + private function dumpVersionsToV2File(Package $package, string $name, string $dir, string $filename, string $packageName, array $versions, array $versionData, bool $forceDump, ?array $advisories = null): void { $versionArrays = []; foreach ($versions as $version) { $versionArrays[] = $version->toV2Array($versionData); } - $path = $dir . '/' . $filename; + $path = $dir.'/'.$filename; $metadata = [ 'minified' => 'composer/2.0', @@ -339,7 +339,7 @@ private function dumpVersionsToV2File(Package $package, string $name, string $di $metadata['security-advisories'] = $advisories; } - $json = json_encode($metadata, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); + $json = json_encode($metadata, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR); $this->writeV2File($package, $name, $path, $json, $forceDump); } @@ -369,7 +369,7 @@ private function writeV2File(Package $package, string $name, string $path, strin $pkgWithDevFlag = $match[1]; $relativePath = 'p2/'.$pkgWithDevFlag.'.json'; - $this->filesystem->mkdir(dirname($path)); + $this->filesystem->mkdir(\dirname($path)); $filemtime = $this->writeCdn($relativePath, $contents); @@ -391,7 +391,7 @@ private function writeV2File(Package $package, string $name, string $path, strin $filemtime += $counter; } - $timeUnix = intval(ceil($filemtime / 10000)); + $timeUnix = (int) ceil($filemtime / 10000); $this->writeFileAtomic($path, $contents, $timeUnix); $this->writeToReplica($path, $contents, $timeUnix); @@ -404,6 +404,7 @@ private function writeV2File(Package $package, string $name, string $path, strin /** * @param non-empty-string $relativePath + * * @throws TransportExceptionInterface */ private function writeCdn(string $relativePath, string $contents): int diff --git a/src/Redis/DownloadsIncr.php b/src/Redis/DownloadsIncr.php index f161997303..627914fe86 100644 --- a/src/Redis/DownloadsIncr.php +++ b/src/Redis/DownloadsIncr.php @@ -25,7 +25,7 @@ public function getKeysCount(): int throw new \LogicException('getKeysCount called before setArguments'); } - return count($this->args) - 4 /* ACTUAL ARGS */; + return \count($this->args) - 4 /* ACTUAL ARGS */; } /** @@ -41,40 +41,40 @@ public function setArguments(array $arguments): void public function getScript(): string { return << 0 then - redis.call("INCRBY", KEYS[1], successful); - redis.call("INCRBY", KEYS[2], successful); - redis.call("INCRBY", KEYS[3], successful); - redis.call("HINCRBY", KEYS[4] .. "days", ARGV[2], successful); - redis.call("HINCRBY", KEYS[4] .. "months", ARGV[3], successful); - redis.call("HINCRBY", KEYS[5] .. "days", ARGV[2], successful); - redis.call("HINCRBY", KEYS[5] .. "months", ARGV[3], successful); -end + if successful > 0 then + redis.call("INCRBY", KEYS[1], successful); + redis.call("INCRBY", KEYS[2], successful); + redis.call("INCRBY", KEYS[3], successful); + redis.call("HINCRBY", KEYS[4] .. "days", ARGV[2], successful); + redis.call("HINCRBY", KEYS[4] .. "months", ARGV[3], successful); + redis.call("HINCRBY", KEYS[5] .. "days", ARGV[2], successful); + redis.call("HINCRBY", KEYS[5] .. "months", ARGV[3], successful); + end -return redis.status_reply("OK"); -LUA; + return redis.status_reply("OK"); + LUA; } } diff --git a/src/Redis/FailedLoginCounter.php b/src/Redis/FailedLoginCounter.php index 3d914befec..1c284fecd4 100644 --- a/src/Redis/FailedLoginCounter.php +++ b/src/Redis/FailedLoginCounter.php @@ -25,7 +25,7 @@ public function getKeysCount(): int throw new \LogicException('getKeysCount called before setArguments'); } - return count($this->args); + return \count($this->args); } /** @@ -41,10 +41,10 @@ public function setArguments(array $arguments): void public function getScript(): string { return <<query && '' === $this->type && count($this->tags) === 0) { + if ('' === $this->query && '' === $this->type && \count($this->tags) === 0) { throw new \InvalidArgumentException('Missing search query, example: ?q=example'); } @@ -74,10 +74,10 @@ public function getOptions(): array $tags[] = 'tags:"'.strtr($tag, ' ', '-').'"'; } } - $filters[] = '(' . implode(' OR ', $tags) . ')'; + $filters[] = '('.implode(' OR ', $tags).')'; } - if (0 !== count($filters)) { + if (0 !== \count($filters)) { $queryParams['filters'] = implode(' AND ', $filters); } diff --git a/src/Security/AccountEmailExistsWithoutGitHubException.php b/src/Security/AccountEmailExistsWithoutGitHubException.php index c3dbc499dc..101c5a601a 100644 --- a/src/Security/AccountEmailExistsWithoutGitHubException.php +++ b/src/Security/AccountEmailExistsWithoutGitHubException.php @@ -20,12 +20,9 @@ public function __construct(private string $email) { } - /** - * @inheritDoc - */ public function getMessageKey(): string { return 'An account with your GitHub email ('.$this->email.') already exists on Packagist.org but it is not linked to your GitHub account. ' - . 'Please log in to it via username/password and then connect your GitHub account from the Profile > Settings page.'; + .'Please log in to it via username/password and then connect your GitHub account from the Profile > Settings page.'; } } diff --git a/src/Security/AccountUsernameExistsWithoutGitHubException.php b/src/Security/AccountUsernameExistsWithoutGitHubException.php index 226af5b3d6..391496d15e 100644 --- a/src/Security/AccountUsernameExistsWithoutGitHubException.php +++ b/src/Security/AccountUsernameExistsWithoutGitHubException.php @@ -23,6 +23,6 @@ public function __construct(private string $username) public function getMessageKey(): string { return 'An account with your GitHub username ('.$this->username.') already exists on Packagist.org but it is not linked to your GitHub account. ' - . 'Please log in to it via username/password and then connect your GitHub account from the Profile > Settings page.'; + .'Please log in to it via username/password and then connect your GitHub account from the Profile > Settings page.'; } } diff --git a/src/Security/BruteForceLoginFormAuthenticator.php b/src/Security/BruteForceLoginFormAuthenticator.php index a9d1e96d4a..1a02cad1ab 100644 --- a/src/Security/BruteForceLoginFormAuthenticator.php +++ b/src/Security/BruteForceLoginFormAuthenticator.php @@ -41,6 +41,7 @@ /** * @phpstan-type Credentials array{username: string, password: string, ip: string|null, recaptcha: string} + * * @template-covariant TUser of UserInterface */ class BruteForceLoginFormAuthenticator extends AbstractLoginFormAuthenticator implements AuthenticationEntryPointInterface @@ -103,7 +104,7 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token, $this->getEM()->flush(); } - if (($targetPath = $request->getSession()->get('_security.'.$firewallName.'.target_path')) && is_string($targetPath)) { + if (($targetPath = $request->getSession()->get('_security.'.$firewallName.'.target_path')) && \is_string($targetPath)) { return $this->httpUtils->createRedirectResponse($request, $targetPath, Response::HTTP_FOUND); } @@ -132,7 +133,7 @@ private function getCredentials(Request $request): array ]; if (!\is_string($credentials['username'])) { - throw new BadRequestHttpException(sprintf('The key "_username" must be a string, "%s" given.', \gettype($credentials['username']))); + throw new BadRequestHttpException(\sprintf('The key "_username" must be a string, "%s" given.', \gettype($credentials['username']))); } $credentials['username'] = trim($credentials['username']); diff --git a/src/Security/EmailVerifier.php b/src/Security/EmailVerifier.php index ee59c0beda..c9a14a7800 100644 --- a/src/Security/EmailVerifier.php +++ b/src/Security/EmailVerifier.php @@ -36,7 +36,7 @@ public function __construct( public function sendEmailConfirmation(string $verifyEmailRouteName, UserInterface $user, TemplatedEmail $email): void { if (!$user instanceof User) { - throw new \UnexpectedValueException('Expected '.User::class.', got '.get_class($user)); + throw new \UnexpectedValueException('Expected '.User::class.', got '.$user::class); } $signatureComponents = $this->verifyEmailHelper->generateSignature( @@ -62,7 +62,7 @@ public function sendEmailConfirmation(string $verifyEmailRouteName, UserInterfac public function handleEmailConfirmation(Request $request, UserInterface $user): void { if (!$user instanceof User) { - throw new \UnexpectedValueException('Expected '.User::class.', got '.get_class($user)); + throw new \UnexpectedValueException('Expected '.User::class.', got '.$user::class); } $this->verifyEmailHelper->validateEmailConfirmationFromRequest($request, (string) $user->getId(), $user->getEmail()); diff --git a/src/Security/GitHubAuthenticator.php b/src/Security/GitHubAuthenticator.php index 34cce18274..c513dee007 100644 --- a/src/Security/GitHubAuthenticator.php +++ b/src/Security/GitHubAuthenticator.php @@ -16,9 +16,9 @@ use App\Util\DoctrineTrait; use Composer\Pcre\Preg; use Doctrine\Persistence\ManagerRegistry; +use KnpU\OAuth2ClientBundle\Client\ClientRegistry; use KnpU\OAuth2ClientBundle\Client\Provider\GithubClient; use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator; -use KnpU\OAuth2ClientBundle\Client\ClientRegistry; use League\OAuth2\Client\Provider\GithubResourceOwner; use Symfony\Component\HttpClient\NoPrivateNetworkHttpClient; use Symfony\Component\HttpFoundation\Request; @@ -52,9 +52,6 @@ public function supports(Request $request): ?bool return $request->attributes->get('_route') === 'login_github_check'; } - /** - * @inheritDoc - */ public function authenticate(Request $request): Passport { $accessToken = $this->fetchAccessToken($this->getGitHubClient()); @@ -145,7 +142,7 @@ public function authenticate(Request $request): Passport $this->getEM()->flush(); $session = $request->getSession(); - assert($session instanceof FlashBagAwareSessionInterface); + \assert($session instanceof FlashBagAwareSessionInterface); $session->getFlashBag()->add('success', 'A new account was automatically created. You are now logged in.'); return $user; @@ -162,7 +159,7 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token, $this->getEM()->flush(); } - if (($targetPath = $request->getSession()->get('_security.'.$firewallName.'.target_path')) && is_string($targetPath)) { + if (($targetPath = $request->getSession()->get('_security.'.$firewallName.'.target_path')) && \is_string($targetPath)) { return $this->httpUtils->createRedirectResponse($request, $targetPath, Response::HTTP_FOUND); } @@ -178,7 +175,7 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio } $session = $request->getSession(); - assert($session instanceof FlashBagAwareSessionInterface); + \assert($session instanceof FlashBagAwareSessionInterface); $session->getFlashBag()->add('warning', $message); return $this->httpUtils->createRedirectResponse($request, 'login', Response::HTTP_FOUND); diff --git a/src/Security/NoGitHubNicknameFoundException.php b/src/Security/NoGitHubNicknameFoundException.php index a3b721b864..7889fcfc8c 100644 --- a/src/Security/NoGitHubNicknameFoundException.php +++ b/src/Security/NoGitHubNicknameFoundException.php @@ -19,6 +19,6 @@ class NoGitHubNicknameFoundException extends UserNotFoundException public function getMessageKey(): string { return 'No username/nickname was found on your GitHub account, so we can not automatically log you in. ' - . 'Please register an account manually and then connect your GitHub account from the Profile > Settings page.'; + .'Please register an account manually and then connect your GitHub account from the Profile > Settings page.'; } } diff --git a/src/Security/NoVerifiedGitHubEmailFoundException.php b/src/Security/NoVerifiedGitHubEmailFoundException.php index d39945d253..b9a4b4f222 100644 --- a/src/Security/NoVerifiedGitHubEmailFoundException.php +++ b/src/Security/NoVerifiedGitHubEmailFoundException.php @@ -19,6 +19,6 @@ class NoVerifiedGitHubEmailFoundException extends UserNotFoundException public function getMessageKey(): string { return 'No verified email address was found on your GitHub account, so we can not automatically log you in. ' - . 'Please register an account manually and then connect your GitHub account from the Profile > Settings page.'; + .'Please register an account manually and then connect your GitHub account from the Profile > Settings page.'; } } diff --git a/src/Security/Provider/UserProvider.php b/src/Security/Provider/UserProvider.php index e38988fed7..93b7085045 100644 --- a/src/Security/Provider/UserProvider.php +++ b/src/Security/Provider/UserProvider.php @@ -12,15 +12,15 @@ namespace App\Security\Provider; +use App\Entity\User; use App\Entity\UserRepository; use App\Util\DoctrineTrait; use Doctrine\Persistence\ManagerRegistry; -use App\Entity\User; use Symfony\Component\Security\Core\Exception\UserNotFoundException; +use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; -use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; /** * @implements UserProviderInterface @@ -44,13 +44,10 @@ public function loadUserByIdentifier(string $usernameOrEmail): User return $user; } - /** - * @inheritDoc - */ public function refreshUser(UserInterface $user): User { if (!$user instanceof User) { - throw new \UnexpectedValueException('Expected '.User::class.', got '.get_class($user)); + throw new \UnexpectedValueException('Expected '.User::class.', got '.$user::class); } $user = $this->getRepo()->find($user->getId()); @@ -64,7 +61,7 @@ public function refreshUser(UserInterface $user): User public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void { if (!$user instanceof User) { - throw new \UnexpectedValueException('Expected '.User::class.', got '.get_class($user)); + throw new \UnexpectedValueException('Expected '.User::class.', got '.$user::class); } $user->setPassword($newHashedPassword); diff --git a/src/Security/RecaptchaContext.php b/src/Security/RecaptchaContext.php index 897ee2c31a..eba89b6683 100644 --- a/src/Security/RecaptchaContext.php +++ b/src/Security/RecaptchaContext.php @@ -32,8 +32,8 @@ public function __construct( public function getRedisKeys(bool $forClear = false): array { return array_filter([ - !$forClear && $this->ip ? self::LOGIN_BASE_KEY_IP . $this->ip : null, - $this->username ? self::LOGIN_BASE_KEY_USER . strtolower($this->username) : null, + !$forClear && $this->ip ? self::LOGIN_BASE_KEY_IP.$this->ip : null, + $this->username ? self::LOGIN_BASE_KEY_USER.strtolower($this->username) : null, ]); } diff --git a/src/Security/RecaptchaHelper.php b/src/Security/RecaptchaHelper.php index 888100e702..0767c6dc9e 100644 --- a/src/Security/RecaptchaHelper.php +++ b/src/Security/RecaptchaHelper.php @@ -70,7 +70,7 @@ public function increaseCounter(RecaptchaContext $context): void return; } - /** @phpstan-ignore-next-line method.notFound */ + /* @phpstan-ignore-next-line method.notFound */ $this->redisCache->incrFailedLoginCounter(...$context->getRedisKeys()); } @@ -81,7 +81,7 @@ public function clearCounter(RecaptchaContext $context): void } $keys = $context->getRedisKeys(true); - if (count($keys) > 0) { + if (\count($keys) > 0) { $this->redisCache->del($keys); } } diff --git a/src/Security/TwoFactorAuthManager.php b/src/Security/TwoFactorAuthManager.php index 0860a61961..a069546175 100644 --- a/src/Security/TwoFactorAuthManager.php +++ b/src/Security/TwoFactorAuthManager.php @@ -13,9 +13,9 @@ namespace App\Security; use App\Entity\User; +use Doctrine\Persistence\ManagerRegistry; use Scheb\TwoFactorBundle\Model\BackupCodeInterface; use Scheb\TwoFactorBundle\Security\TwoFactor\Backup\BackupCodeManagerInterface; -use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface; @@ -81,7 +81,7 @@ public function generateAndSaveNewBackupCode(User $user): string /** * Check if the code is a valid backup code of the user. * - * @param User $user + * @param User $user */ public function isBackupCode(object $user, string $code): bool { @@ -97,7 +97,7 @@ public function isBackupCode(object $user, string $code): bool * * This should only be called after the backup code has been confirmed and consumed. * - * @param User $user + * @param User $user */ public function invalidateBackupCode(object $user, string $code): void { @@ -112,7 +112,7 @@ public function invalidateBackupCode(object $user, string $code): void return; } - assert($session instanceof FlashBagAwareSessionInterface); + \assert($session instanceof FlashBagAwareSessionInterface); $session->getFlashBag()->add('warning', 'Use of your backup code has disabled two-factor authentication for your account. Please consider re-enabling it for your security.'); } } diff --git a/src/Security/TwoFactorAuthRateLimiter.php b/src/Security/TwoFactorAuthRateLimiter.php index d7c96177ac..f6bebd1c79 100644 --- a/src/Security/TwoFactorAuthRateLimiter.php +++ b/src/Security/TwoFactorAuthRateLimiter.php @@ -36,7 +36,7 @@ public function onAuthAttempt(TwoFactorAuthenticationEvent $event): void $count = (int) $this->redisCache->get($key); if ($count >= self::MAX_ATTEMPTS) { - throw new CustomUserMessageAuthenticationException(sprintf('Too many authentication failures. Try again in %d minutes.', self::RATE_LIMIT_DURATION)); + throw new CustomUserMessageAuthenticationException(\sprintf('Too many authentication failures. Try again in %d minutes.', self::RATE_LIMIT_DURATION)); } } diff --git a/src/Security/UserNotifier.php b/src/Security/UserNotifier.php index c7cefd4e19..fae2ba57e3 100644 --- a/src/Security/UserNotifier.php +++ b/src/Security/UserNotifier.php @@ -36,7 +36,7 @@ public function __construct( */ public function notifyChange(string $email, string $reason = '', string $template = 'email/alert_change.txt.twig', string $subject = 'A change has been made to your Packagist.org account', ...$templateVars): void { - $email = (new TemplatedEmail()) + $email = new TemplatedEmail() ->from(new Address($this->mailFromEmail, $this->mailFromName)) ->to($email) ->subject($subject) @@ -49,7 +49,7 @@ public function notifyChange(string $email, string $reason = '', string $templat try { $this->mailer->send($email); } catch (TransportExceptionInterface $e) { - $this->logger->error('['.get_class($e).'] '.$e->getMessage()); + $this->logger->error('['.$e::class.'] '.$e->getMessage()); } } } diff --git a/src/Security/Voter/PackageVoter.php b/src/Security/Voter/PackageVoter.php index 018d87f3cd..f006b3cb58 100644 --- a/src/Security/Voter/PackageVoter.php +++ b/src/Security/Voter/PackageVoter.php @@ -49,7 +49,7 @@ protected function voteOnAttribute(string $attribute, mixed $subject, TokenInter /** @var Package $package */ $package = $subject; - return match(PackageActions::from($attribute)) { + return match (PackageActions::from($attribute)) { PackageActions::Abandon => $this->canEdit($package, $user), PackageActions::Delete => $this->canDelete($package, $user), PackageActions::DeleteVersion => $this->canDeleteVersion($package, $user), diff --git a/src/SecurityAdvisory/AdvisoryIdGenerator.php b/src/SecurityAdvisory/AdvisoryIdGenerator.php index 04e464ecdc..6a687f463a 100644 --- a/src/SecurityAdvisory/AdvisoryIdGenerator.php +++ b/src/SecurityAdvisory/AdvisoryIdGenerator.php @@ -15,13 +15,13 @@ class AdvisoryIdGenerator { // All alphanumeric symbols except vowels and some to avoid misspellings (I, O, l, 0), case insensitive, 34 character alphabet - private const ALNUM_SAFE_CI = "bcdfghjkmnpqrstvwxyz123456789"; + private const ALNUM_SAFE_CI = 'bcdfghjkmnpqrstvwxyz123456789'; public static function generate(): string { $letterPool = self::ALNUM_SAFE_CI; $token = 'PKSA-'; - $len = strlen($letterPool) - 1; + $len = \strlen($letterPool) - 1; for ($i = 0; $i < 3; $i++) { for ($j = 0; $j < 4; $j++) { $token .= $letterPool[random_int(0, $len)]; diff --git a/src/SecurityAdvisory/FriendsOfPhpSecurityAdvisoriesSource.php b/src/SecurityAdvisory/FriendsOfPhpSecurityAdvisoriesSource.php index 666a8ad84f..e470322aa4 100644 --- a/src/SecurityAdvisory/FriendsOfPhpSecurityAdvisoriesSource.php +++ b/src/SecurityAdvisory/FriendsOfPhpSecurityAdvisoriesSource.php @@ -12,6 +12,8 @@ namespace App\SecurityAdvisory; +use App\Entity\Package; +use App\Entity\Version; use Composer\Downloader\TransportException; use Composer\Factory; use Composer\IO\ConsoleIO; @@ -19,10 +21,8 @@ use Composer\Package\Loader\ArrayLoader; use Composer\Util\Loop; use Composer\Util\ProcessExecutor; -use App\Entity\Package; -use App\Entity\Version; -use Psr\Log\LoggerInterface; use Doctrine\Persistence\ManagerRegistry; +use Psr\Log\LoggerInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; use Symfony\Component\Yaml\Yaml; @@ -57,8 +57,8 @@ public function getAdvisories(ConsoleIO $io): ?RemoteSecurityAdvisoryCollection $localCwdDir = null; try { - $localCwdDir = sys_get_temp_dir() . '/' . uniqid(self::SOURCE_NAME, true); - $localDir = $localCwdDir . '/' . self::SOURCE_NAME; + $localCwdDir = sys_get_temp_dir().'/'.uniqid(self::SOURCE_NAME, true); + $localDir = $localCwdDir.'/'.self::SOURCE_NAME; $config = Factory::createConfig($io, $localCwdDir); $process = new ProcessExecutor(); $factory = new Factory(); @@ -85,7 +85,7 @@ public function getAdvisories(ConsoleIO $io): ?RemoteSecurityAdvisoryCollection return new RemoteSecurityAdvisoryCollection($advisories); } catch (TransportException $e) { - $this->logger->error(sprintf('Failed to download "%s" zip file', self::SECURITY_PACKAGE), [ + $this->logger->error(\sprintf('Failed to download "%s" zip file', self::SECURITY_PACKAGE), [ 'exception' => $e, ]); diff --git a/src/SecurityAdvisory/GitHubSecurityAdvisoriesSource.php b/src/SecurityAdvisory/GitHubSecurityAdvisoriesSource.php index 678fd6b069..b540368a94 100644 --- a/src/SecurityAdvisory/GitHubSecurityAdvisoriesSource.php +++ b/src/SecurityAdvisory/GitHubSecurityAdvisoriesSource.php @@ -57,10 +57,10 @@ public function getAdvisories(ConsoleIO $io): ?RemoteSecurityAdvisoryCollection while ($hasNextPage) { $headers = []; - if (count($this->fallbackGhTokens) > 0) { - $fallbackUser = $this->doctrine->getRepository(User::class)->findOneBy(['usernameCanonical' => $this->fallbackGhTokens[random_int(0, count($this->fallbackGhTokens) - 1)]]); + if (\count($this->fallbackGhTokens) > 0) { + $fallbackUser = $this->doctrine->getRepository(User::class)->findOneBy(['usernameCanonical' => $this->fallbackGhTokens[random_int(0, \count($this->fallbackGhTokens) - 1)]]); if (null !== $fallbackUser?->getGithubToken()) { - $headers = ['Authorization' => 'token ' . $fallbackUser->getGithubToken()]; + $headers = ['Authorization' => 'token '.$fallbackUser->getGithubToken()]; } } @@ -77,7 +77,7 @@ public function getAdvisories(ConsoleIO $io): ?RemoteSecurityAdvisoryCollection return null; } - $data = json_decode($response->getContent(), true, JSON_THROW_ON_ERROR); + $data = json_decode($response->getContent(), true, \JSON_THROW_ON_ERROR); $data = $data['data']; foreach ($data['securityVulnerabilities']['nodes'] as $node) { @@ -101,7 +101,7 @@ public function getAdvisories(ConsoleIO $io): ?RemoteSecurityAdvisoryCollection continue; } - if (in_array($cve, self::IGNORE_CVES, true)) { + if (\in_array($cve, self::IGNORE_CVES, true)) { continue; } @@ -167,40 +167,40 @@ public function getAdvisories(ConsoleIO $io): ?RemoteSecurityAdvisoryCollection private function getQuery(string $after = ''): string { if ('' !== $after) { - $after = sprintf(',after:"%s"', $after); + $after = \sprintf(',after:"%s"', $after); } $query = <<setTime(0, 0, 0); + $date = new \DateTimeImmutable()->setTime(0, 0, 0); } } @@ -125,7 +124,7 @@ public static function createFromFriendsOfPhp(string $fileNameWithPath, array $i $cve = $info['cve']; } - return new RemoteSecurityAdvisory( + return new self( $fileNameWithPath, $info['title'], str_replace('composer://', '', $info['reference']), diff --git a/src/SecurityAdvisory/SecurityAdvisoryResolver.php b/src/SecurityAdvisory/SecurityAdvisoryResolver.php index af2218e07d..46da43ea44 100644 --- a/src/SecurityAdvisory/SecurityAdvisoryResolver.php +++ b/src/SecurityAdvisory/SecurityAdvisoryResolver.php @@ -18,6 +18,7 @@ class SecurityAdvisoryResolver { /** * @param SecurityAdvisory[] $existingAdvisories + * * @return array{SecurityAdvisory[], SecurityAdvisory[]} */ public function resolve(array $existingAdvisories, RemoteSecurityAdvisoryCollection $remoteAdvisories, string $sourceName): array diff --git a/src/Service/CdnClient.php b/src/Service/CdnClient.php index f4abe32734..7c01863fae 100644 --- a/src/Service/CdnClient.php +++ b/src/Service/CdnClient.php @@ -32,13 +32,14 @@ public function __construct( /** * @param non-empty-string $path + * * @return int file modified time in units of 100-microseconds (i.e. 1.2345 seconds = a return value of 12345) */ public function uploadMetadata(string $path, string $contents): int { $path = ltrim($path, '/'); if ($this->metadataApiKey === null || $this->metadataEndpoint === null || $this->metadataPublicEndpoint === null || $this->cdnApiKey === null) { - return intval(time() * 10000); + return (int) (time() * 10000); } $resp = $this->sendUploadMetadataRequest($path, $contents); diff --git a/src/Service/FallbackGitHubAuthProvider.php b/src/Service/FallbackGitHubAuthProvider.php index 90f7a7e1f1..556a1ad793 100644 --- a/src/Service/FallbackGitHubAuthProvider.php +++ b/src/Service/FallbackGitHubAuthProvider.php @@ -12,8 +12,8 @@ namespace App\Service; -use Doctrine\Persistence\ManagerRegistry; use App\Entity\User; +use Doctrine\Persistence\ManagerRegistry; class FallbackGitHubAuthProvider { @@ -24,10 +24,10 @@ public function __construct( ) { } - public function getAuthToken(): string|null + public function getAuthToken(): ?string { if ($this->fallbackGhTokens) { - $fallbackUser = $this->doctrine->getRepository(User::class)->findOneBy(['usernameCanonical' => $this->fallbackGhTokens[random_int(0, count($this->fallbackGhTokens) - 1)]]); + $fallbackUser = $this->doctrine->getRepository(User::class)->findOneBy(['usernameCanonical' => $this->fallbackGhTokens[random_int(0, \count($this->fallbackGhTokens) - 1)]]); if (null === $fallbackUser) { throw new \LogicException('Invalid fallback user was not found'); } diff --git a/src/Service/GitHubUserMigrationWorker.php b/src/Service/GitHubUserMigrationWorker.php index e4e2293ff7..8e80115a2d 100644 --- a/src/Service/GitHubUserMigrationWorker.php +++ b/src/Service/GitHubUserMigrationWorker.php @@ -12,13 +12,13 @@ namespace App\Service; -use Composer\Pcre\Preg; -use Psr\Log\LoggerInterface; -use Doctrine\Persistence\ManagerRegistry; +use App\Entity\Job; use App\Entity\Package; use App\Entity\User; -use App\Entity\Job; use App\Util\DoctrineTrait; +use Composer\Pcre\Preg; +use Doctrine\Persistence\ManagerRegistry; +use Psr\Log\LoggerInterface; use Seld\Signal\SignalHandler; use Symfony\Component\HttpClient\NoPrivateNetworkHttpClient; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; @@ -43,6 +43,7 @@ public function __construct( /** * @param Job $job + * * @return GenericCompletedResult|GitHubMigrationFailedResult|RescheduleResult|GitHubMigrationResult */ public function process(Job $job, SignalHandler $signal): array @@ -68,7 +69,7 @@ public function process(Job $job, SignalHandler $signal): array $results = ['hooks_setup' => 0, 'hooks_failed' => [], 'hooks_ok_unchanged' => 0]; foreach ($packageRepository->getGitHubPackagesByMaintainer($id) as $package) { $result = $this->setupWebHook($user->getGithubToken(), $package); - if (is_string($result)) { + if (\is_string($result)) { $results['hooks_failed'][] = ['package' => $package->getName(), 'reason' => $result]; } elseif ($result === true) { $results['hooks_setup']++; @@ -77,7 +78,7 @@ public function process(Job $job, SignalHandler $signal): array } // null result means not processed as not a github-like URL } - } catch (TransportExceptionInterface | DecodingExceptionInterface | HttpExceptionInterface $e) { + } catch (TransportExceptionInterface|DecodingExceptionInterface|HttpExceptionInterface $e) { return [ 'status' => Job::STATUS_RESCHEDULE, 'message' => 'Got error, rescheduling: '.$e->getMessage(), @@ -92,7 +93,7 @@ public function process(Job $job, SignalHandler $signal): array ]; } - public function setupWebHook(string $token, Package $package): null|bool|string + public function setupWebHook(string $token, Package $package): bool|string|null { if (!Preg::isMatch('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):)(?P[^/]+)/(?P.+?)(?:\.git|/)?$#', $package->getRepository(), $match)) { return null; @@ -105,7 +106,7 @@ public function setupWebHook(string $token, Package $package): null|bool|string try { $hooks = $this->getHooks($token, $repoKey); - $this->logger->debug(count($hooks).' existing hooks', ['hooks' => $hooks]); + $this->logger->debug(\count($hooks).' existing hooks', ['hooks' => $hooks]); $legacyHooks = array_values(array_filter( $hooks, @@ -116,7 +117,7 @@ static function ($hook) { $currentHooks = array_values(array_filter( $hooks, static function ($hook) { - return $hook['name'] === 'web' && (strpos($hook['config']['url'], self::HOOK_URL) === 0 || strpos($hook['config']['url'], self::HOOK_URL_ALT) === 0); + return $hook['name'] === 'web' && (str_starts_with($hook['config']['url'], self::HOOK_URL) || str_starts_with($hook['config']['url'], self::HOOK_URL_ALT)); } )); // sort shorter urls first as that should lead us to find the correct one first @@ -168,7 +169,7 @@ static function ($hook) { } } - if (count($hooks) && !Preg::isMatch('{^https://api\.github\.com/repos/'.$repoKey.'/hooks/}', $hooks[0]['url'])) { + if (\count($hooks) && !Preg::isMatch('{^https://api\.github\.com/repos/'.$repoKey.'/hooks/}', $hooks[0]['url'])) { if (Preg::isMatch('{https://api\.github\.com/repos/([^/]+/[^/]+)/hooks}', $hooks[0]['url'], $match)) { $package->setRepository('https://github.com/'.$match[1]); $this->getEM()->persist($package); @@ -204,7 +205,7 @@ public function deleteWebHook(string $token, Package $package): bool $hooks = $this->getHooks($token, $repoKey); foreach ($hooks as $hook) { - if ($hook['name'] === 'web' && strpos($hook['config']['url'], self::HOOK_URL) === 0) { + if ($hook['name'] === 'web' && str_starts_with($hook['config']['url'], self::HOOK_URL)) { $this->logger->debug('Deleting hook '.$hook['id'], ['hook' => $hook]); $this->request($token, 'DELETE', 'repos/'.$repoKey.'/hooks/'.$hook['id']); } @@ -270,7 +271,7 @@ private function request(string $token, string $method, string $url, ?array $jso $opts['json'] = $json; } - return $this->httpClient->request($method, 'https://api.github.com/' . $url, $opts); + return $this->httpClient->request($method, 'https://api.github.com/'.$url, $opts); } /** diff --git a/src/Service/Locker.php b/src/Service/Locker.php index 0def5e3f83..0187de7bd4 100644 --- a/src/Service/Locker.php +++ b/src/Service/Locker.php @@ -12,10 +12,10 @@ namespace App\Service; +use App\Util\DoctrineTrait; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection; use Doctrine\Persistence\ManagerRegistry; -use App\Util\DoctrineTrait; class Locker { diff --git a/src/Service/QueueWorker.php b/src/Service/QueueWorker.php index f345e6124b..269c4421be 100644 --- a/src/Service/QueueWorker.php +++ b/src/Service/QueueWorker.php @@ -12,14 +12,13 @@ namespace App\Service; +use App\Entity\Job; use App\Logger\LogIdProcessor; -use Predis\Client as Redis; -use Monolog\Logger; use Doctrine\Persistence\ManagerRegistry; -use App\Entity\Job; -use Seld\Signal\SignalHandler; use Graze\DogStatsD\Client as StatsDClient; -use TypeError; +use Monolog\Logger; +use Predis\Client as Redis; +use Seld\Signal\SignalHandler; use Webmozart\Assert\Assert; class QueueWorker @@ -124,12 +123,12 @@ private function process(string $jobId, SignalHandler $signal): bool $processor = $this->jobWorkers[$job->getType()]; $this->logger->reset(); - $this->logger->debug('Processing ' . $job->getType() . ' job', ['job' => $job->getPayload()]); + $this->logger->debug('Processing '.$job->getType().' job', ['job' => $job->getPayload()]); try { $result = $processor->process($job, $signal); } catch (\Throwable $e) { - if ($e instanceof TypeError) { + if ($e instanceof \TypeError) { $this->logger->error('TypeError: '.$e->getMessage(), ['exception' => $e]); $this->statsd->increment('worker.queue.processed', 1, 1, [ 'jobType' => $job->getType(), @@ -185,7 +184,7 @@ private function process(string $jobId, SignalHandler $signal): bool if (isset($result['exception'])) { $result['exceptionMsg'] = $result['exception']->getMessage(); - $result['exceptionClass'] = get_class($result['exception']); + $result['exceptionClass'] = \get_class($result['exception']); unset($result['exception']); } diff --git a/src/Service/Scheduler.php b/src/Service/Scheduler.php index bb582d0a39..a47d852c78 100644 --- a/src/Service/Scheduler.php +++ b/src/Service/Scheduler.php @@ -12,10 +12,10 @@ namespace App\Service; +use App\Entity\Job; +use App\Entity\Package; use Doctrine\Persistence\ManagerRegistry; use Predis\Client as RedisClient; -use App\Entity\Package; -use App\Entity\Job; class Scheduler { @@ -23,7 +23,7 @@ class Scheduler public function __construct( private RedisClient $redis, - private ManagerRegistry $doctrine + private ManagerRegistry $doctrine, ) { } @@ -113,6 +113,7 @@ public function getJobStatus(string $jobId): array /** * @param array> $jobs + * * @return array */ public function getJobsStatus(array $jobs): array @@ -135,7 +136,9 @@ public function getJobsStatus(array $jobs): array /** * @template T of AnyJob + * * @param T $payload + * * @return Job */ private function createJob(string $type, array $payload, ?int $packageId = null, ?\DateTimeImmutable $executeAfter = null): Job diff --git a/src/Service/SecurityAdvisoryWorker.php b/src/Service/SecurityAdvisoryWorker.php index 4be85b1f42..29fe878e99 100644 --- a/src/Service/SecurityAdvisoryWorker.php +++ b/src/Service/SecurityAdvisoryWorker.php @@ -12,17 +12,17 @@ namespace App\Service; +use App\Entity\Job; +use App\Entity\SecurityAdvisory; use App\EventListener\SecurityAdvisoryUpdateListener; use App\SecurityAdvisory\SecurityAdvisoryResolver; +use App\SecurityAdvisory\SecurityAdvisorySourceInterface; use Composer\Console\HtmlOutputFormatter; use Composer\Factory; use Composer\IO\BufferIO; -use App\Entity\Job; -use App\Entity\SecurityAdvisory; -use App\SecurityAdvisory\SecurityAdvisorySourceInterface; +use Doctrine\Persistence\ManagerRegistry; use Psr\Log\LoggerInterface; use Seld\Signal\SignalHandler; -use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\Console\Output\OutputInterface; class SecurityAdvisoryWorker @@ -44,6 +44,7 @@ public function __construct( /** * @param Job $job + * * @return AdvisoriesCompletedResult|AdvisoriesErroredResult|RescheduleResult */ public function process(Job $job, SignalHandler $signal): array diff --git a/src/Service/UpdaterWorker.php b/src/Service/UpdaterWorker.php index f1999d6d93..990dc2bdb5 100644 --- a/src/Service/UpdaterWorker.php +++ b/src/Service/UpdaterWorker.php @@ -12,36 +12,36 @@ namespace App\Service; -use Doctrine\ORM\EntityNotFoundException; +use App\Entity\EmptyReferenceCache; +use App\Entity\Job; +use App\Entity\Package; use App\Entity\PackageFreezeReason; +use App\Entity\Version; +use App\Model\DownloadManager; +use App\Model\PackageManager; +use App\Package\Updater; use App\SecurityAdvisory\FriendsOfPhpSecurityAdvisoriesSource; -use Composer\Pcre\Preg; -use Psr\Cache\CacheItemPoolInterface; -use Psr\Log\LoggerInterface; +use App\Util\DoctrineTrait; +use App\Util\LoggingHttpDownloader; +use Composer\Console\HtmlOutputFormatter; +use Composer\Downloader\TransportException; +use Composer\Factory; +use Composer\IO\BufferIO; use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ValidatingArrayLoader; -use Doctrine\Persistence\ManagerRegistry; -use Composer\Console\HtmlOutputFormatter; +use Composer\Pcre\Preg; use Composer\Repository\InvalidRepositoryException; use Composer\Repository\VcsRepository; -use Composer\IO\BufferIO; +use Composer\Util\HttpDownloader; +use Doctrine\ORM\EntityNotFoundException; +use Doctrine\Persistence\ManagerRegistry; +use Graze\DogStatsD\Client as StatsDClient; +use Psr\Cache\CacheItemPoolInterface; +use Psr\Log\LoggerInterface; use Psr\SimpleCache\CacheInterface; +use Seld\Signal\SignalHandler; use Symfony\Component\Cache\Psr16Cache; use Symfony\Component\Console\Output\OutputInterface; -use App\Entity\Package; -use App\Entity\Version; -use App\Package\Updater; -use App\Entity\Job; -use App\Entity\EmptyReferenceCache; -use App\Model\PackageManager; -use App\Model\DownloadManager; -use App\Util\DoctrineTrait; -use App\Util\LoggingHttpDownloader; -use Seld\Signal\SignalHandler; -use Composer\Factory; -use Composer\Downloader\TransportException; -use Composer\Util\HttpDownloader; -use Graze\DogStatsD\Client as StatsDClient; use Symfony\Component\HtmlSanitizer\HtmlSanitizer; use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig; @@ -102,8 +102,10 @@ public function setLoadMinimalVersions(bool $loadMinimalVersions): void /** * @param Job $job - * @phpstan-return PackageCompletedResult|PackageFailedResult|PackageGoneResult|PackageDeletedResult|RescheduleResult + * * @return array{status: Job::STATUS_*, message?: string, after?: \DateTimeImmutable, vendor?: string, details?: string, exception?: \Throwable} + * + * @phpstan-return PackageCompletedResult|PackageFailedResult|PackageGoneResult|PackageDeletedResult|RescheduleResult */ public function process(Job $job, SignalHandler $signal): array { @@ -133,7 +135,7 @@ public function process(Job $job, SignalHandler $signal): array // sandbox into a unique cache dir per package id to avoid potential cache reuse issues if (trim($this->updaterWorkerCacheDir) !== '' && is_dir($this->updaterWorkerCacheDir)) { - $subDir = str_pad((string) $package->getId(), 9, '0', STR_PAD_LEFT); + $subDir = str_pad((string) $package->getId(), 9, '0', \STR_PAD_LEFT); $subDir = substr($subDir, 0, 6).'/'.$package->getId(); $config->merge(['config' => ['cache-dir' => $this->updaterWorkerCacheDir.'/'.$subDir]]); unset($subDir); @@ -445,7 +447,7 @@ private function cleanupOutput(string $str): string (?PFound\ cached\ composer.json\ of\ (?P=pkg)\ \((?P=version)\)\r?\n) }x', '$5', $str); - $config = (new HtmlSanitizerConfig()) + $config = new HtmlSanitizerConfig() ->allowElement('span') ->allowAttribute('style', ['span']) ->withMaxInputLength(10_000_000); @@ -468,7 +470,7 @@ private function checkForDeadGitHubPackage(Package $package, string $repo, HttpD if ( $e instanceof TransportException && ( - in_array($e->getStatusCode(), [404, 409, 451], true) + \in_array($e->getStatusCode(), [404, 409, 451], true) || ($e->getStatusCode() === 403 && str_contains('"message": "Repository access blocked"', (string) $e->getResponse())) ) ) { @@ -490,9 +492,7 @@ private function checkForDeadGitLabPackage(Package $package, string $repo, HttpD // 404 indicates the repo does not exist if ( $e instanceof TransportException - && ( - in_array($e->getStatusCode(), [404], true) - ) + && \in_array($e->getStatusCode(), [404], true) ) { return $this->completeDeadPackageCheck('https://gitlab.com/api/v4/projects/'.urlencode('packagist/vcs-repository-test'), $package, $httpDownloader, $output, $e); } diff --git a/src/Service/VersionCache.php b/src/Service/VersionCache.php index f1eec28ade..da1acced85 100644 --- a/src/Service/VersionCache.php +++ b/src/Service/VersionCache.php @@ -12,10 +12,10 @@ namespace App\Service; -use Composer\Pcre\Preg; -use Composer\Repository\VersionCacheInterface; use App\Entity\Package; use App\Entity\Version; +use Composer\Pcre\Preg; +use Composer\Repository\VersionCacheInterface; use Composer\Semver\VersionParser; class VersionCache implements VersionCacheInterface @@ -25,12 +25,12 @@ class VersionCache implements VersionCacheInterface /** * @param array $existingVersions - * @param string[] $emptyReferences + * @param string[] $emptyReferences */ public function __construct( private Package $package, array $existingVersions, - private array $emptyReferences + private array $emptyReferences, ) { foreach ($existingVersions as $version) { $this->versionCache[$version['version']] = $version; @@ -44,7 +44,7 @@ public function getVersionPackage(string $version, string $identifier): array|fa { if (!empty($this->versionCache[$version]['source']['reference']) && $this->versionCache[$version]['source']['reference'] === $identifier) { // if the source has some corrupted github private url we do not return a cached version to ensure full metadata gets loaded - if (isset($this->versionCache[$version]['source']['url']) && is_string($this->versionCache[$version]['source']['url']) && Preg::isMatch('{^git@github.com:.*?\.git$}', $this->versionCache[$version]['source']['url'])) { + if (isset($this->versionCache[$version]['source']['url']) && \is_string($this->versionCache[$version]['source']['url']) && Preg::isMatch('{^git@github.com:.*?\.git$}', $this->versionCache[$version]['source']['url'])) { return null; } @@ -56,7 +56,7 @@ public function getVersionPackage(string $version, string $identifier): array|fa ]; } - if (in_array($identifier, $this->emptyReferences, true)) { + if (\in_array($identifier, $this->emptyReferences, true)) { return false; } diff --git a/src/Twig/PackagistExtension.php b/src/Twig/PackagistExtension.php index 34d95bab58..7ee38f485b 100644 --- a/src/Twig/PackagistExtension.php +++ b/src/Twig/PackagistExtension.php @@ -71,7 +71,7 @@ public function getVendor(string $packageName): string public function numericTest(mixed $val): bool { - if (!is_string($val) && !is_int($val)) { + if (!\is_string($val) && !\is_int($val)) { return false; } @@ -80,7 +80,7 @@ public function numericTest(mixed $val): bool public function packageExistsTest(mixed $package): bool { - if (!is_string($package)) { + if (!\is_string($package)) { return false; } @@ -93,7 +93,7 @@ public function packageExistsTest(mixed $package): bool public function providerExistsTest(mixed $package): bool { - if (!is_string($package)) { + if (!\is_string($package)) { return false; } @@ -116,6 +116,7 @@ public function generateGravatarHash(string $email): string /** * @param PackageLink[] $links + * * @return PackageLink[] */ public function sortLinks(array $links): array diff --git a/src/Util/Killswitch.php b/src/Util/Killswitch.php index fa29975776..8191d89224 100644 --- a/src/Util/Killswitch.php +++ b/src/Util/Killswitch.php @@ -34,6 +34,7 @@ class Killswitch /** * Silly workaround to avoid phpstan reporting "this condition is always true/false" when using the constants directly + * * @param self::* $feature */ public static function isEnabled(bool $feature): bool diff --git a/src/Util/LoggingHttpDownloader.php b/src/Util/LoggingHttpDownloader.php index fb2b55c5ba..e680126b42 100644 --- a/src/Util/LoggingHttpDownloader.php +++ b/src/Util/LoggingHttpDownloader.php @@ -44,7 +44,7 @@ public function get($url, $options = []): Response if ($this->loadMinimalVersions && Preg::isMatch('{/(tags|git/refs/heads)(\?|$)}', $url)) { $reflProp = new \ReflectionProperty(Response::class, 'request'); $newBody = $result->decodeJson(); - $newBody = array_slice($newBody, 0, 1); + $newBody = \array_slice($newBody, 0, 1); $result = new Response($reflProp->getValue($result), $result->getStatusCode(), [], (string) json_encode($newBody)); } diff --git a/src/Util/UserAgentParser.php b/src/Util/UserAgentParser.php index 33d2ca4984..be074f9f51 100644 --- a/src/Util/UserAgentParser.php +++ b/src/Util/UserAgentParser.php @@ -30,8 +30,8 @@ public function __construct(?string $userAgent) $matches['composer'] = 'pre-1.8.5'; } $this->composerVersion = Preg::replace('{\+[a-f0-9]{40}}', '', $matches['composer']); - $this->phpVersion = (strtolower($matches['engine']) === 'hhvm' ? 'hhvm-' : '') . $matches['php']; - $this->platformPhpVersion = null !== $matches['platform_php'] ? (strtolower($matches['engine']) === 'hhvm' ? 'hhvm-' : '') . $matches['platform_php'] : null; + $this->phpVersion = (strtolower($matches['engine']) === 'hhvm' ? 'hhvm-' : '').$matches['php']; + $this->platformPhpVersion = null !== $matches['platform_php'] ? (strtolower($matches['engine']) === 'hhvm' ? 'hhvm-' : '').$matches['platform_php'] : null; $this->os = Preg::replace('{^cygwin_nt-.*}', 'cygwin', strtolower($matches['os'])); if (str_contains(strtolower((string) $matches['osversion']), 'microsoft')) { // likely WSL 1 e.g. version-Microsoft $this->os = 'wsl'; diff --git a/src/Validator/Copyright.php b/src/Validator/Copyright.php index a7f187f500..0c71e27865 100644 --- a/src/Validator/Copyright.php +++ b/src/Validator/Copyright.php @@ -12,10 +12,9 @@ namespace App\Validator; -use Attribute; use Symfony\Component\Validator\Constraint; -#[Attribute(Attribute::TARGET_CLASS)] +#[\Attribute(\Attribute::TARGET_CLASS)] class Copyright extends Constraint { public string $message = ''; diff --git a/src/Validator/CopyrightValidator.php b/src/Validator/CopyrightValidator.php index 069ceb1ade..939f55e79d 100644 --- a/src/Validator/CopyrightValidator.php +++ b/src/Validator/CopyrightValidator.php @@ -66,11 +66,11 @@ public function validate(mixed $value, Constraint $constraint): void } foreach ($copyrightWatches as $vendor => $config) { - if (in_array($value->getVendor(), $config['allow']) || !str_contains($value->getVendor(), $vendor)) { + if (\in_array($value->getVendor(), $config['allow']) || !str_contains($value->getVendor(), $vendor)) { continue; } - $message = (new Email()) + $message = new Email() ->subject('Packagist.org package submission notification: '.$value->getName().' contains '.$vendor.' in its vendor name') ->from(new Address($this->mailFromEmail)) ->to($config['email']) diff --git a/src/Validator/NotProhibitedPassword.php b/src/Validator/NotProhibitedPassword.php index e3d56f0ad8..60e0835581 100644 --- a/src/Validator/NotProhibitedPassword.php +++ b/src/Validator/NotProhibitedPassword.php @@ -12,10 +12,9 @@ namespace App\Validator; -use Attribute; use Symfony\Component\Validator\Constraint; -#[Attribute(Attribute::TARGET_CLASS)] +#[\Attribute(\Attribute::TARGET_CLASS)] class NotProhibitedPassword extends Constraint { public string $message = 'Password should not match your email or any of your names.'; diff --git a/src/Validator/NotProhibitedPasswordValidator.php b/src/Validator/NotProhibitedPasswordValidator.php index 96d39bb7bc..e78b0b9087 100644 --- a/src/Validator/NotProhibitedPasswordValidator.php +++ b/src/Validator/NotProhibitedPasswordValidator.php @@ -55,6 +55,5 @@ public function validate(mixed $value, Constraint $constraint): void return; } } - } } diff --git a/src/Validator/NotReservedWord.php b/src/Validator/NotReservedWord.php index bbbc23a821..a38f8707f9 100644 --- a/src/Validator/NotReservedWord.php +++ b/src/Validator/NotReservedWord.php @@ -12,10 +12,9 @@ namespace App\Validator; -use Attribute; use Symfony\Component\Validator\Constraint; -#[Attribute(Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_PROPERTY)] class NotReservedWord extends Constraint { public string $message = 'This is a reserved word.'; diff --git a/src/Validator/NotReservedWordValidator.php b/src/Validator/NotReservedWordValidator.php index 95b17deebc..9438472a81 100644 --- a/src/Validator/NotReservedWordValidator.php +++ b/src/Validator/NotReservedWordValidator.php @@ -24,7 +24,7 @@ public function validate(mixed $value, Constraint $constraint): void throw new UnexpectedTypeException($constraint, NotReservedWord::class); } - if (!is_string($value)) { + if (!\is_string($value)) { return; } @@ -44,6 +44,5 @@ public function validate(mixed $value, Constraint $constraint): void return; } } - } } diff --git a/src/Validator/Password.php b/src/Validator/Password.php index c6982393d1..8279e2c92e 100644 --- a/src/Validator/Password.php +++ b/src/Validator/Password.php @@ -12,11 +12,10 @@ namespace App\Validator; -use Attribute; -use Symfony\Component\Validator\Constraints\Compound; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Constraints\Compound; -#[Attribute(Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_PROPERTY)] class Password extends Compound { /** diff --git a/src/Validator/PopularPackageSafety.php b/src/Validator/PopularPackageSafety.php index 8e63d008e6..26da263ef7 100644 --- a/src/Validator/PopularPackageSafety.php +++ b/src/Validator/PopularPackageSafety.php @@ -12,10 +12,9 @@ namespace App\Validator; -use Attribute; use Symfony\Component\Validator\Constraint; -#[Attribute(Attribute::TARGET_CLASS)] +#[\Attribute(\Attribute::TARGET_CLASS)] class PopularPackageSafety extends Constraint { public string $message = 'This package is very popular and URL editing has been disabled for security reasons. Please add a note on the old repo pointing to the new one if possible then get in touch at contact@packagist.org so we can get it sorted.'; diff --git a/src/Validator/PopularPackageSafetyValidator.php b/src/Validator/PopularPackageSafetyValidator.php index d6e18761fc..2b09c14b06 100644 --- a/src/Validator/PopularPackageSafetyValidator.php +++ b/src/Validator/PopularPackageSafetyValidator.php @@ -55,14 +55,14 @@ public function validate(mixed $value, Constraint $constraint): void // bypass download check for some accounts which requested it $user = $this->security->getUser(); - if ($user instanceof User && in_array($user->getUsernameCanonical(), [''], true)) { + if ($user instanceof User && \in_array($user->getUsernameCanonical(), [''], true)) { return; } try { $downloads = $this->downloadManager->getTotalDownloads($value); } catch (ConnectionException $e) { - $downloads = PHP_INT_MAX; + $downloads = \PHP_INT_MAX; } // more than 50000 downloads = established package, do not allow editing URL anymore @@ -74,7 +74,7 @@ public function validate(mixed $value, Constraint $constraint): void /** @var Connection $conn */ $conn = $this->doctrine->getConnection(); $oldRemoteId = $conn->fetchOne('SELECT remoteId FROM package WHERE id = :id', ['id' => $value->getId()]); - if (is_string($oldRemoteId)) { + if (\is_string($oldRemoteId)) { if ($oldRemoteId === $value->getRemoteId()) { return; } diff --git a/src/Validator/TypoSquatters.php b/src/Validator/TypoSquatters.php index 97a2cf6111..ada7528cbc 100644 --- a/src/Validator/TypoSquatters.php +++ b/src/Validator/TypoSquatters.php @@ -12,10 +12,9 @@ namespace App\Validator; -use Attribute; use Symfony\Component\Validator\Constraint; -#[Attribute(Attribute::TARGET_CLASS)] +#[\Attribute(\Attribute::TARGET_CLASS)] class TypoSquatters extends Constraint { public string $message = 'Your package name "{{ name }}" is blocked as its name is too close to "{{ existing }}"'; diff --git a/src/Validator/TypoSquattersValidator.php b/src/Validator/TypoSquattersValidator.php index 053915957a..e49a418dde 100644 --- a/src/Validator/TypoSquattersValidator.php +++ b/src/Validator/TypoSquattersValidator.php @@ -16,12 +16,12 @@ use App\Model\DownloadManager; use App\Util\DoctrineTrait; use Doctrine\Persistence\ManagerRegistry; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; @@ -96,7 +96,7 @@ public function validate(mixed $value, Constraint $constraint): void $req = $this->requestStack->getMainRequest(); if ($req && $req->attributes->get('_route') !== 'submit.fetch_info') { - $message = (new Email()) + $message = new Email() ->subject($value->getName().' is suspiciously close to '.$existingPackage['name']) ->from(new Address($this->mailFromEmail)) ->to($this->mailFromEmail) diff --git a/src/Validator/UniquePackage.php b/src/Validator/UniquePackage.php index f9a5047cce..696223d9c1 100644 --- a/src/Validator/UniquePackage.php +++ b/src/Validator/UniquePackage.php @@ -12,10 +12,9 @@ namespace App\Validator; -use Attribute; use Symfony\Component\Validator\Constraint; -#[Attribute(Attribute::TARGET_CLASS)] +#[\Attribute(\Attribute::TARGET_CLASS)] class UniquePackage extends Constraint { public string $message = ''; diff --git a/src/Validator/ValidPackageRepository.php b/src/Validator/ValidPackageRepository.php index eec5d821f6..f6652e6cae 100644 --- a/src/Validator/ValidPackageRepository.php +++ b/src/Validator/ValidPackageRepository.php @@ -12,10 +12,9 @@ namespace App\Validator; -use Attribute; use Symfony\Component\Validator\Constraint; -#[Attribute(Attribute::TARGET_CLASS)] +#[\Attribute(\Attribute::TARGET_CLASS)] class ValidPackageRepository extends Constraint { public string $message = ''; diff --git a/src/Validator/ValidPackageRepositoryValidator.php b/src/Validator/ValidPackageRepositoryValidator.php index 4cc10b3900..edad606fa7 100644 --- a/src/Validator/ValidPackageRepositoryValidator.php +++ b/src/Validator/ValidPackageRepositoryValidator.php @@ -50,13 +50,13 @@ public function validate(mixed $value, Constraint $constraint): void } $driver = $value->vcsDriver; - if (!is_object($driver)) { + if (!\is_object($driver)) { if (Preg::isMatch('{^http://}', $value->getRepository())) { $this->addViolation('Non-secure HTTP URLs are not supported, make sure you use an HTTPS or SSH URL'); } elseif (Preg::isMatch('{https?://.+@}', $value->getRepository())) { $this->addViolation('URLs with user@host are not supported, use a read-only public URL'); - } elseif (is_string($value->vcsDriverError)) { - $this->addViolation('Uncaught Exception: '.htmlentities($value->vcsDriverError, ENT_COMPAT, 'utf-8')); + } elseif (\is_string($value->vcsDriverError)) { + $this->addViolation('Uncaught Exception: '.htmlentities($value->vcsDriverError, \ENT_COMPAT, 'utf-8')); } else { $this->addViolation('No valid/supported repository was found at the given URL'); } @@ -66,7 +66,7 @@ public function validate(mixed $value, Constraint $constraint): void try { $information = $driver->getComposerInformation($driver->getRootIdentifier()); - if (empty($information['name']) || !is_string($information['name'])) { + if (empty($information['name']) || !\is_string($information['name'])) { $this->addViolation('The package name was not found in the composer.json, make sure there is a name present.'); return; @@ -78,7 +78,7 @@ public function validate(mixed $value, Constraint $constraint): void return; } - $this->addViolation('We had problems parsing your composer.json file, the parser reports: '.htmlentities($e->getMessage(), ENT_COMPAT, 'utf-8')); + $this->addViolation('We had problems parsing your composer.json file, the parser reports: '.htmlentities($e->getMessage(), \ENT_COMPAT, 'utf-8')); return; } @@ -91,7 +91,7 @@ public function validate(mixed $value, Constraint $constraint): void $name = $value->getName(); if (!Preg::isMatch('{^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9]([_.-]?[a-z0-9]+)*$}iD', $name)) { - $this->addViolation('The package name '.htmlentities($name, ENT_COMPAT, 'utf-8').' is invalid, it should have a vendor name, a forward slash, and a package name. The vendor and package name can be words separated by -, . or _. The complete name should match "[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9]([_.-]?[a-z0-9]+)*".'); + $this->addViolation('The package name '.htmlentities($name, \ENT_COMPAT, 'utf-8').' is invalid, it should have a vendor name, a forward slash, and a package name. The vendor and package name can be words separated by -, . or _. The complete name should match "[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9]([_.-]?[a-z0-9]+)*".'); return; } @@ -101,7 +101,7 @@ public function validate(mixed $value, Constraint $constraint): void Preg::isMatch('{(free.*watch|watch.*free|(stream|online).*anschauver.*pelicula|ver.*completa|pelicula.*complet|season.*episode.*online|film.*(complet|entier)|(voir|regarder|guarda|assistir).*(film|complet)|full.*movie|online.*(free|tv|full.*hd)|(free|full|gratuit).*stream|movie.*free|free.*(movie|hack)|watch.*movie|watch.*full|generate.*resource|generate.*unlimited|hack.*coin|coin.*(hack|generat)|vbucks|hack.*cheat|hack.*generat|generat.*hack|hack.*unlimited|cheat.*(unlimited|generat)|(mod(?!ule|el)\b|cheat|apk).*(hack|cheat|mod(?!ule|el)\b)|hack.*(apk|mod(?!ule|el)|free|gold|gems|diamonds|coin)|putlocker|generat.*free|coins.*generat|(download|telecharg).*album|album.*(download|telecharg)|album.*(free|gratuit)|generat.*coins|unlimited.*coins|(fortnite|pubg|apex.*legend|t[1i]k.*t[o0]k).*(free|gratuit|generat|unlimited|coins|mobile|hack|follow))}i', str_replace(['.', '-'], '', $name)) && !Preg::isMatch('{^(modularavel|hexmode|calgamo|liberty_code(_module)?|dvi|thelia|clayfreeman|watchfulli|assaneonline|awema-pl|magemodules?|simplepleb|modullo|modernmt|modina|havefnubb|lucid-modules|codecomodo|modulith|cointavia|magento-hackathon|pragmatic-modules|pmpr|moderntribe|teamneusta|modelfox|yii2-module|chrisjenkinson|jsonphpmodifier|textmod|md-asifiqbal|modoo-id|modularthink)/}', $name) ) { - $this->addViolation('The package name '.htmlentities($name, ENT_COMPAT, 'utf-8').' is blocked, if you think this is a mistake please get in touch with us.'); + $this->addViolation('The package name '.htmlentities($name, \ENT_COMPAT, 'utf-8').' is blocked, if you think this is a mistake please get in touch with us.'); return; } @@ -110,29 +110,29 @@ public function validate(mixed $value, Constraint $constraint): void Preg::isMatchStrictGroups('{^([^/]*(symfony|packagist|composer)[^/]*)/}', $name, $match) && !$this->packageRepository->isVendorTaken($match[1]) ) { - $this->addViolation('The vendor name '.htmlentities($match[1], ENT_COMPAT, 'utf-8').' is blocked, if you think this is a mistake please get in touch with us.'); + $this->addViolation('The vendor name '.htmlentities($match[1], \ENT_COMPAT, 'utf-8').' is blocked, if you think this is a mistake please get in touch with us.'); return; } $reservedVendors = ['php', 'packagist', 'api', 'sdk', 'auth', 'openai', 'annotation', 'authentication', 'authorization', 'dependency', 'dependencies', 'kernel', 'mcp', 'namespace', 'namespaces', 'rfc', 'routing', 'standards', 'standard', 'token']; $bits = explode('/', strtolower($name)); - if (in_array($bits[0], $reservedVendors, true)) { - $this->addViolation('The vendor name '.htmlentities($bits[0], ENT_COMPAT, 'utf-8').' is reserved, please use another name or reach out to us if you have a legitimate use for it.'); + if (\in_array($bits[0], $reservedVendors, true)) { + $this->addViolation('The vendor name '.htmlentities($bits[0], \ENT_COMPAT, 'utf-8').' is reserved, please use another name or reach out to us if you have a legitimate use for it.'); return; } $reservedNames = ['nul', 'con', 'prn', 'aux', 'com1', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9', 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9']; $bits = explode('/', strtolower($name)); - if (in_array($bits[0], $reservedNames, true) || in_array($bits[1], $reservedNames, true)) { - $this->addViolation('The package name '.htmlentities($name, ENT_COMPAT, 'utf-8').' is reserved, package and vendor names can not match any of: '.implode(', ', $reservedNames).'.'); + if (\in_array($bits[0], $reservedNames, true) || \in_array($bits[1], $reservedNames, true)) { + $this->addViolation('The package name '.htmlentities($name, \ENT_COMPAT, 'utf-8').' is reserved, package and vendor names can not match any of: '.implode(', ', $reservedNames).'.'); return; } if (Preg::isMatch('{\.json$}', $name)) { - $this->addViolation('The package name '.htmlentities($name, ENT_COMPAT, 'utf-8').' is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead.'); + $this->addViolation('The package name '.htmlentities($name, \ENT_COMPAT, 'utf-8').' is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead.'); return; } @@ -141,7 +141,7 @@ public function validate(mixed $value, Constraint $constraint): void $suggestName = Preg::replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name); $suggestName = strtolower($suggestName); - $this->addViolation('The package name '.htmlentities($name, ENT_COMPAT, 'utf-8').' is invalid, it should not contain uppercase characters. We suggest using '.$suggestName.' instead.'); + $this->addViolation('The package name '.htmlentities($name, \ENT_COMPAT, 'utf-8').' is invalid, it should not contain uppercase characters. We suggest using '.$suggestName.' instead.'); return; } diff --git a/src/Validator/VendorWritable.php b/src/Validator/VendorWritable.php index 0b9c9fd85b..888d68a768 100644 --- a/src/Validator/VendorWritable.php +++ b/src/Validator/VendorWritable.php @@ -12,10 +12,9 @@ namespace App\Validator; -use Attribute; use Symfony\Component\Validator\Constraint; -#[Attribute(Attribute::TARGET_CLASS)] +#[\Attribute(\Attribute::TARGET_CLASS)] class VendorWritable extends Constraint { public string $message = ''; diff --git a/src/Validator/VendorWritableValidator.php b/src/Validator/VendorWritableValidator.php index f2f0685723..c54ac9897c 100644 --- a/src/Validator/VendorWritableValidator.php +++ b/src/Validator/VendorWritableValidator.php @@ -48,12 +48,12 @@ public function validate(mixed $value, Constraint $constraint): void $vendor = $value->getVendor(); if ($vendor && $this->packageRepository->isVendorTaken($vendor, $value->getMaintainers()->first() ?: null)) { $this->context->buildViolation('The vendor name "'.$vendor.'" was already claimed by someone else on Packagist.org. ' - . 'You may ask them to add your package and give you maintainership access. ' - . 'If they add you as a maintainer on any package in that vendor namespace, ' - . 'you will then be able to add new packages in that namespace. ' - . 'The packages already in that vendor namespace can be found at ' - . ''.$vendor.'.' - . 'If those packages belong to you but were submitted by someone else, you can contact us to resolve the issue.') + .'You may ask them to add your package and give you maintainership access. ' + .'If they add you as a maintainer on any package in that vendor namespace, ' + .'you will then be able to add new packages in that namespace. ' + .'The packages already in that vendor namespace can be found at ' + .''.$vendor.'.' + .'If those packages belong to you but were submitted by someone else, you can contact us to resolve the issue.') ->atPath('repository') ->addViolation() ; diff --git a/tests/Audit/PackageAuditRecordTest.php b/tests/Audit/PackageAuditRecordTest.php index 364a0297fc..1830c18f6d 100644 --- a/tests/Audit/PackageAuditRecordTest.php +++ b/tests/Audit/PackageAuditRecordTest.php @@ -13,14 +13,14 @@ namespace App\Tests\Controller; use App\Audit\AuditRecordType; +use App\Entity\Package; use Doctrine\DBAL\Connection; use Doctrine\Persistence\ManagerRegistry; -use App\Entity\Package; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; class PackageAuditRecordTest extends KernelTestCase { - public function setUp(): void + protected function setUp(): void { self::bootKernel(); static::getContainer()->get(Connection::class)->beginTransaction(); @@ -28,7 +28,7 @@ public function setUp(): void parent::setUp(); } - public function tearDown(): void + protected function tearDown(): void { static::getContainer()->get(Connection::class)->rollBack(); diff --git a/tests/Audit/VersionAuditRecordTest.php b/tests/Audit/VersionAuditRecordTest.php index 73f7c63c91..71ea8a956d 100644 --- a/tests/Audit/VersionAuditRecordTest.php +++ b/tests/Audit/VersionAuditRecordTest.php @@ -13,15 +13,15 @@ namespace App\Tests\Controller; use App\Audit\AuditRecordType; +use App\Entity\Package; use App\Entity\Version; use Doctrine\DBAL\Connection; use Doctrine\Persistence\ManagerRegistry; -use App\Entity\Package; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; class VersionAuditRecordTest extends KernelTestCase { - public function setUp(): void + protected function setUp(): void { self::bootKernel(); static::getContainer()->get(Connection::class)->beginTransaction(); @@ -29,7 +29,7 @@ public function setUp(): void parent::setUp(); } - public function tearDown(): void + protected function tearDown(): void { static::getContainer()->get(Connection::class)->rollBack(); diff --git a/tests/Controller/ApiControllerTest.php b/tests/Controller/ApiControllerTest.php index 4964e14ba5..d19f4586d9 100644 --- a/tests/Controller/ApiControllerTest.php +++ b/tests/Controller/ApiControllerTest.php @@ -175,7 +175,7 @@ public function testSecurityAdvisories(): void $this->client->request('GET', '/api/security-advisories/?packages[]=acme/package'); $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), $this->client->getResponse()->getContent()); - $content = json_decode($this->client->getResponse()->getContent(), true, flags: JSON_THROW_ON_ERROR); + $content = json_decode($this->client->getResponse()->getContent(), true, flags: \JSON_THROW_ON_ERROR); $this->assertArrayHasKey('acme/package', $content['advisories']); $this->assertCount(1, $content['advisories']['acme/package']); } diff --git a/tests/Controller/ChangePasswordControllerTest.php b/tests/Controller/ChangePasswordControllerTest.php index a81d40965d..8205694386 100644 --- a/tests/Controller/ChangePasswordControllerTest.php +++ b/tests/Controller/ChangePasswordControllerTest.php @@ -53,7 +53,7 @@ public function testChangePassword(string $newPassword, string $expectedResult): if ($expectedResult === 'prohibited-password-error') { $this->assertResponseStatusCodeSame(422); - $this->assertFormError((new NotProhibitedPassword)->message, 'change_password_form', $crawler); + $this->assertFormError(new NotProhibitedPassword()->message, 'change_password_form', $crawler); } } } diff --git a/tests/Controller/ControllerTestCase.php b/tests/Controller/ControllerTestCase.php index 3276097a82..887c127437 100644 --- a/tests/Controller/ControllerTestCase.php +++ b/tests/Controller/ControllerTestCase.php @@ -17,7 +17,6 @@ use Doctrine\DBAL\Connection; use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; -use ReflectionProperty; use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\DomCrawler\Crawler; @@ -26,7 +25,7 @@ class ControllerTestCase extends WebTestCase { protected KernelBrowser $client; - public function setUp(): void + protected function setUp(): void { $this->client = self::createClient(); $this->client->disableReboot(); // prevent reboot to keep the transaction @@ -36,7 +35,7 @@ public function setUp(): void parent::setUp(); } - public function tearDown(): void + protected function tearDown(): void { static::getContainer()->get(Connection::class)->rollBack(); @@ -50,10 +49,10 @@ public static function getEM(): EntityManagerInterface protected function assertFormError(string $message, string $formName, Crawler $crawler): void { - $formCrawler = $crawler->filter(sprintf('[name="%s"]', $formName)); + $formCrawler = $crawler->filter(\sprintf('[name="%s"]', $formName)); $this->assertCount( 1, - $formCrawler->filter('.alert-danger:contains("' . $message . '")'), + $formCrawler->filter('.alert-danger:contains("'.$message.'")'), $formCrawler->html()."\nShould find an .alert-danger within the form with the message: '$message'", ); } @@ -65,7 +64,7 @@ protected function store(array|object ...$objects): void { $em = $this->getEM(); foreach ($objects as $obj) { - if (is_array($obj)) { + if (\is_array($obj)) { foreach ($obj as $obj2) { $em->persist($obj2); } @@ -88,7 +87,7 @@ protected static function createPackage(string $name, string $repository, ?strin $package->setName($name); $package->setRemoteId($remoteId); - (new ReflectionProperty($package, 'repository'))->setValue($package, $repository); + new \ReflectionProperty($package, 'repository')->setValue($package, $repository); if (\count($maintainers) > 0) { foreach ($maintainers as $user) { $package->addMaintainer($user); diff --git a/tests/Controller/RegistrationControllerTest.php b/tests/Controller/RegistrationControllerTest.php index 68a58cfe04..d2fe0c1eac 100644 --- a/tests/Controller/RegistrationControllerTest.php +++ b/tests/Controller/RegistrationControllerTest.php @@ -36,7 +36,7 @@ public function testRegisterWithoutOAuth(): void $em = self::getEM(); $user = $em->getRepository(User::class)->findOneBy(['username' => 'max.example']); $this->assertInstanceOf(User::class, $user); - $this->assertSame('max@example.com', $user->getEmailCanonical(), "user email should have been canonicalized"); + $this->assertSame('max@example.com', $user->getEmailCanonical(), 'user email should have been canonicalized'); } #[TestWith(['max.example'])] @@ -57,6 +57,6 @@ public function testRegisterWithTooSimplePasswords(string $password): void $crawler = $this->client->submit($form); $this->assertResponseStatusCodeSame(422, 'Should be invalid because password is the same as email or username'); - $this->assertFormError((new NotProhibitedPassword)->message, 'registration_form', $crawler); + $this->assertFormError(new NotProhibitedPassword()->message, 'registration_form', $crawler); } } diff --git a/tests/Controller/ResetPasswordControllerTest.php b/tests/Controller/ResetPasswordControllerTest.php index e620beca69..cd74f5196c 100644 --- a/tests/Controller/ResetPasswordControllerTest.php +++ b/tests/Controller/ResetPasswordControllerTest.php @@ -25,7 +25,7 @@ public function testResetPassword(): void $user = $this->setupUserWithPasswordResetRequest(false); $oldPassword = $user->getPassword(); - $crawler = $this->client->request('GET', '/reset-password/reset/' . $user->getConfirmationToken()); + $crawler = $this->client->request('GET', '/reset-password/reset/'.$user->getConfirmationToken()); $this->assertResponseStatusCodeSame(200); $this->submitPasswordResetFormAndAsserStatusCode($crawler, 'new-password', 302); @@ -37,7 +37,7 @@ public function testResetPasswordWithTwoFactor(): void $user = $this->setupUserWithPasswordResetRequest(true); $oldPassword = $user->getPassword(); - $crawler = $this->client->request('GET', '/reset-password/reset/' . $user->getConfirmationToken()); + $crawler = $this->client->request('GET', '/reset-password/reset/'.$user->getConfirmationToken()); $this->assertResponseStatusCodeSame(200); $this->submitPasswordResetFormAndAsserStatusCode($crawler, 'new-password', 422); @@ -52,7 +52,7 @@ public function testResetPasswordToProhibited(): void $user = $this->setupUserWithPasswordResetRequest(false); $oldPassword = $user->getPassword(); - $crawler = $this->client->request('GET', '/reset-password/reset/' . $user->getConfirmationToken()); + $crawler = $this->client->request('GET', '/reset-password/reset/'.$user->getConfirmationToken()); $this->assertResponseStatusCodeSame(200); $this->submitPasswordResetFormAndAsserStatusCode($crawler, newPassword: $user->getEmail(), expectedStatusCode: 422); diff --git a/tests/Controller/UserControllerTest.php b/tests/Controller/UserControllerTest.php index 708a301007..5f36d8df05 100644 --- a/tests/Controller/UserControllerTest.php +++ b/tests/Controller/UserControllerTest.php @@ -24,7 +24,7 @@ public function testEnableTwoFactorCode(): void $this->client->loginUser($user); - $crawler = $this->client->request('GET', sprintf('/users/%s/2fa/enable', $user->getUsername())); + $crawler = $this->client->request('GET', \sprintf('/users/%s/2fa/enable', $user->getUsername())); $form = $crawler->selectButton('Enable Two-Factor Authentication')->form(); $form->setValues([ 'enable_two_factor_auth[code]' => 123456, diff --git a/tests/Controller/WebControllerTest.php b/tests/Controller/WebControllerTest.php index 79ea774546..e8213599e2 100644 --- a/tests/Controller/WebControllerTest.php +++ b/tests/Controller/WebControllerTest.php @@ -67,7 +67,7 @@ public function testSearchJsonWithQuery(): void $this->client->request('GET', '/search.json', ['q' => 'monolog']); static::assertResponseStatusCodeSame(200); - static::assertJsonStringEqualsJsonFile(__DIR__ . '/responses/search-with-query.json', $this->client->getResponse()->getContent()); + static::assertJsonStringEqualsJsonFile(__DIR__.'/responses/search-with-query.json', $this->client->getResponse()->getContent()); } public function testSearchJsonWithQueryAndTag(): void @@ -76,7 +76,7 @@ public function testSearchJsonWithQueryAndTag(): void $this->client->request('GET', '/search.json', ['q' => 'pro', 'tags' => 'testing']); static::assertResponseStatusCodeSame(200); - static::assertJsonStringEqualsJsonFile(__DIR__ . '/responses/search-with-query-tag.json', $this->client->getResponse()->getContent()); + static::assertJsonStringEqualsJsonFile(__DIR__.'/responses/search-with-query-tag.json', $this->client->getResponse()->getContent()); } public function testSearchJsonWithQueryAndTagsAndTypes(): void @@ -85,14 +85,14 @@ public function testSearchJsonWithQueryAndTagsAndTypes(): void $this->client->request('GET', '/search.json', ['q' => 'pro', 'tags' => ['testing', 'mock'], 'type' => 'library']); static::assertResponseStatusCodeSame(200); - static::assertJsonStringEqualsJsonFile(__DIR__ . '/responses/search-with-query-tags.json', $this->client->getResponse()->getContent()); + static::assertJsonStringEqualsJsonFile(__DIR__.'/responses/search-with-query-tags.json', $this->client->getResponse()->getContent()); } public function testPackages(): void { $this->initializePackages(); - //we expect at least one package + // we expect at least one package $crawler = $this->client->request('GET', '/explore/'); $this->assertGreaterThan(0, $crawler->filter('.packages-short li')->count()); } @@ -101,7 +101,7 @@ public function testPackage(): void { $this->initializePackages(); - //we expect package to be clickable and showing at least 'package' div + // we expect package to be clickable and showing at least 'package' div $crawler = $this->client->request('GET', '/packages/symfony/symfony'); $this->assertGreaterThan(0, $crawler->filter('.package')->count()); } diff --git a/tests/Entity/SecurityAdvisoryTest.php b/tests/Entity/SecurityAdvisoryTest.php index 27f8f10754..0904cdce8b 100644 --- a/tests/Entity/SecurityAdvisoryTest.php +++ b/tests/Entity/SecurityAdvisoryTest.php @@ -105,22 +105,22 @@ public function testStoreSeverity(): void $this->assertNull($advisory->getSeverity(), "FriendsOfPHP doesn't provide severity information"); $advisory->addSource($gitHubRemoteAdvisor->id, GitHubSecurityAdvisoriesSource::SOURCE_NAME, null); $advisory->updateAdvisory($this->generateGitHubAdvisory(Severity::HIGH)); - $this->assertSame(Severity::HIGH, $advisory->getSeverity(), "GitHub should update the advisory severity"); + $this->assertSame(Severity::HIGH, $advisory->getSeverity(), 'GitHub should update the advisory severity'); $this->assertSame(Severity::HIGH, $advisory->findSecurityAdvisorySource(GitHubSecurityAdvisoriesSource::SOURCE_NAME)?->getSeverity(), 'GitHub should update the source data'); $advisory->updateAdvisory($this->generateGitHubAdvisory(Severity::MEDIUM)); - $this->assertSame(Severity::MEDIUM, $advisory->getSeverity(), "GitHub should update the advisory severity"); + $this->assertSame(Severity::MEDIUM, $advisory->getSeverity(), 'GitHub should update the advisory severity'); $this->assertSame(Severity::MEDIUM, $advisory->findSecurityAdvisorySource(GitHubSecurityAdvisoriesSource::SOURCE_NAME)?->getSeverity(), 'GitHub should update the source data'); $advisory->updateAdvisory($friendsOfPhpRemoteAdvisory); $this->assertSame(Severity::MEDIUM, $advisory->getSeverity(), "FriendsOfPHP shouldn't reset the severity information"); $advisory->updateAdvisory($this->generateGitHubAdvisory(Severity::HIGH)); - $this->assertSame(Severity::HIGH, $advisory->getSeverity(), "GitHub should update the advisory severity"); + $this->assertSame(Severity::HIGH, $advisory->getSeverity(), 'GitHub should update the advisory severity'); $this->assertSame(Severity::HIGH, $advisory->findSecurityAdvisorySource(GitHubSecurityAdvisoriesSource::SOURCE_NAME)?->getSeverity(), 'GitHub should update the source data'); } - private function generateGitHubAdvisory(Severity|null $severity): RemoteSecurityAdvisory + private function generateGitHubAdvisory(?Severity $severity): RemoteSecurityAdvisory { return new RemoteSecurityAdvisory( 'GHSA-1234-1234-1234', @@ -139,7 +139,7 @@ private function generateGitHubAdvisory(Severity|null $severity): RemoteSecurity private function generateFriendsOfPhpRemoteAdvisory(string $title, string $link, string $cve): RemoteSecurityAdvisory { - return RemoteSecurityAdvisory::createFromFriendsOfPhp(sprintf('symfony/framework-bundle/%s.yaml', $cve), [ + return RemoteSecurityAdvisory::createFromFriendsOfPhp(\sprintf('symfony/framework-bundle/%s.yaml', $cve), [ 'title' => $title, 'link' => $link, 'cve' => $cve, diff --git a/tests/Mock/TotpAuthenticatorStub.php b/tests/Mock/TotpAuthenticatorStub.php index 67ea8bd886..c08d31c2ec 100644 --- a/tests/Mock/TotpAuthenticatorStub.php +++ b/tests/Mock/TotpAuthenticatorStub.php @@ -12,10 +12,10 @@ namespace App\Tests\Mock; +use ParagonIE\ConstantTime\Base32; use Scheb\TwoFactorBundle\Model\Totp\TwoFactorInterface; use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Totp\TotpAuthenticatorInterface; use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Totp\TotpFactory; -use ParagonIE\ConstantTime\Base32; class TotpAuthenticatorStub implements TotpAuthenticatorInterface { diff --git a/tests/Model/PackageManagerTest.php b/tests/Model/PackageManagerTest.php index d8d4d0fff4..acfa944e79 100644 --- a/tests/Model/PackageManagerTest.php +++ b/tests/Model/PackageManagerTest.php @@ -23,10 +23,10 @@ public function testNotifyFailure(): void $client = self::createClient(); - $package = new Package; + $package = new Package(); $package->setRepository($url); - $user = new User; + $user = new User(); $user->addPackage($package); $repo = $this->createMock('App\Entity\UserRepository'); @@ -36,7 +36,7 @@ public function testNotifyFailure(): void $repo->expects($this->once()) ->method('findOneBy') ->with($this->equalTo(['username' => 'test', 'apiToken' => 'token'])) - ->will($this->returnValue($user)); + ->willReturn($user); static::$kernel->getContainer()->set('test.user_repo', $repo); static::$kernel->getContainer()->set('doctrine.orm.entity_manager', $em); diff --git a/tests/Package/SymlinkDumperTest.php b/tests/Package/SymlinkDumperTest.php index 3bb4d37b9f..f44bf75632 100644 --- a/tests/Package/SymlinkDumperTest.php +++ b/tests/Package/SymlinkDumperTest.php @@ -12,20 +12,20 @@ namespace App\Tests\Package; +use App\Package\SymlinkDumper; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -use App\Package\SymlinkDumper; class SymlinkDumperTest extends TestCase { private $mockDumper; - public function setUp(): void + protected function setUp(): void { $this->mockDumper = $this->createMock(SymlinkDumper::class); } - public function tearDown(): void + protected function tearDown(): void { $this->mockDumper = null; } @@ -87,7 +87,7 @@ private static function invoke($object, $method): mixed { $refl = new \ReflectionMethod($object, $method); - $args = func_get_args(); + $args = \func_get_args(); array_shift($args); // object array_shift($args); // method diff --git a/tests/Package/UpdaterTest.php b/tests/Package/UpdaterTest.php index 910b7f73e8..32c172d053 100644 --- a/tests/Package/UpdaterTest.php +++ b/tests/Package/UpdaterTest.php @@ -14,6 +14,12 @@ use App\Entity\Dependent; use App\Entity\DependentRepository; +use App\Entity\Package; +use App\Entity\Version; +use App\Entity\VersionRepository; +use App\Model\ProviderManager; +use App\Model\VersionIdCache; +use App\Package\Updater; use Composer\Config; use Composer\IO\IOInterface; use Composer\IO\NullIO; @@ -23,14 +29,8 @@ use Composer\Repository\Vcs\VcsDriverInterface; use Composer\Repository\VcsRepository; use Doctrine\Bundle\DoctrineBundle\Registry; -use Doctrine\ORM\EntityManager; use Doctrine\DBAL\Connection; -use App\Entity\Package; -use App\Entity\Version; -use App\Package\Updater; -use App\Entity\VersionRepository; -use App\Model\ProviderManager; -use App\Model\VersionIdCache; +use Doctrine\ORM\EntityManager; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\MailerInterface; @@ -52,8 +52,8 @@ protected function setUp(): void $this->config = new Config(); $this->package = new Package(); $this->package->setName('test/pkg'); - (new \ReflectionProperty($this->package, 'repository'))->setValue($this->package, 'https://example.com/test/pkg'); - (new \ReflectionProperty($this->package, 'id'))->setValue($this->package, 1); + new \ReflectionProperty($this->package, 'repository')->setValue($this->package, 'https://example.com/test/pkg'); + new \ReflectionProperty($this->package, 'id')->setValue($this->package, 1); $this->ioMock = $this->createMock(NullIO::class); $this->repositoryMock = $this->createMock(VcsRepository::class); @@ -92,7 +92,7 @@ protected function setUp(): void $this->updater = new Updater($registryMock, $providerManagerMock, $versionIdCache, $mailerMock, 'foo@example.org', $routerMock); } - public function tearDown(): void + protected function tearDown(): void { parent::tearDown(); unset($this->updater); @@ -114,24 +114,24 @@ public function testUpdatesTheReadme(): void public function testConvertsMarkdownForReadme(): void { $readme = <<Why you should use this package:

-
    -
  • it is easy to use
  • -
  • no overhead
  • -
  • minimal requirements
  • -
+

Why you should use this package:

+
    +
  • it is easy to use
  • +
  • no overhead
  • +
  • minimal requirements
  • +
-EOR; + EOR; $this->driverMock->expects($this->any())->method('getRootIdentifier')->willReturn('master'); $this->driverMock->expects($this->any())->method('getComposerInformation') @@ -151,16 +151,16 @@ public function testConvertsMarkdownForReadme(): void public function testNoUsefulTitlesAreRemovedForReadme(): void { $readme = <<Lorem ipsum dolor sit amet.

-

some title

+

Lorem ipsum dolor sit amet.

+

some title

-EOR; + EOR; $this->driverMock->expects($this->any())->method('getRootIdentifier')->willReturn('master'); $this->driverMock->expects($this->any())->method('getComposerInformation') @@ -202,127 +202,126 @@ public function testUnderstandsDifferentFileNames(): void public function testReadmeParsing(): void { $readme = <<<'SOURCE' -

PROJECT NAME

Fork CMS

-

Build Status -Latest Stable Version -License -Code Coverage -Documentation Status -huntr.dev | the place to protect open source

-

Installation

-
    -
  1. ⚠️ Test Emoji Make sure you have composer installed.
  2. -
  3. Run composer create-project forkcms/forkcms . in your document root.
  4. -
  5. Browse to your website
  6. -
  7. Follow the steps on-screen
  8. -
  9. Have fun!
  10. -
-

Dependencies

-

Remark: If you are using GIT instead of composer create-project or the zip-file from http://www.fork-cms.com, you -should install our dependencies. The dependencies are handled by composer

-

To install the dependencies, you can run the command below in the document-root:

-
composer install -o
-
-

Security

-

If you discover any security-related issues, please email core@fork-cms.com instead of using the issue tracker. -HTML is allowed in translations because you sometimes need it. Any reports regarding this will not be accepted as a security issue. Owners of a website can narrow down who can add/edit translation strings using the group permissions.

-

Bugs

-

If you encounter any bugs, please create an issue on Github. -If you're stuck or would like to discuss Fork CMS: Join our Slack channel Join our Slack Channel!

-

Running the tests

-

We use phpunit as a test framework. It's installed when using composer install. -To be able to run them, make sure you have a database with the same credentials as -your normal database and with the name suffixed with _test.

-

Because we support multiple php versions it gave some issues. Therefore we use the bridge from symfony.

-

Running the tests:

-
composer test
-
-

Running only the unit, functional, or the installer tests

-
 composer test -- --testsuite=functional
- composer test -- --testsuite=unit
- composer test -- --testsuite=installer
-
-

If you want to run all the tests except the ones from the installer use

-
composer test -- --exclude-group=installer
-
-

Styling the backend

-

The backend uses Bootstrap in combination with Sass. To make changes, you should make -the changes into the scss-files, and regenerate the real css with gulp build.

-

Yarn

-

We use yarn to install our dependencies. For now we have a gulp-script that moves everything to -the correct directories. So if you change the dependencies, make sure you run gulp build.

-

Community

-

Join our Slack channel Join our Slack Channel!

-

The Fork CMS team

- - - -
-SOURCE; +

PROJECT NAME

Fork CMS

+

Build Status + Latest Stable Version + License + Code Coverage + Documentation Status + huntr.dev | the place to protect open source

+

Installation

+
    +
  1. ⚠️ Test Emoji Make sure you have composer installed.
  2. +
  3. Run composer create-project forkcms/forkcms . in your document root.
  4. +
  5. Browse to your website
  6. +
  7. Follow the steps on-screen
  8. +
  9. Have fun!
  10. +
+

Dependencies

+

Remark: If you are using GIT instead of composer create-project or the zip-file from http://www.fork-cms.com, you + should install our dependencies. The dependencies are handled by composer

+

To install the dependencies, you can run the command below in the document-root:

+
composer install -o
+            
+

Security

+

If you discover any security-related issues, please email core@fork-cms.com instead of using the issue tracker. + HTML is allowed in translations because you sometimes need it. Any reports regarding this will not be accepted as a security issue. Owners of a website can narrow down who can add/edit translation strings using the group permissions.

+

Bugs

+

If you encounter any bugs, please create an issue on Github. + If you're stuck or would like to discuss Fork CMS: Join our Slack channel Join our Slack Channel!

+

Running the tests

+

We use phpunit as a test framework. It's installed when using composer install. + To be able to run them, make sure you have a database with the same credentials as + your normal database and with the name suffixed with _test.

+

Because we support multiple php versions it gave some issues. Therefore we use the bridge from symfony.

+

Running the tests:

+
composer test
+            
+

Running only the unit, functional, or the installer tests

+
 composer test -- --testsuite=functional
+             composer test -- --testsuite=unit
+             composer test -- --testsuite=installer
+            
+

If you want to run all the tests except the ones from the installer use

+
composer test -- --exclude-group=installer
+            
+

Styling the backend

+

The backend uses Bootstrap in combination with Sass. To make changes, you should make + the changes into the scss-files, and regenerate the real css with gulp build.

+

Yarn

+

We use yarn to install our dependencies. For now we have a gulp-script that moves everything to + the correct directories. So if you change the dependencies, make sure you run gulp build.

+

Community

+

Join our Slack channel Join our Slack Channel!

+

The Fork CMS team

+ + + +
+ SOURCE; $reflMethod = new \ReflectionMethod($this->updater, 'prepareReadme'); $readme = $reflMethod->invoke($this->updater, $readme, 'github.com', 'foo', 'bar'); self::assertSame(<<<'EXPECTED' -

Fork CMS

-

Build Status -Latest Stable Version -License -Code Coverage -Documentation Status -huntr.dev | the place to protect open source

-

Installation

-
    -
  1. ⚠️ Test Emoji Make sure you have composer installed.
  2. -
  3. Run composer create-project forkcms/forkcms . in your document root.
  4. -
  5. Browse to your website
  6. -
  7. Follow the steps on-screen
  8. -
  9. Have fun!
  10. -
-

Dependencies

-

Remark: If you are using GIT instead of composer create-project or the zip-file from http://www.fork-cms.com, you -should install our dependencies. The dependencies are handled by composer

-

To install the dependencies, you can run the command below in the document-root:

-
composer install -o
-
-

Security

-

If you discover any security-related issues, please email core@fork-cms.com instead of using the issue tracker. -HTML is allowed in translations because you sometimes need it. Any reports regarding this will not be accepted as a security issue. Owners of a website can narrow down who can add/edit translation strings using the group permissions.

-

Bugs

-

If you encounter any bugs, please create an issue on Github. -If you're stuck or would like to discuss Fork CMS: Join our Slack channel Join our Slack Channel!

-

Running the tests

-

We use phpunit as a test framework. It's installed when using composer install. -To be able to run them, make sure you have a database with the same credentials as -your normal database and with the name suffixed with _test.

-

Because we support multiple php versions it gave some issues. Therefore we use the bridge from symfony.

-

Running the tests:

-
composer test
-
-

Running only the unit, functional, or the installer tests

-
 composer test -- --testsuite=functional
- composer test -- --testsuite=unit
- composer test -- --testsuite=installer
-
-

If you want to run all the tests except the ones from the installer use

-
composer test -- --exclude-group=installer
-
-

Styling the backend

-

The backend uses Bootstrap in combination with Sass. To make changes, you should make -the changes into the scss-files, and regenerate the real css with gulp build.

-

Yarn

-

We use yarn to install our dependencies. For now we have a gulp-script that moves everything to -the correct directories. So if you change the dependencies, make sure you run gulp build.

-

Community

-

Join our Slack channel Join our Slack Channel!

-

The Fork CMS team

- - - - -EXPECTED - , $readme); +

Fork CMS

+

Build Status + Latest Stable Version + License + Code Coverage + Documentation Status + huntr.dev | the place to protect open source

+

Installation

+
    +
  1. ⚠️ Test Emoji Make sure you have composer installed.
  2. +
  3. Run composer create-project forkcms/forkcms . in your document root.
  4. +
  5. Browse to your website
  6. +
  7. Follow the steps on-screen
  8. +
  9. Have fun!
  10. +
+

Dependencies

+

Remark: If you are using GIT instead of composer create-project or the zip-file from http://www.fork-cms.com, you + should install our dependencies. The dependencies are handled by composer

+

To install the dependencies, you can run the command below in the document-root:

+
composer install -o
+            
+

Security

+

If you discover any security-related issues, please email core@fork-cms.com instead of using the issue tracker. + HTML is allowed in translations because you sometimes need it. Any reports regarding this will not be accepted as a security issue. Owners of a website can narrow down who can add/edit translation strings using the group permissions.

+

Bugs

+

If you encounter any bugs, please create an issue on Github. + If you're stuck or would like to discuss Fork CMS: Join our Slack channel Join our Slack Channel!

+

Running the tests

+

We use phpunit as a test framework. It's installed when using composer install. + To be able to run them, make sure you have a database with the same credentials as + your normal database and with the name suffixed with _test.

+

Because we support multiple php versions it gave some issues. Therefore we use the bridge from symfony.

+

Running the tests:

+
composer test
+            
+

Running only the unit, functional, or the installer tests

+
 composer test -- --testsuite=functional
+             composer test -- --testsuite=unit
+             composer test -- --testsuite=installer
+            
+

If you want to run all the tests except the ones from the installer use

+
composer test -- --exclude-group=installer
+            
+

Styling the backend

+

The backend uses Bootstrap in combination with Sass. To make changes, you should make + the changes into the scss-files, and regenerate the real css with gulp build.

+

Yarn

+

We use yarn to install our dependencies. For now we have a gulp-script that moves everything to + the correct directories. So if you change the dependencies, make sure you run gulp build.

+

Community

+

Join our Slack channel Join our Slack Channel!

+

The Fork CMS team

+ + + + + EXPECTED, $readme); } } diff --git a/tests/Search/AlgoliaMock.php b/tests/Search/AlgoliaMock.php index 8b91dda4b7..50faef5b7b 100644 --- a/tests/Search/AlgoliaMock.php +++ b/tests/Search/AlgoliaMock.php @@ -24,7 +24,7 @@ final class AlgoliaMock extends SearchClient public static function setup(KernelBrowser $client, Query $query, string $resultName): self { - $mock = (new \ReflectionClass(__CLASS__))->newInstanceWithoutConstructor(); + $mock = new \ReflectionClass(__CLASS__)->newInstanceWithoutConstructor(); $mock->query = $query; if (false === $result = @include __DIR__.'/results/'.$resultName.'.php') { @@ -51,7 +51,7 @@ public function initIndex($indexName): self */ public function search($query, $requestOptions = []): array { - $queryMessage = sprintf('AlgoliaMock expected query string \'%s\', but got \'%s\'.', $this->query->query, $query); + $queryMessage = \sprintf('AlgoliaMock expected query string \'%s\', but got \'%s\'.', $this->query->query, $query); Assert::assertSame($this->query->query, $query, $queryMessage); Assert::assertSame($this->query->getOptions(), $requestOptions, 'AlgoliaMock expected different request options.'); diff --git a/tests/Security/BruteForceLoginFormAuthenticatorTest.php b/tests/Security/BruteForceLoginFormAuthenticatorTest.php index 8a25b41703..c6b510cb91 100644 --- a/tests/Security/BruteForceLoginFormAuthenticatorTest.php +++ b/tests/Security/BruteForceLoginFormAuthenticatorTest.php @@ -12,9 +12,9 @@ namespace App\Tests\Security; -use Beelab\Recaptcha2Bundle\Recaptcha\RecaptchaVerifier; use App\Security\BruteForceLoginFormAuthenticator; use App\Security\RecaptchaHelper; +use Beelab\Recaptcha2Bundle\Recaptcha\RecaptchaVerifier; use Doctrine\Persistence\ManagerRegistry; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; diff --git a/tests/SecurityAdvisory/GitHubSecurityAdvisoriesSourceTest.php b/tests/SecurityAdvisory/GitHubSecurityAdvisoriesSourceTest.php index 3ff2ddf55c..f44e2331ed 100644 --- a/tests/SecurityAdvisory/GitHubSecurityAdvisoriesSourceTest.php +++ b/tests/SecurityAdvisory/GitHubSecurityAdvisoriesSourceTest.php @@ -246,7 +246,7 @@ private function graphQlPackageNode(string $advisoryId, string $packageName, str return [ 'advisory' => [ 'summary' => $summary, - 'permalink' => 'https://github.com/advisories/' . $advisoryId, + 'permalink' => 'https://github.com/advisories/'.$advisoryId, 'publishedAt' => $publishedAt, 'withdrawnAt' => null, 'severity' => 'MODERATE', diff --git a/tests/SecurityAdvisory/RemoteSecurityAdvisoryTest.php b/tests/SecurityAdvisory/RemoteSecurityAdvisoryTest.php index 6ec1dd0f8c..a04eff030e 100644 --- a/tests/SecurityAdvisory/RemoteSecurityAdvisoryTest.php +++ b/tests/SecurityAdvisory/RemoteSecurityAdvisoryTest.php @@ -55,7 +55,6 @@ public function testCreateFromFriendsOfPhpOnlyYearAvailable(): void 'time' => null, 'versions' => ['<1.7.2'], ], - ], 'reference' => 'composer://erusev/parsedown', ]); @@ -74,7 +73,6 @@ public function testCreateFromFriendsOfPhpOnlyYearButBranchDatesAvailable(): voi 'time' => 1570492800, 'versions' => ['>=1', '<1.14.4.3'], ], - ], 'reference' => 'composer://magento/magento1ee', 'composer-repository' => false, diff --git a/tests/SecurityAdvisoryWorkerTest.php b/tests/SecurityAdvisoryWorkerTest.php index 8db9f8561d..51e6820e62 100644 --- a/tests/SecurityAdvisoryWorkerTest.php +++ b/tests/SecurityAdvisoryWorkerTest.php @@ -12,26 +12,26 @@ namespace App\Tests; +use App\Entity\Job; use App\Entity\Package; +use App\Entity\SecurityAdvisory; use App\Entity\SecurityAdvisoryRepository; use App\EventListener\SecurityAdvisoryUpdateListener; +use App\SecurityAdvisory\RemoteSecurityAdvisory; use App\SecurityAdvisory\RemoteSecurityAdvisoryCollection; use App\SecurityAdvisory\SecurityAdvisoryResolver; -use Doctrine\DBAL\Connection; -use Doctrine\ORM\EntityManager; -use Doctrine\ORM\EntityRepository; -use App\Entity\Job; -use App\Entity\SecurityAdvisory; -use App\SecurityAdvisory\RemoteSecurityAdvisory; use App\SecurityAdvisory\SecurityAdvisorySourceInterface; use App\Service\Locker; use App\Service\SecurityAdvisoryWorker; +use Doctrine\DBAL\Connection; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityRepository; +use Doctrine\Persistence\ManagerRegistry; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Predis\Client; use Psr\Log\NullLogger; use Seld\Signal\SignalHandler; -use Doctrine\Persistence\ManagerRegistry; class SecurityAdvisoryWorkerTest extends TestCase { @@ -170,10 +170,10 @@ private function createRemoteAdvisory(string $packageName, string $remoteId): Re { return new RemoteSecurityAdvisory( $remoteId, - 'Advisory' . $packageName, + 'Advisory'.$packageName, $packageName, '^1.0', - 'https://example/' . $packageName, + 'https://example/'.$packageName, null, new \DateTimeImmutable(), null, diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 0c9737854b..6d95f49c2a 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -17,14 +17,14 @@ if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) { require dirname(__DIR__).'/config/bootstrap.php'; } elseif (method_exists(Dotenv::class, 'bootEnv')) { - (new Dotenv())->bootEnv(dirname(__DIR__).'/.env'); + new Dotenv()->bootEnv(dirname(__DIR__).'/.env'); } // hack for PHPUnit 11, see https://github.com/symfony/symfony/issues/53812 set_exception_handler([new Symfony\Component\ErrorHandler\ErrorHandler(), 'handleException']); if ($_SERVER['APP_DEBUG']) { - umask(0000); + umask(0o000); } /** @@ -32,7 +32,7 @@ * * @param string $command a command to execute * - * @throws Exception when the return code is not 0. + * @throws Exception when the return code is not 0 */ function executeCommand(string $command, bool $errorHandling = true): void { @@ -43,18 +43,12 @@ function executeCommand(string $command, bool $errorHandling = true): void exec($command, $output, $returnCode); if ($errorHandling && $returnCode !== 0) { - throw new Exception( - sprintf( - 'Error executing command "%s", return code was "%s".', - $command, - $returnCode - ) - ); + throw new Exception(sprintf('Error executing command "%s", return code was "%s".', $command, $returnCode)); } } if (!getenv('QUICK')) { - echo 'For quicker test runs without a fresh DB schema, prefix the test command with a QUICK=1 env var.' . PHP_EOL; + echo 'For quicker test runs without a fresh DB schema, prefix the test command with a QUICK=1 env var.'.\PHP_EOL; executeCommand('php ./bin/console doctrine:database:drop --env=test --force -q', false); executeCommand('php ./bin/console doctrine:database:create --env=test -q'); diff --git a/tests/console-application.php b/tests/console-application.php index 339063b0c8..841bf15d1e 100644 --- a/tests/console-application.php +++ b/tests/console-application.php @@ -14,9 +14,9 @@ use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Component\Dotenv\Dotenv; -require __DIR__ . '/../vendor/autoload.php'; +require __DIR__.'/../vendor/autoload.php'; -(new Dotenv())->bootEnv(__DIR__ . '/../.env'); +new Dotenv()->bootEnv(__DIR__.'/../.env'); $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); diff --git a/tests/object-manager.php b/tests/object-manager.php index 45c09779f5..158f829f70 100644 --- a/tests/object-manager.php +++ b/tests/object-manager.php @@ -13,9 +13,9 @@ use App\Kernel; use Symfony\Component\Dotenv\Dotenv; -require __DIR__ . '/../vendor/autoload.php'; +require __DIR__.'/../vendor/autoload.php'; -(new Dotenv())->bootEnv(__DIR__ . '/../.env'); +new Dotenv()->bootEnv(__DIR__.'/../.env'); $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); $kernel->boot();