Files
oai-symfony/src/OAI/Verb/ListRecords.php
2026-04-30 16:08:01 +02:00

186 lines
5.3 KiB
PHP

<?php
declare(strict_types=1);
namespace App\OAI\Verb;
use App\OAI\{
RecordOaiDc,
RecordOaiDataCite,
RecordOaiInterface,
ResumptionToken
};
use App\OAI\Exception\InvalidTokenException;
use App\OAI\OaiBase;
use App\OAI\OaiError;
use \Symfony\Component\HttpFoundation\Request;
use function \Symfony\Component\String\b;
/**
* Represents a ListRecords response
*/
final class ListRecords
{
private RecordOaiInterface $record;
private Request $request;
private ?string $metadataFormat;
private ?ResumptionToken $resumptionToken;
public function __construct(Request $req)
{
$this->request = $req;
}
/**
* Returns the XML response
* @todo Refactor (complexity...)
*/
public function response(): string
{
$this->metadataFormat = $this->request->get('metadataPrefix');
$until = $this->request->get('until');
$from = $this->request->get('from');
$set = $this->request->get('set');
$token = $this->request->get('resumptionToken');
if ($token !== null) {
$tokenObj = ResumptionToken::decode($token);
$set = $tokenObj->set;
$this->metadataFormat = $tokenObj->metadataFormat;
$from = $tokenObj->from;
$until = $tokenObj->until;
}
$hasErrors = $this->hasErrors($from, $until, $set);
if ($hasErrors !== false) return $hasErrors->toXML();
try {
$identifiers = $this->getIdentifiers(
$set,
$from,
$until,
);
}
catch (InvalidTokenException $e) {
return (new OaiError($e->getCode(), $e->getMessage()))
->toXML();
}
if (count($identifiers) === 0) {
return (new OaiError('noRecordsMatch', 'No records were found in repository.'))
->toXML();
}
$xml = '';
$xml = $this->createXML($identifiers, $this->metadataFormat);
$xml = b($xml)->toUnicodeString()->trim("\n");
$xml = $xml->prepend("<ListRecords>\n");
$xml = $xml->append("\n</ListRecords>");
return OaiBase::create($xml->toString(), 'ListRecords', $this->metadataFormat);
}
private function checkGranularity(string $date): bool
{
$valid = true;
$pattern = "/\d{4}-\d{2}-\d{2}/";
preg_match($pattern, $date, $matches);
if (count($matches) === 0) return false;
$valid &= $matches[0] === $date;
$parts = explode('-', $date);
$valid &= checkdate((int)$parts[1], (int)$parts[2], (int)$parts[0]);
return (bool)$valid;
}
private function checkValidSet(string $setspec): bool
{
// Implement
return false;
}
/**
* @todo Implement limit for cumulative array
* @throws InvalidTokenException
* @return string[]
*/
private function getIdentifiers(?string $set, ?string $from, ?string $until,): array
{
$identifiers = [];
$decodedToken = null;
$offset = 0;
$size = 0;
$limit = (int)$_ENV['OAI_LIMIT'];
$token = $this->request->get('resumptionToken');
if ($token !== null) {
$decodedToken = ResumptionToken::decode($token);
$offset = $decodedToken->cursor;
}
if ($set === null && $this->metadataFormat === 'oai_dc') {
// Get resources and size (total number)
$this->resumptionToken = new ResumptionToken(
$offset + $limit,
$size,
set: $set,
metadataFormat: $this->metadataFormat,
from: $from,
until: $until,
);
return $identifiers;
}
return $identifiers;
}
private function createXML(
array $identifiers,
string $metadataFormat,
): string
{
$xml = '';
foreach ($identifiers as $id) {
$this->record = match ($metadataFormat) {
'oai_dc' => new RecordOaiDc($id['identifier'], verb: 'ListRecords'),
'oai_datacite' => new RecordOaiDataCite($id['identifier'], verb: 'ListRecords'),
default => new RecordOaiDc($id['identifier'], verb: 'ListRecords'),
};
$xml .= "\n" . $this->record->toXML();
}
if ($this->resumptionToken->cursor < $this->resumptionToken->size) {
$xml .= "\n{$this->resumptionToken->toXML()}";
}
return $xml;
}
private function hasErrors(?string $from, ?string $until, ?string $set): OaiError|false
{
$error = false;
if ($from !== null && ! $this->checkGranularity($from) ||
$until !== null && ! $this->checkGranularity($until)
) {
$error = new OaiError('badArgument', "The argument value for 'from' and/or 'until' is invalid.");
}
if (($until !== null && $from !== null) && ($from > $until)) {
$error = new OaiError('noRecordsMatch', 'No records were found in repository.');
}
if ($set !== null && ! $this->checkValidSet($set)) {
$error = new OaiError('badArgument', "The set '$set' does not exist in this repository.");
}
return $error;
}
}