186 lines
5.3 KiB
PHP
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;
|
|
}
|
|
} |