2
0
mirror of https://github.com/opencultureconsulting/oai-pmh2.git synced 2025-03-30 00:00:30 +01:00

Update Psalm and fix new issues

This commit is contained in:
Sebastian Meyer 2025-03-21 13:15:34 +01:00
parent 373104fff4
commit cd6d2e038f
27 changed files with 66 additions and 43 deletions

View File

@ -13,7 +13,15 @@
> >
<issueHandlers> <issueHandlers>
<!-- <!--
Psalm doesn't recognize some variables always being set because of prior validation. This is a false-positive caused by Doctrine's EntityManagerDecorator.
-->
<MethodSignatureMismatch>
<errorLevel type="suppress">
<file name="src/EntityManager.php"/>
</errorLevel>
</MethodSignatureMismatch>
<!--
This is a false-positive caused by Doctrine's ArrayCollection.
--> -->
<PossiblyNullReference> <PossiblyNullReference>
<errorLevel type="suppress"> <errorLevel type="suppress">
@ -30,15 +38,6 @@
--> -->
<PropertyNotSetInConstructor errorLevel="suppress"/> <PropertyNotSetInConstructor errorLevel="suppress"/>
<RedundantPropertyInitializationCheck errorLevel="suppress"/> <RedundantPropertyInitializationCheck errorLevel="suppress"/>
<!--
We deliberately want to evaluate empty strings as FALSE in those files.
-->
<RiskyTruthyFalsyComparison>
<errorLevel type="suppress">
<file name="src/Console/AddRecordCommand.php"/>
<file name="src/Console/AddSetCommand.php"/>
</errorLevel>
</RiskyTruthyFalsyComparison>
<!-- <!--
Those classes are dynamically used depending on the given OAI verb. Those classes are dynamically used depending on the given OAI verb.
@see src/Middleware/Dispatcher.php:95 @see src/Middleware/Dispatcher.php:95

View File

@ -107,12 +107,12 @@ abstract class Console extends Command
protected function getPhpMemoryLimit(): int protected function getPhpMemoryLimit(): int
{ {
if (!isset($this->memoryLimit)) { if (!isset($this->memoryLimit)) {
$ini = trim(ini_get('memory_limit')); $phpValue = (string) ini_get('memory_limit');
$limit = (int) $ini; $limit = (int) $phpValue;
if ($limit < 0) { if ($limit <= 0) {
return -1; return -1;
} }
$unit = strtolower($ini[strlen($ini) - 1]); $unit = strtolower($phpValue[strlen($phpValue) - 1]);
switch ($unit) { switch ($unit) {
case 'g': case 'g':
$limit *= 1024; $limit *= 1024;

View File

@ -42,13 +42,14 @@ use Symfony\Component\Console\Output\OutputInterface;
name: 'oai:records:add', name: 'oai:records:add',
description: 'Add or update a record in the database' description: 'Add or update a record in the database'
)] )]
class AddRecordCommand extends Console final class AddRecordCommand extends Console
{ {
/** /**
* Configures the current command. * Configures the current command.
* *
* @return void * @return void
*/ */
#[\Override]
protected function configure(): void protected function configure(): void
{ {
$this->addArgument( $this->addArgument(
@ -82,6 +83,7 @@ class AddRecordCommand extends Console
* *
* @return int 0 if everything went fine, or an error code * @return int 0 if everything went fine, or an error code
*/ */
#[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
if (!$this->validateInput($input, $output)) { if (!$this->validateInput($input, $output)) {
@ -90,7 +92,7 @@ class AddRecordCommand extends Console
/** @var Format */ /** @var Format */
$format = $this->em->getMetadataFormat($this->arguments['format']); $format = $this->em->getMetadataFormat($this->arguments['format']);
$content = file_get_contents($this->arguments['file']) ?: ''; $content = (string) file_get_contents($this->arguments['file']);
$record = new Record($this->arguments['identifier'], $format); $record = new Record($this->arguments['identifier'], $format);
if (trim($content) !== '') { if (trim($content) !== '') {

View File

@ -40,13 +40,14 @@ use Symfony\Component\Console\Output\OutputInterface;
name: 'oai:sets:add', name: 'oai:sets:add',
description: 'Add or update a set in the database' description: 'Add or update a set in the database'
)] )]
class AddSetCommand extends Console final class AddSetCommand extends Console
{ {
/** /**
* Configures the current command. * Configures the current command.
* *
* @return void * @return void
*/ */
#[\Override]
protected function configure(): void protected function configure(): void
{ {
$this->addArgument( $this->addArgument(
@ -79,6 +80,7 @@ class AddSetCommand extends Console
* *
* @return int 0 if everything went fine, or an error code * @return int 0 if everything went fine, or an error code
*/ */
#[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
if (!$this->validateInput($input, $output)) { if (!$this->validateInput($input, $output)) {
@ -86,6 +88,7 @@ class AddSetCommand extends Console
} }
if (array_key_exists('file', $this->arguments)) { if (array_key_exists('file', $this->arguments)) {
/** @psalm-suppress RiskyTruthyFalsyComparison */
$description = file_get_contents($this->arguments['file']) ?: null; $description = file_get_contents($this->arguments['file']) ?: null;
} }

View File

@ -52,13 +52,14 @@ use Symfony\Component\Console\Output\OutputInterface;
name: 'oai:records:import:csv', name: 'oai:records:import:csv',
description: 'Import records from a CSV file' description: 'Import records from a CSV file'
)] )]
class CsvImportCommand extends Console final class CsvImportCommand extends Console
{ {
/** /**
* Configures the current command. * Configures the current command.
* *
* @return void * @return void
*/ */
#[\Override]
protected function configure(): void protected function configure(): void
{ {
$this->addArgument( $this->addArgument(
@ -120,6 +121,7 @@ class CsvImportCommand extends Console
* *
* @return int 0 if everything went fine, or an error code * @return int 0 if everything went fine, or an error code
*/ */
#[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
if (!$this->validateInput($input, $output)) { if (!$this->validateInput($input, $output)) {
@ -226,6 +228,7 @@ class CsvImportCommand extends Console
$headers = array_flip($headers); $headers = array_flip($headers);
$callback = function (string $column) use ($headers): ?int { $callback = function (string $column) use ($headers): ?int {
/** @psalm-suppress InvalidArgument */
return array_key_exists($column, $headers) ? $headers[$column] : null; return array_key_exists($column, $headers) ? $headers[$column] : null;
}; };

View File

@ -39,13 +39,14 @@ use Symfony\Component\Console\Output\OutputInterface;
name: 'oai:records:delete', name: 'oai:records:delete',
description: 'Delete a record while obeying deleted record policy' description: 'Delete a record while obeying deleted record policy'
)] )]
class DeleteRecordCommand extends Console final class DeleteRecordCommand extends Console
{ {
/** /**
* Configures the current command. * Configures the current command.
* *
* @return void * @return void
*/ */
#[\Override]
protected function configure(): void protected function configure(): void
{ {
$this->addArgument( $this->addArgument(
@ -69,6 +70,7 @@ class DeleteRecordCommand extends Console
* *
* @return int 0 if everything went fine, or an error code * @return int 0 if everything went fine, or an error code
*/ */
#[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
if (!$this->validateInput($input, $output)) { if (!$this->validateInput($input, $output)) {

View File

@ -40,13 +40,14 @@ use Symfony\Component\Console\Output\OutputInterface;
name: 'oai:records:prune', name: 'oai:records:prune',
description: 'Prune deleted records from database' description: 'Prune deleted records from database'
)] )]
class PruneDeletedRecordsCommand extends Console final class PruneDeletedRecordsCommand extends Console
{ {
/** /**
* Configures the current command. * Configures the current command.
* *
* @return void * @return void
*/ */
#[\Override]
protected function configure(): void protected function configure(): void
{ {
$this->addOption( $this->addOption(
@ -66,13 +67,14 @@ class PruneDeletedRecordsCommand extends Console
* *
* @return int 0 if everything went fine, or an error code * @return int 0 if everything went fine, or an error code
*/ */
#[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$policy = Configuration::getInstance()->deletedRecords; $policy = Configuration::getInstance()->deletedRecords;
$forced = (bool) $input->getOption('force'); $forced = $input->getOption('force');
if ( if (
$policy === 'no' $policy === 'no'
or ($policy === 'transient' && $forced) or ($policy === 'transient' && $forced === true)
) { ) {
$deleted = $this->em->pruneDeletedRecords(); $deleted = $this->em->pruneDeletedRecords();
$this->clearResultCache(); $this->clearResultCache();

View File

@ -38,7 +38,7 @@ use Symfony\Component\Console\Output\OutputInterface;
name: 'oai:tokens:prune', name: 'oai:tokens:prune',
description: 'Prune expired resumption tokens from database' description: 'Prune expired resumption tokens from database'
)] )]
class PruneResumptionTokensCommand extends Console final class PruneResumptionTokensCommand extends Console
{ {
/** /**
* Executes the current command. * Executes the current command.
@ -48,6 +48,7 @@ class PruneResumptionTokensCommand extends Console
* *
* @return int 0 if everything went fine, or an error code * @return int 0 if everything went fine, or an error code
*/ */
#[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$expired = $this->em->pruneExpiredTokens(); $expired = $this->em->pruneExpiredTokens();

View File

@ -41,7 +41,7 @@ use Symfony\Component\Validator\Exception\ValidationFailedException;
name: 'oai:formats:update', name: 'oai:formats:update',
description: 'Update metadata formats in database from configuration' description: 'Update metadata formats in database from configuration'
)] )]
class UpdateFormatsCommand extends Console final class UpdateFormatsCommand extends Console
{ {
/** /**
* Executes the current command. * Executes the current command.
@ -51,6 +51,7 @@ class UpdateFormatsCommand extends Console
* *
* @return int 0 if everything went fine, or an error code * @return int 0 if everything went fine, or an error code
*/ */
#[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$formats = Configuration::getInstance()->metadataPrefix; $formats = Configuration::getInstance()->metadataPrefix;

View File

@ -37,7 +37,7 @@ use Symfony\Component\Validator\Exception\ValidationFailedException;
*/ */
#[ORM\Entity(repositoryClass: FormatRepository::class)] #[ORM\Entity(repositoryClass: FormatRepository::class)]
#[ORM\Table(name: 'formats')] #[ORM\Table(name: 'formats')]
class Format extends Entity final class Format extends Entity
{ {
/** /**
* The unique metadata prefix. * The unique metadata prefix.

View File

@ -42,7 +42,7 @@ use Symfony\Component\Validator\Exception\ValidationFailedException;
#[ORM\Index(name: 'format_idx', columns: ['format'])] #[ORM\Index(name: 'format_idx', columns: ['format'])]
#[ORM\Index(name: 'last_changed_idx', columns: ['last_changed'])] #[ORM\Index(name: 'last_changed_idx', columns: ['last_changed'])]
#[ORM\Index(name: 'format_last_changed_idx', columns: ['format', 'last_changed'])] #[ORM\Index(name: 'format_last_changed_idx', columns: ['format', 'last_changed'])]
class Record extends Entity final class Record extends Entity
{ {
/** /**
* The record identifier. * The record identifier.

View File

@ -37,7 +37,7 @@ use Symfony\Component\Validator\Exception\ValidationFailedException;
*/ */
#[ORM\Entity(repositoryClass: SetRepository::class)] #[ORM\Entity(repositoryClass: SetRepository::class)]
#[ORM\Table(name: 'sets')] #[ORM\Table(name: 'sets')]
class Set extends Entity final class Set extends Entity
{ {
/** /**
* The unique set spec. * The unique set spec.

View File

@ -40,7 +40,7 @@ use OCC\OaiPmh2\Repository\TokenRepository;
#[ORM\Entity(repositoryClass: TokenRepository::class)] #[ORM\Entity(repositoryClass: TokenRepository::class)]
#[ORM\Table(name: 'tokens')] #[ORM\Table(name: 'tokens')]
#[ORM\Index(name: 'valid_until_idx', columns: ['valid_until'])] #[ORM\Index(name: 'valid_until_idx', columns: ['valid_until'])]
class Token extends Entity final class Token extends Entity
{ {
/** /**
* The resumption token. * The resumption token.

View File

@ -205,11 +205,11 @@ final class EntityManager extends EntityManagerDecorator
->setMaxResults($maxRecords); ->setMaxResults($maxRecords);
if (isset($from)) { if (isset($from)) {
$dql->andWhere($dql->expr()->gte('records.lastChanged', ':from')); $dql->andWhere($dql->expr()->gte('records.lastChanged', ':from'));
$dql->setParameter('from', new DateTime($from)); $dql->setParameter('from', new DateTime($from), 'datetime');
} }
if (isset($until)) { if (isset($until)) {
$dql->andWhere($dql->expr()->lte('records.lastChanged', ':until')); $dql->andWhere($dql->expr()->lte('records.lastChanged', ':until'));
$dql->setParameter('until', new DateTime($until)); $dql->setParameter('until', new DateTime($until), 'datetime');
} }
if (isset($set)) { if (isset($set)) {
$dql->innerJoin( $dql->innerJoin(
@ -338,7 +338,7 @@ final class EntityManager extends EntityManagerDecorator
public function isValidRecordIdentifier(string $identifier): bool public function isValidRecordIdentifier(string $identifier): bool
{ {
$records = $this->getRepository(Record::class)->findBy(['identifier' => $identifier]); $records = $this->getRepository(Record::class)->findBy(['identifier' => $identifier]);
return (bool) count($records) > 0; return count($records) > 0;
} }
/** /**
@ -369,7 +369,7 @@ final class EntityManager extends EntityManagerDecorator
$dql = $this->createQueryBuilder(); $dql = $this->createQueryBuilder();
$dql->delete(Token::class, 'tokens') $dql->delete(Token::class, 'tokens')
->where($dql->expr()->lt('tokens.validUntil', ':now')) ->where($dql->expr()->lt('tokens.validUntil', ':now'))
->setParameter('now', new DateTime()); ->setParameter('now', new DateTime(), 'datetime');
/** @var int */ /** @var int */
return $dql->getQuery()->execute(); return $dql->getQuery()->execute();
} }

View File

@ -142,6 +142,7 @@ abstract class Middleware extends AbstractMiddleware
* *
* @return ServerRequestInterface The processed server request * @return ServerRequestInterface The processed server request
*/ */
#[\Override]
protected function processRequest(ServerRequestInterface $request): ServerRequestInterface protected function processRequest(ServerRequestInterface $request): ServerRequestInterface
{ {
/** @var OaiRequestMetadata */ /** @var OaiRequestMetadata */
@ -158,6 +159,7 @@ abstract class Middleware extends AbstractMiddleware
* *
* @return ResponseInterface The processed response * @return ResponseInterface The processed response
*/ */
#[\Override]
protected function processResponse(ResponseInterface $response): ResponseInterface protected function processResponse(ResponseInterface $response): ResponseInterface
{ {
if (!ErrorHandler::getInstance()->hasErrors() && isset($this->preparedResponse)) { if (!ErrorHandler::getInstance()->hasErrors() && isset($this->preparedResponse)) {

View File

@ -34,7 +34,7 @@ use Psr\Http\Message\ServerRequestInterface;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class Dispatcher extends AbstractMiddleware final class Dispatcher extends AbstractMiddleware
{ {
/** /**
* List of defined OAI-PMH parameters. * List of defined OAI-PMH parameters.
@ -85,6 +85,7 @@ class Dispatcher extends AbstractMiddleware
* *
* @return ServerRequestInterface The processed server request * @return ServerRequestInterface The processed server request
*/ */
#[\Override]
protected function processRequest(ServerRequestInterface $request): ServerRequestInterface protected function processRequest(ServerRequestInterface $request): ServerRequestInterface
{ {
$request = $this->getRequestWithAttributes($request); $request = $this->getRequestWithAttributes($request);
@ -108,6 +109,7 @@ class Dispatcher extends AbstractMiddleware
* *
* @return ResponseInterface The final response * @return ResponseInterface The final response
*/ */
#[\Override]
protected function processResponse(ResponseInterface $response): ResponseInterface protected function processResponse(ResponseInterface $response): ResponseInterface
{ {
// TODO: Add support for content compression // TODO: Add support for content compression

View File

@ -36,7 +36,7 @@ use Psr\Http\Message\StreamInterface;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class ErrorHandler extends AbstractMiddleware final class ErrorHandler extends AbstractMiddleware
{ {
use Singleton; use Singleton;
@ -99,6 +99,7 @@ class ErrorHandler extends AbstractMiddleware
* *
* @return ResponseInterface The error response * @return ResponseInterface The error response
*/ */
#[\Override]
protected function processResponse(ResponseInterface $response): ResponseInterface protected function processResponse(ResponseInterface $response): ResponseInterface
{ {
if ($this->hasErrors()) { if ($this->hasErrors()) {

View File

@ -34,7 +34,7 @@ use Psr\Http\Message\ServerRequestInterface;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class GetRecord extends Middleware final class GetRecord extends Middleware
{ {
/** /**
* Prepare the response body for verb "GetRecord". * Prepare the response body for verb "GetRecord".
@ -43,6 +43,7 @@ class GetRecord extends Middleware
* *
* @return void * @return void
*/ */
#[\Override]
protected function prepareResponse(ServerRequestInterface $request): void protected function prepareResponse(ServerRequestInterface $request): void
{ {
$oaiRecord = $this->em->getRecord( $oaiRecord = $this->em->getRecord(

View File

@ -36,7 +36,7 @@ use Psr\Http\Message\ServerRequestInterface;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class Identify extends Middleware final class Identify extends Middleware
{ {
/** /**
* Prepare the response body for verb "Identify". * Prepare the response body for verb "Identify".
@ -45,6 +45,7 @@ class Identify extends Middleware
* *
* @return void * @return void
*/ */
#[\Override]
protected function prepareResponse(ServerRequestInterface $request): void protected function prepareResponse(ServerRequestInterface $request): void
{ {
$response = new Response($request); $response = new Response($request);

View File

@ -43,6 +43,7 @@ class ListIdentifiers extends Middleware
* *
* @return void * @return void
*/ */
#[\Override]
protected function prepareResponse(ServerRequestInterface $request): void protected function prepareResponse(ServerRequestInterface $request): void
{ {
$this->checkResumptionToken(); $this->checkResumptionToken();

View File

@ -34,7 +34,7 @@ use Psr\Http\Message\ServerRequestInterface;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class ListMetadataFormats extends Middleware final class ListMetadataFormats extends Middleware
{ {
/** /**
* Prepare the response body for verb "ListMetadataFormats". * Prepare the response body for verb "ListMetadataFormats".
@ -43,6 +43,7 @@ class ListMetadataFormats extends Middleware
* *
* @return void * @return void
*/ */
#[\Override]
protected function prepareResponse(ServerRequestInterface $request): void protected function prepareResponse(ServerRequestInterface $request): void
{ {
$formats = $this->em->getMetadataFormats($this->arguments['identifier']); $formats = $this->em->getMetadataFormats($this->arguments['identifier']);

View File

@ -30,7 +30,7 @@ namespace OCC\OaiPmh2\Middleware;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class ListRecords extends ListIdentifiers final class ListRecords extends ListIdentifiers
{ {
/** /**
* "ListIdentifiers" and "ListRecords" are practically identical except the * "ListIdentifiers" and "ListRecords" are practically identical except the

View File

@ -34,7 +34,7 @@ use Psr\Http\Message\ServerRequestInterface;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class ListSets extends Middleware final class ListSets extends Middleware
{ {
/** /**
* Prepare the response body for verb "ListSets". * Prepare the response body for verb "ListSets".
@ -43,6 +43,7 @@ class ListSets extends Middleware
* *
* @return void * @return void
*/ */
#[\Override]
protected function prepareResponse(ServerRequestInterface $request): void protected function prepareResponse(ServerRequestInterface $request): void
{ {
$this->checkResumptionToken(); $this->checkResumptionToken();

View File

@ -33,7 +33,7 @@ use Symfony\Component\Validator\Validation;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class ConfigurationValidator final class ConfigurationValidator
{ {
/** /**
* Get constraints for configuration array. * Get constraints for configuration array.

View File

@ -33,7 +33,7 @@ use Symfony\Component\Validator\Validation;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class RegExValidator final class RegExValidator
{ {
/** /**
* Get constraints for regular expression. * Get constraints for regular expression.

View File

@ -33,7 +33,7 @@ use Symfony\Component\Validator\Validation;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class UrlValidator final class UrlValidator
{ {
/** /**
* Get constraints for URLs. * Get constraints for URLs.

View File

@ -34,7 +34,7 @@ use Symfony\Component\Validator\Validation;
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com> * @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
* @package OAIPMH2 * @package OAIPMH2
*/ */
class XmlValidator final class XmlValidator
{ {
/** /**
* Get constraints for XML. * Get constraints for XML.