Fix Psalm issues

This commit is contained in:
Sebastian Meyer 2024-07-13 21:37:20 +02:00
parent b3585777a4
commit c6193ede07
13 changed files with 164 additions and 304 deletions

View File

@ -32,7 +32,7 @@
"ext-libxml": "*",
"ext-sqlite3": "*",
"doctrine/dbal": "^3.8",
"doctrine/orm": "^2.19",
"doctrine/orm": "^3.2",
"opencultureconsulting/basics": "^1.1",
"opencultureconsulting/psr15": "^1.0",
"symfony/cache": "^6.4",
@ -97,6 +97,9 @@
],
"psalm:check": [
"@php vendor/bin/psalm"
],
"psalm:check-security": [
"@php vendor/bin/psalm --taint-analysis"
]
},
"scripts-descriptions": {
@ -107,6 +110,7 @@
"phpcs:check": "Runs a code check with PHP_CodeSniffer and reports problems. If a custom configuration file '.phpcs.xml' exists, it will be used instead of the default settings in '.phpcs.xml.dist'.",
"phpdoc:build": "Builds the documentation from source files in ./src and additional templates in .phpdoc/. If a custom configuration file 'phpdoc.xml' exists, it will be used instead of the default settings in 'phpdoc.dist.xml'.",
"phpstan:check": "Runs a code check with PHPStan static code analyzer and reports problems. If a custom configuration file 'phpstan.neon' exists, it will be used instead of the default settings in 'phpstan.dist.neon'.",
"psalm:check": "Runs a code check with Psalm static code analyzer and reports problems. If a custom configuration file 'psalm.xml' exists, it will be used instead of the default settings in 'psalm.xml.dist'."
"psalm:check": "Runs a code check with Psalm static code analyzer and reports problems. If a custom configuration file 'psalm.xml' exists, it will be used instead of the default settings in 'psalm.xml.dist'.",
"psalm:check-security": "Runs a code check with Psalm static code analyzer and reports security issues. If a custom configuration file 'psalm.xml' exists, it will be used instead of the default settings in 'psalm.xml.dist'."
}
}

379
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f2f983ef97bc36ea0dea83537e3affce",
"content-hash": "8fbabb7463378ac73b62ab40c5f50b20",
"packages": [
{
"name": "doctrine/cache",
@ -185,97 +185,6 @@
],
"time": "2024-04-18T06:56:21+00:00"
},
{
"name": "doctrine/common",
"version": "3.4.4",
"source": {
"type": "git",
"url": "https://github.com/doctrine/common.git",
"reference": "0aad4b7ab7ce8c6602dfbb1e1a24581275fb9d1a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/common/zipball/0aad4b7ab7ce8c6602dfbb1e1a24581275fb9d1a",
"reference": "0aad4b7ab7ce8c6602dfbb1e1a24581275fb9d1a",
"shasum": ""
},
"require": {
"doctrine/persistence": "^2.0 || ^3.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9.0 || ^10.0",
"doctrine/collections": "^1",
"phpstan/phpstan": "^1.4.1",
"phpstan/phpstan-phpunit": "^1",
"phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0",
"squizlabs/php_codesniffer": "^3.0",
"symfony/phpunit-bridge": "^6.1",
"vimeo/psalm": "^4.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
},
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.",
"homepage": "https://www.doctrine-project.org/projects/common.html",
"keywords": [
"common",
"doctrine",
"php"
],
"support": {
"issues": "https://github.com/doctrine/common/issues",
"source": "https://github.com/doctrine/common/tree/3.4.4"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcommon",
"type": "tidelift"
}
],
"time": "2024-04-16T13:35:33+00:00"
},
{
"name": "doctrine/dbal",
"version": "3.8.6",
@ -767,61 +676,48 @@
},
{
"name": "doctrine/orm",
"version": "2.19.6",
"version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/orm.git",
"reference": "c1bb2ccf4b19c845f91ff7c4c01dc7cbba7f4073"
"reference": "722cea6536775206e81744542b36fa7c9a4ea3e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/orm/zipball/c1bb2ccf4b19c845f91ff7c4c01dc7cbba7f4073",
"reference": "c1bb2ccf4b19c845f91ff7c4c01dc7cbba7f4073",
"url": "https://api.github.com/repos/doctrine/orm/zipball/722cea6536775206e81744542b36fa7c9a4ea3e5",
"reference": "722cea6536775206e81744542b36fa7c9a4ea3e5",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2",
"doctrine/cache": "^1.12.1 || ^2.1.1",
"doctrine/collections": "^1.5 || ^2.1",
"doctrine/common": "^3.0.3",
"doctrine/dbal": "^2.13.1 || ^3.2",
"doctrine/collections": "^2.2",
"doctrine/dbal": "^3.8.2 || ^4",
"doctrine/deprecations": "^0.5.3 || ^1",
"doctrine/event-manager": "^1.2 || ^2",
"doctrine/inflector": "^1.4 || ^2.0",
"doctrine/instantiator": "^1.3 || ^2",
"doctrine/lexer": "^2 || ^3",
"doctrine/persistence": "^2.4 || ^3",
"doctrine/lexer": "^3",
"doctrine/persistence": "^3.3.1",
"ext-ctype": "*",
"php": "^7.1 || ^8.0",
"php": "^8.1",
"psr/cache": "^1 || ^2 || ^3",
"symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0",
"symfony/polyfill-php72": "^1.23",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"doctrine/annotations": "<1.13 || >= 3.0"
"symfony/console": "^5.4 || ^6.0 || ^7.0",
"symfony/var-exporter": "^6.3.9 || ^7.0"
},
"require-dev": {
"doctrine/annotations": "^1.13 || ^2",
"doctrine/coding-standard": "^9.0.2 || ^12.0",
"phpbench/phpbench": "^0.16.10 || ^1.0",
"phpstan/phpstan": "~1.4.10 || 1.11.1",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
"doctrine/coding-standard": "^12.0",
"phpbench/phpbench": "^1.0",
"phpstan/phpstan": "1.11.1",
"phpunit/phpunit": "^10.4.0",
"psr/log": "^1 || ^2 || ^3",
"squizlabs/php_codesniffer": "3.7.2",
"symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0",
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0",
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0",
"vimeo/psalm": "4.30.0 || 5.24.0"
"symfony/cache": "^5.4 || ^6.2 || ^7.0",
"vimeo/psalm": "5.24.0"
},
"suggest": {
"ext-dom": "Provides support for XSD validation for XML mapping files",
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0",
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0"
},
"bin": [
"bin/doctrine"
],
"type": "library",
"autoload": {
"psr-4": {
@ -862,9 +758,9 @@
],
"support": {
"issues": "https://github.com/doctrine/orm/issues",
"source": "https://github.com/doctrine/orm/tree/2.19.6"
"source": "https://github.com/doctrine/orm/tree/3.2.1"
},
"time": "2024-06-26T17:24:40+00:00"
"time": "2024-06-26T21:48:58+00:00"
},
{
"name": "doctrine/persistence",
@ -2361,159 +2257,6 @@
],
"time": "2024-06-19T12:30:46+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "10112722600777e02d2745716b70c5db4ca70442"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/10112722600777e02d2745716b70c5db4ca70442",
"reference": "10112722600777e02d2745716b70c5db4ca70442",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.30.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-06-19T12:30:46+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433",
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/polyfill-php83",
"version": "v1.30.0",
@ -5644,6 +5387,86 @@
],
"time": "2024-05-31T14:49:08+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433",
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.30.0",

View File

@ -10,11 +10,35 @@
findUnusedVariablesAndParams="true"
>
<issueHandlers>
<!--
Psalm doesn't recognize $columns['idColumn'] and $columns['contentColumn'] always being set in execute().
-->
<PossiblyNullArrayOffset>
<errorLevel type="suppress">
<file name="src/Console/CsvImportCommand.php"/>
</errorLevel>
</PossiblyNullArrayOffset>
<PossiblyUnusedMethod errorLevel="suppress"/>
<PossiblyUnusedReturnValue errorLevel="suppress"/>
<PropertyNotSetInConstructor errorLevel="suppress"/>
<RedundantCastGivenDocblockType errorLevel="suppress"/>
<RedundantConditionGivenDocblockType errorLevel="suppress"/>
<RedundantFunctionCallGivenDocblockType errorLevel="suppress"/>
<RedundantPropertyInitializationCheck errorLevel="suppress"/>
<UnusedClass>
<errorLevel type="suppress">
<referencedClass name="OCC\OaiPmh2\Middleware\GetRecord"/>
<referencedClass name="OCC\OaiPmh2\Middleware\Identify"/>
<referencedClass name="OCC\OaiPmh2\Middleware\ListIdentifiers"/>
<referencedClass name="OCC\OaiPmh2\Middleware\ListMetadataFormats"/>
<referencedClass name="OCC\OaiPmh2\Middleware\ListRecords"/>
<referencedClass name="OCC\OaiPmh2\Middleware\ListSets"/>
</errorLevel>
</UnusedClass>
</issueHandlers>
<projectFiles>
<file name="bin/cli"/>
<directory name="public"/>
<directory name="src"/>
<ignoreFiles>
<directory name="vendor"/>

View File

@ -146,13 +146,13 @@ class Configuration
$configPath
);
}
/** @var array<TKey, TValue> */
$config = Yaml::parseFile($configPath);
$validator = Validation::createValidator();
$violations = $validator->validate($config, $this->getValidationConstraints());
if ($violations->count() > 0) {
throw new ValidationFailedException(null, $violations);
}
/** @var array<TKey, TValue> */
return $config;
}

View File

@ -124,10 +124,6 @@ class CsvImportCommand extends Console
/** @var array<string, string> */
$arguments = $input->getArguments();
/** @var Format */
$format = Database::getInstance()
->getEntityManager()
->getReference(Format::class, $arguments['format']);
/** @var bool */
$noValidation = $input->getOption('noValidation');
/** @var resource */
@ -143,6 +139,10 @@ class CsvImportCommand extends Console
$progressIndicator->start('Importing...');
while ($row = fgetcsv($file)) {
/** @var Format */
$format = Database::getInstance()
->getEntityManager()
->getReference(Format::class, $arguments['format']);
$record = new Record($row[$columns['idColumn']], $format);
if (strlen(trim($row[$columns['contentColumn']])) > 0) {
$record->setContent($row[$columns['contentColumn']], !$noValidation);
@ -171,10 +171,10 @@ class CsvImportCommand extends Console
$progressIndicator->setMessage(
'Importing... ' . (string) $count . ' records processed. Flushing to database...'
);
Database::getInstance()->flush([Record::class]);
Database::getInstance()->flush(true);
}
}
Database::getInstance()->flush();
Database::getInstance()->flush(true);
Database::getInstance()->pruneOrphanSets();
$progressIndicator->finish('All done!');

View File

@ -54,6 +54,7 @@ class UpdateFormatsCommand extends Console
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
/** @var array<string, array<string, string>> */
$formats = Configuration::getInstance()->metadataPrefix;
$this->clearResultCache();
$inDatabase = Database::getInstance()

View File

@ -198,15 +198,14 @@ class Database
/**
* Flush all changes to the database.
*
* @param string[] $entities Optional array of entity types to clear from entity manager
*
* @param bool $clear Should the entity manager get cleared as well?
* @return void
*/
public function flush(array $entities = []): void
public function flush(bool $clear = false): void
{
$this->entityManager->flush();
foreach ($entities as $entity) {
$this->entityManager->clear($entity);
if ($clear) {
$this->entityManager->clear();
}
}
@ -412,7 +411,6 @@ class Database
*/
public function getSets(int $counter = 0): Result
{
$result = [];
$maxRecords = Configuration::getInstance()->maxRecords;
$cursor = $counter * $maxRecords;

View File

@ -98,7 +98,9 @@ class Document
);
$request = $this->dom->createElement('request', $baseUrl);
$this->rootNode->appendChild($request);
foreach ($this->serverRequest->getAttributes() as $param => $value) {
/** @var array<string, string> */
$params = $this->serverRequest->getAttributes();
foreach ($params as $param => $value) {
$request->setAttribute(
$param,
htmlspecialchars($value, ENT_XML1 | ENT_COMPAT, 'UTF-8')

View File

@ -59,9 +59,11 @@ class Dispatcher extends AbstractMiddleware
{
$arguments = [];
if ($request->getMethod() === 'GET') {
/** @var array<string, string> */
$arguments = $request->getQueryParams();
} elseif ($request->getMethod() === 'POST') {
if ($request->getHeaderLine('Content-Type') === 'application/x-www-form-urlencoded') {
/** @var array<string, string> */
$arguments = (array) $request->getParsedBody();
}
}
@ -84,8 +86,10 @@ class Dispatcher extends AbstractMiddleware
{
$request = $this->getRequestWithAttributes($request);
if (!ErrorHandler::getInstance()->hasErrors()) {
/** @var string */
$verb = $request->getAttribute('verb');
/** @var Middleware $middleware */
$middleware = __NAMESPACE__ . '\\' . $request->getAttribute('verb');
$middleware = __NAMESPACE__ . '\\' . $verb;
$this->requestHandler->queue->enqueue(new $middleware());
}
$this->requestHandler->queue->enqueue(ErrorHandler::getInstance());

View File

@ -46,6 +46,7 @@ class GetRecord extends Middleware
*/
protected function prepareResponse(ServerRequestInterface $request): void
{
/** @var array<string, string> */
$params = $request->getAttributes();
/** @var Format */
$format = Database::getInstance()->getEntityManager()->getReference(Format::class, $params['metadataPrefix']);
@ -58,6 +59,8 @@ class GetRecord extends Middleware
ErrorHandler::getInstance()->withError('idDoesNotExist');
}
return;
} else {
$oaiRecordContent = $oaiRecord->getContent();
}
$document = new Document($request);
@ -67,7 +70,7 @@ class GetRecord extends Middleware
$getRecord->appendChild($record);
$header = $document->createElement('header');
if ($oaiRecord->getContent() === null) {
if (!isset($oaiRecordContent)) {
$header->setAttribute('status', 'deleted');
}
$record->appendChild($header);
@ -83,11 +86,11 @@ class GetRecord extends Middleware
$header->appendChild($setSpec);
}
if ($oaiRecord->getContent() !== null) {
if (isset($oaiRecordContent)) {
$metadata = $document->createElement('metadata');
$record->appendChild($metadata);
$data = $document->importData($oaiRecord->getContent());
$data = $document->importData($oaiRecordContent);
$metadata->appendChild($data);
}

View File

@ -52,6 +52,7 @@ class ListIdentifiers extends Middleware
$completeListSize = 0;
$maxRecords = Configuration::getInstance()->maxRecords;
/** @var array<string, string> */
$params = $request->getAttributes();
$verb = $params['verb'];
$metadataPrefix = $params['metadataPrefix'] ?? '';
@ -99,11 +100,11 @@ class ListIdentifiers extends Middleware
$until,
$set
);
$newToken = $records->getResumptionToken();
if (count($records) === 0) {
ErrorHandler::getInstance()->withError('noRecordsMatch');
return;
} elseif ($records->getResumptionToken() !== null) {
$newToken = $records->getResumptionToken();
} elseif (isset($newToken)) {
$completeListSize = $newToken->getParameters()['completeListSize'];
}

View File

@ -68,11 +68,11 @@ class ListSets extends Middleware
}
$sets = Database::getInstance()->getSets($counter);
$newToken = $sets->getResumptionToken();
if (count($sets) === 0) {
ErrorHandler::getInstance()->withError('noSetHierarchy');
return;
} elseif ($sets->getResumptionToken() !== null) {
$newToken = $sets->getResumptionToken();
} elseif (isset($newToken)) {
$completeListSize = $newToken->getParameters()['completeListSize'];
}

View File

@ -50,12 +50,12 @@ class Result implements Countable, Iterator
*
* @var QueryResult
*/
private array $data = [];
private array $data;
/**
* This holds the optional resumption token.
*/
protected ?Token $resumptionToken;
protected ?Token $resumptionToken = null;
/**
* Get the query result.