From b0145d568c8fe7d541879fd24d1796810f80f989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20=C5=BB=C3=B3=C5=82tak?= Date: Mon, 16 Sep 2024 17:43:24 +0200 Subject: [PATCH] TemplateMetadata: add PARENT special value and allow some special values to be used on the right side of if --- doc/TemplateMetadata.md | 3 + .../oaipmh/metadata/TemplateMetadata.php | 60 ++++++++++++------- tests/TemplateMetadataTest.php | 19 ++++++ tests/data/ifSpecial.ttl | 8 +++ tests/data/ifSpecial.xml | 10 ++++ tests/data/ifSpecial.yml | 10 ++++ 6 files changed, 88 insertions(+), 22 deletions(-) create mode 100644 tests/data/ifSpecial.ttl create mode 100644 tests/data/ifSpecial.xml create mode 100644 tests/data/ifSpecial.yml diff --git a/doc/TemplateMetadata.md b/doc/TemplateMetadata.md index 7cd261d..481321d 100644 --- a/doc/TemplateMetadata.md +++ b/doc/TemplateMetadata.md @@ -371,6 +371,9 @@ A term consists of: * optional operator and value * operator is one of `==`, `!=`, `starts`, `ends`, `contains`, `>`, `<`, `>=`, `<=`, `regex` * value is single- or double-quited literal value or an RDF property in the `prefix:suffix` format + or a special value of `OAIID`, `URI`/`URL` (see the `val` attribute documentation) + or a special value of `PARENT` (meaning last direct parent of the previous `foreach`; + if there is no `foreach`, then its equivalent to `URI`/`URL`) E.g. diff --git a/src/acdhOeaw/arche/oaipmh/metadata/TemplateMetadata.php b/src/acdhOeaw/arche/oaipmh/metadata/TemplateMetadata.php index f0df43c..85c41bc 100644 --- a/src/acdhOeaw/arche/oaipmh/metadata/TemplateMetadata.php +++ b/src/acdhOeaw/arche/oaipmh/metadata/TemplateMetadata.php @@ -70,8 +70,8 @@ */ class TemplateMetadata implements MetadataInterface { - const PREDICATE_REGEX = '[-_a-zA-Z0-9]+:[^ )]*'; - const IF_VALUE_REGEX = '(==|!=|starts|ends|contains|>|<|>=|<=|regex) +(?:"([^"]*)"|\'([^\']*)\'|([0-9]+[.]?[0-9]*)|(' . self::PREDICATE_REGEX . '))'; + const PREDICATE_REGEX = '[-_a-zA-Z0-9]+:[^ )]*|CURNODE'; + const IF_VALUE_REGEX = '(==|!=|starts|ends|contains|>|<|>=|<=|regex) +(?:"([^"]*)"|\'([^\']*)\'|([0-9]+[.]?[0-9]*)|(' . self::PREDICATE_REGEX . ')|(OAIID|URI|URL|PARENT))'; const IF_PART_REGEX = '`^ *(any|every|none)[(](' . self::PREDICATE_REGEX . ')(?: +' . self::IF_VALUE_REGEX . ')?[)]`u'; const IF_LOGICAL_REGEX = '`^ *(OR|AND|NOT) *`'; @@ -84,6 +84,19 @@ class TemplateMetadata implements MetadataInterface { */ static private array $loadedInverse = []; + static public function extendSearchFilterQuery(MetadataFormat $format): QueryPart { + return new QueryPart(); + } + + static public function extendSearchDataQuery(MetadataFormat $format): QueryPart { + return new QueryPart(); + } + + static public function clearDataset(): void { + self::$dataset = new Dataset(); + self::$loadedInverse = []; + } + /** * Repository resource object */ @@ -184,14 +197,6 @@ public function getXml(): DOMElement { return $this->xml->documentElement; } - static public function extendSearchFilterQuery(MetadataFormat $format): QueryPart { - return new QueryPart(); - } - - static public function extendSearchDataQuery(MetadataFormat $format): QueryPart { - return new QueryPart(); - } - private function processElement(DOMDocument | DOMElement $el): void { $this->xmlLocation[] = $el->nodeName; $this->removeUnneededNodes($el); @@ -294,7 +299,13 @@ private function evaluateIf(string $if): bool { $func = $matches[1]; $value = null; if (!empty($matches[3])) { - $value = !empty($matches[7]) ? $this->expand($matches[7]) : $matches[4] . ($matches[5] ?? '') . ($matches[6] ?? ''); + if (!empty($matches[8])) { + $value = $this->getSpecialValue($matches[8]); + } elseif (!empty($matches[7])) { + $value = $this->expand($matches[7]); + } else { + $value = $matches[4] . ($matches[5] ?? '') . ($matches[6] ?? ''); + } if ($matches[3] === ValueTemplate::REGEX) { $value = "`$value`u"; } @@ -412,17 +423,7 @@ private function processValue(DOMDocument | DOMElement $el): void { } private function fetchValues(Value $val): array { - $result = match ($val->path) { - 'NOW' => (new DateTimeImmutable())->format(DateTimeImmutable::ISO8601), - 'URI', 'URL' => $this->res->getRepo()->getBaseUrl() . $this->headerData->repoid, - 'METAURL' => $this->res->getRepo()->getBaseUrl() . $this->headerData->repoid . '/metadata', - 'OAIID' => $this->headerData->id, - 'OAIURL' => $this->format->info->baseURL . '?verb=GetRecord&metadataPrefix=' . rawurlencode($this->format->metadataPrefix) . '&identifier=' . rawurldecode($this->headerData->id), - 'RANDOM' => rand(), - 'SEQ' => $this->seqNo++, - 'CURNODE' => end($this->nodesStack), - default => null, - }; + $result = $this->getSpecialValue($val->path); if ($result !== null) { return [$result]; } @@ -514,4 +515,19 @@ private function loadMetadata(array $resources, } } } + + private function getSpecialValue(string $val): TermInterface | string | null { + return match ($val) { + 'NOW' => (new DateTimeImmutable())->format(DateTimeImmutable::ISO8601), + 'URI', 'URL' => $this->res->getRepo()->getBaseUrl() . $this->headerData->repoid, + 'METAURL' => $this->res->getRepo()->getBaseUrl() . $this->headerData->repoid . '/metadata', + 'OAIID' => $this->headerData->id, + 'OAIURL' => $this->format->info->baseURL . '?verb=GetRecord&metadataPrefix=' . rawurlencode($this->format->metadataPrefix) . '&identifier=' . rawurldecode($this->headerData->id), + 'RANDOM' => rand(), + 'SEQ' => $this->seqNo++, + 'CURNODE' => end($this->nodesStack), + 'PARENT' => $this->nodesStack[count($this->nodesStack) - 2], + default => null, + }; + } } diff --git a/tests/TemplateMetadataTest.php b/tests/TemplateMetadataTest.php index aa1f5b9..49d1ef5 100644 --- a/tests/TemplateMetadataTest.php +++ b/tests/TemplateMetadataTest.php @@ -27,6 +27,7 @@ namespace acdhOeaw\arche\oaipmh\tests; use DateTimeImmutable; +use acdhOeaw\arche\oaipmh\metadata\TemplateMetadata; /** * Description of TemplateMetadataTest @@ -35,6 +36,11 @@ */ class TemplateMetadataTest extends TestBase { + public function setUp(): void { + parent::setUp(); + TemplateMetadata::clearDataset(); + } + public function testCommentsWhitespaces(): void { $in = file_get_contents(__DIR__ . '/data/keepComments.xml'); $tmpl = $this->getMetadataObject('common', $in); @@ -345,6 +351,19 @@ public function testFetchCycle(): void { http://127.0.0.1/api/234 http://127.0.0.1/api/345 +OUT; + $this->assertEquals($this->std($expected), $xml); + } + + public function testIfSpecial(): void { + $tmpl = $this->getMetadataObject('ifSpecial'); + $xml = $this->asString($tmpl->getXml()); + $expected = << +foo +baz +baz + OUT; $this->assertEquals($this->std($expected), $xml); } diff --git a/tests/data/ifSpecial.ttl b/tests/data/ifSpecial.ttl new file mode 100644 index 0000000..a0c9f7e --- /dev/null +++ b/tests/data/ifSpecial.ttl @@ -0,0 +1,8 @@ + , + ; + , + ; + "foo" . + "bar" . + "baz" ; + . diff --git a/tests/data/ifSpecial.xml b/tests/data/ifSpecial.xml new file mode 100644 index 0000000..e0f9e4e --- /dev/null +++ b/tests/data/ifSpecial.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/data/ifSpecial.yml b/tests/data/ifSpecial.yml new file mode 100644 index 0000000..f722130 --- /dev/null +++ b/tests/data/ifSpecial.yml @@ -0,0 +1,10 @@ +metadataPrefix: templateMetadata +metadataNamespace: http://unknown/namespace +schema: http://unknown/schema +class: \acdhOeaw\arche\oaipmh\metadata\TemplateMetadata +templatePath: "" +keepComments: false +xmlErrors: true +rdfNamespaces: + base: https:// + local: http://127.0.0.1/api/