From 9ac3661b6a75255832203b87a9ba7994add64061 Mon Sep 17 00:00:00 2001 From: Valentin Dassonville <129871973+valentin-dassonville@users.noreply.github.com> Date: Wed, 6 Nov 2024 11:50:57 +0100 Subject: [PATCH] fix(hydra): store and use hydra context in a local variable (#6765) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kévin Dunglas Co-authored-by: soyuka --- composer.json | 5 +- features/hydra/docs.feature | 2 +- .../Serializer/DocumentationNormalizer.php | 4 +- .../DocumentationNormalizerTest.php | 8 +- src/JsonLd/ContextBuilder.php | 2 +- src/JsonLd/HydraContext.php | 919 ++++++++++++++++++ src/JsonLd/composer.json | 3 + tests/Behat/HydraContext.php | 22 + tests/JsonLd/ContextBuilderTest.php | 4 +- update-hydra-context.php | 32 + 10 files changed, 993 insertions(+), 8 deletions(-) create mode 100644 src/JsonLd/HydraContext.php create mode 100644 update-hydra-context.php diff --git a/composer.json b/composer.json index ff7ae164554..39314dc5890 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,10 @@ "autoload": { "psr-4": { "ApiPlatform\\": "src/" - } + }, + "files": [ + "src/JsonLd/HydraContext.php" + ] }, "autoload-dev": { "psr-4": { diff --git a/features/hydra/docs.feature b/features/hydra/docs.feature index 6e3501d3bca..3b5d665a2c6 100644 --- a/features/hydra/docs.feature +++ b/features/hydra/docs.feature @@ -13,7 +13,7 @@ Feature: Documentation support And the response should be in JSON And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" # Context - And the JSON node "@context[0]" should be equal to "http://www.w3.org/ns/hydra/context.jsonld" + And the Hydra context matches the online resource "http://www.w3.org/ns/hydra/context.jsonld" And the JSON node "@context[1].@vocab" should be equal to "http://example.com/docs.jsonld#" And the JSON node "@context[1].hydra" should be equal to "http://www.w3.org/ns/hydra/core#" And the JSON node "@context[1].rdf" should be equal to "http://www.w3.org/1999/02/22-rdf-syntax-ns#" diff --git a/src/Hydra/Serializer/DocumentationNormalizer.php b/src/Hydra/Serializer/DocumentationNormalizer.php index 0cae690f683..510e5f48c56 100644 --- a/src/Hydra/Serializer/DocumentationNormalizer.php +++ b/src/Hydra/Serializer/DocumentationNormalizer.php @@ -35,6 +35,8 @@ use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use const ApiPlatform\JsonLd\HYDRA_CONTEXT; + /** * Creates a machine readable Hydra API documentation. * @@ -573,7 +575,7 @@ private function computeDoc(Documentation $object, array $classes, string $hydra private function getContext(string $hydraPrefix = ContextBuilder::HYDRA_PREFIX): array { return [ - ContextBuilderInterface::HYDRA_CONTEXT, + HYDRA_CONTEXT, [ '@vocab' => $this->urlGenerator->generate('api_doc', ['_format' => self::FORMAT], UrlGeneratorInterface::ABS_URL).'#', 'hydra' => ContextBuilderInterface::HYDRA_NS, diff --git a/src/Hydra/Tests/Serializer/DocumentationNormalizerTest.php b/src/Hydra/Tests/Serializer/DocumentationNormalizerTest.php index f54c56a0bbe..f82f796a7fe 100644 --- a/src/Hydra/Tests/Serializer/DocumentationNormalizerTest.php +++ b/src/Hydra/Tests/Serializer/DocumentationNormalizerTest.php @@ -37,6 +37,8 @@ use Prophecy\PhpUnit\ProphecyTrait; use Symfony\Component\PropertyInfo\Type; +use const ApiPlatform\JsonLd\HYDRA_CONTEXT; + /** * @author Amrouche Hamza */ @@ -106,7 +108,7 @@ private function doTestNormalize($resourceMetadataFactory = null): void $expected = [ '@context' => [ - 'http://www.w3.org/ns/hydra/context.jsonld', + HYDRA_CONTEXT, [ '@vocab' => '/doc#', 'hydra' => 'http://www.w3.org/ns/hydra/core#', @@ -406,7 +408,7 @@ public function testNormalizeInputOutputClass(): void $expected = [ '@context' => [ - 'http://www.w3.org/ns/hydra/context.jsonld', + HYDRA_CONTEXT, [ '@vocab' => '/doc#', 'hydra' => 'http://www.w3.org/ns/hydra/core#', @@ -766,7 +768,7 @@ public function testNormalizeWithoutPrefix(): void $expected = [ '@context' => [ - 'http://www.w3.org/ns/hydra/context.jsonld', + HYDRA_CONTEXT, [ '@vocab' => '/doc#', 'hydra' => 'http://www.w3.org/ns/hydra/core#', diff --git a/src/JsonLd/ContextBuilder.php b/src/JsonLd/ContextBuilder.php index bfc6e5765ba..a3d638f5a7b 100644 --- a/src/JsonLd/ContextBuilder.php +++ b/src/JsonLd/ContextBuilder.php @@ -185,7 +185,7 @@ private function getResourceContextWithShortname(string $resourceClass, int $ref } if (false === ($this->defaultContext[self::HYDRA_CONTEXT_HAS_PREFIX] ?? true)) { - return [ContextBuilderInterface::HYDRA_CONTEXT, $context]; + return [HYDRA_CONTEXT, $context]; } return $context; diff --git a/src/JsonLd/HydraContext.php b/src/JsonLd/HydraContext.php new file mode 100644 index 00000000000..90b6858682a --- /dev/null +++ b/src/JsonLd/HydraContext.php @@ -0,0 +1,919 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\JsonLd; + +/* + * This is an autogenerated file, DO NOT MODIFY IT. + * Run the update-hydra-context.php script at the root of the project to refresh it. + */ +const HYDRA_CONTEXT = [ + '@context' => [ + 'hydra' => 'http://www.w3.org/ns/hydra/core#', + 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', + 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', + 'xsd' => 'http://www.w3.org/2001/XMLSchema#', + 'owl' => 'http://www.w3.org/2002/07/owl#', + 'vs' => 'http://www.w3.org/2003/06/sw-vocab-status/ns#', + 'dc' => 'http://purl.org/dc/terms/', + 'cc' => 'http://creativecommons.org/ns#', + 'schema' => 'http://schema.org/', + 'apiDocumentation' => 'hydra:apiDocumentation', + 'ApiDocumentation' => 'hydra:ApiDocumentation', + 'title' => 'hydra:title', + 'description' => 'hydra:description', + 'entrypoint' => [ + '@id' => 'hydra:entrypoint', + '@type' => '@id', + ], + 'supportedClass' => [ + '@id' => 'hydra:supportedClass', + '@type' => '@vocab', + ], + 'Class' => 'hydra:Class', + 'supportedProperty' => [ + '@id' => 'hydra:supportedProperty', + '@type' => '@id', + ], + 'SupportedProperty' => 'hydra:SupportedProperty', + 'property' => [ + '@id' => 'hydra:property', + '@type' => '@vocab', + ], + 'required' => 'hydra:required', + 'readable' => 'hydra:readable', + 'writable' => 'hydra:writable', + 'writeable' => 'hydra:writeable', + 'supportedOperation' => [ + '@id' => 'hydra:supportedOperation', + '@type' => '@id', + ], + 'Operation' => 'hydra:Operation', + 'method' => 'hydra:method', + 'expects' => [ + '@id' => 'hydra:expects', + '@type' => '@vocab', + ], + 'returns' => [ + '@id' => 'hydra:returns', + '@type' => '@vocab', + ], + 'possibleStatus' => [ + '@id' => 'hydra:possibleStatus', + '@type' => '@id', + ], + 'Status' => 'hydra:Status', + 'statusCode' => 'hydra:statusCode', + 'Error' => 'hydra:Error', + 'Resource' => 'hydra:Resource', + 'operation' => 'hydra:operation', + 'Collection' => 'hydra:Collection', + 'collection' => 'hydra:collection', + 'member' => [ + '@id' => 'hydra:member', + '@type' => '@id', + ], + 'memberAssertion' => 'hydra:memberAssertion', + 'manages' => 'hydra:manages', + 'subject' => [ + '@id' => 'hydra:subject', + '@type' => '@vocab', + ], + 'object' => [ + '@id' => 'hydra:object', + '@type' => '@vocab', + ], + 'search' => 'hydra:search', + 'freetextQuery' => 'hydra:freetextQuery', + 'view' => [ + '@id' => 'hydra:view', + '@type' => '@id', + ], + 'PartialCollectionView' => 'hydra:PartialCollectionView', + 'totalItems' => 'hydra:totalItems', + 'first' => [ + '@id' => 'hydra:first', + '@type' => '@id', + ], + 'last' => [ + '@id' => 'hydra:last', + '@type' => '@id', + ], + 'next' => [ + '@id' => 'hydra:next', + '@type' => '@id', + ], + 'previous' => [ + '@id' => 'hydra:previous', + '@type' => '@id', + ], + 'Link' => 'hydra:Link', + 'TemplatedLink' => 'hydra:TemplatedLink', + 'IriTemplate' => 'hydra:IriTemplate', + 'template' => 'hydra:template', + 'Rfc6570Template' => 'hydra:Rfc6570Template', + 'variableRepresentation' => [ + '@id' => 'hydra:variableRepresentation', + '@type' => '@vocab', + ], + 'VariableRepresentation' => 'hydra:VariableRepresentation', + 'BasicRepresentation' => 'hydra:BasicRepresentation', + 'ExplicitRepresentation' => 'hydra:ExplicitRepresentation', + 'mapping' => 'hydra:mapping', + 'IriTemplateMapping' => 'hydra:IriTemplateMapping', + 'variable' => 'hydra:variable', + 'offset' => [ + '@id' => 'hydra:offset', + '@type' => 'xsd:nonNegativeInteger', + ], + 'limit' => [ + '@id' => 'hydra:limit', + '@type' => 'xsd:nonNegativeInteger', + ], + 'pageIndex' => [ + '@id' => 'hydra:pageIndex', + '@type' => 'xsd:nonNegativeInteger', + ], + 'pageReference' => [ + '@id' => 'hydra:pageReference', + ], + 'returnsHeader' => [ + '@id' => 'hydra:returnsHeader', + '@type' => 'xsd:string', + ], + 'expectsHeader' => [ + '@id' => 'hydra:expectsHeader', + '@type' => 'xsd:string', + ], + 'HeaderSpecification' => 'hydra:HeaderSpecification', + 'headerName' => 'hydra:headerName', + 'possibleValue' => 'hydra:possibleValue', + 'closedSet' => [ + '@id' => 'hydra:possibleValue', + '@type' => 'xsd:boolean', + ], + 'name' => [ + '@id' => 'hydra:name', + '@type' => 'xsd:string', + ], + 'extension' => [ + '@id' => 'hydra:extension', + '@type' => '@id', + ], + 'isDefinedBy' => [ + '@id' => 'rdfs:isDefinedBy', + '@type' => '@id', + ], + 'defines' => [ + '@reverse' => 'rdfs:isDefinedBy', + ], + 'comment' => 'rdfs:comment', + 'label' => 'rdfs:label', + 'preferredPrefix' => 'http://purl.org/vocab/vann/preferredNamespacePrefix', + 'cc:license' => [ + '@type' => '@id', + ], + 'cc:attributionURL' => [ + '@type' => '@id', + ], + 'domain' => [ + '@id' => 'rdfs:domain', + '@type' => '@vocab', + ], + 'range' => [ + '@id' => 'rdfs:range', + '@type' => '@vocab', + ], + 'subClassOf' => [ + '@id' => 'rdfs:subClassOf', + '@type' => '@vocab', + ], + 'subPropertyOf' => [ + '@id' => 'rdfs:subPropertyOf', + '@type' => '@vocab', + ], + 'seeAlso' => [ + '@id' => 'rdfs:seeAlso', + '@type' => '@id', + ], + 'domainIncludes' => [ + '@id' => 'schema:domainIncludes', + '@type' => '@id', + ], + 'rangeIncludes' => [ + '@id' => 'schema:rangeIncludes', + '@type' => '@id', + ], + ], + '@id' => 'http://www.w3.org/ns/hydra/core', + '@type' => 'owl:Ontology', + 'label' => 'The Hydra Core Vocabulary', + 'comment' => 'A lightweight vocabulary for hypermedia-driven Web APIs', + 'seeAlso' => 'https://www.hydra-cg.com/spec/latest/core/', + 'preferredPrefix' => 'hydra', + 'dc:description' => 'The Hydra Core Vocabulary is a lightweight vocabulary to create hypermedia-driven Web APIs. By specifying a number of concepts commonly used in Web APIs it enables the creation of generic API clients.', + 'dc:rights' => 'Copyright © 2012-2014 the Contributors to the Hydra Core Vocabulary Specification', + 'dc:publisher' => 'Hydra W3C Community Group', + 'cc:license' => 'http://creativecommons.org/licenses/by/4.0/', + 'cc:attributionName' => 'Hydra W3C Community Group', + 'cc:attributionURL' => 'http://www.hydra-cg.com/', + 'defines' => [ + 0 => [ + '@id' => 'hydra:Resource', + '@type' => 'hydra:Class', + 'label' => 'Hydra Resource', + 'comment' => 'The class of dereferenceable resources by means a client can attempt to dereference; however, the received responses should still be verified.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 1 => [ + '@id' => 'hydra:Class', + '@type' => [ + 0 => 'hydra:Resource', + 1 => 'rdfs:Class', + ], + 'subClassOf' => [ + 0 => 'rdfs:Class', + ], + 'label' => 'Hydra Class', + 'comment' => 'The class of Hydra classes.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 2 => [ + '@id' => 'hydra:Link', + '@type' => 'hydra:Class', + 'subClassOf' => [ + 0 => 'hydra:Resource', + 1 => 'rdf:Property', + ], + 'label' => 'Link', + 'comment' => 'The class of properties representing links.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 3 => [ + '@id' => 'hydra:apiDocumentation', + '@type' => 'hydra:Link', + 'label' => 'apiDocumentation', + 'comment' => 'A link to the API documentation', + 'range' => 'hydra:ApiDocumentation', + 'domain' => 'hydra:Resource', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 4 => [ + '@id' => 'hydra:ApiDocumentation', + '@type' => 'hydra:Class', + 'subClassOf' => 'hydra:Resource', + 'label' => 'ApiDocumentation', + 'comment' => 'The Hydra API documentation class', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 5 => [ + '@id' => 'hydra:entrypoint', + '@type' => 'hydra:Link', + 'label' => 'entrypoint', + 'comment' => 'A link to main entry point of the Web API', + 'domain' => 'hydra:ApiDocumentation', + 'range' => 'hydra:Resource', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 6 => [ + '@id' => 'hydra:supportedClass', + '@type' => 'hydra:Link', + 'label' => 'supported classes', + 'comment' => 'A class known to be supported by the Web API', + 'domain' => 'hydra:ApiDocumentation', + 'range' => 'rdfs:Class', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 7 => [ + '@id' => 'hydra:possibleStatus', + '@type' => 'hydra:Link', + 'label' => 'possible status', + 'comment' => 'A status that might be returned by the Web API (other statuses should be expected and properly handled as well)', + 'range' => 'hydra:Status', + 'domainIncludes' => [ + 0 => 'hydra:ApiDocumentation', + 1 => 'hydra:Operation', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 8 => [ + '@id' => 'hydra:supportedProperty', + '@type' => 'hydra:Link', + 'label' => 'supported properties', + 'comment' => 'The properties known to be supported by a Hydra class', + 'domain' => 'rdfs:Class', + 'range' => 'hydra:SupportedProperty', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 9 => [ + '@id' => 'hydra:SupportedProperty', + '@type' => 'hydra:Class', + 'label' => 'Supported Property', + 'comment' => 'A property known to be supported by a Hydra class.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 10 => [ + '@id' => 'hydra:property', + '@type' => 'rdf:Property', + 'label' => 'property', + 'comment' => 'A property', + 'range' => 'rdf:Property', + 'domainIncludes' => [ + 0 => 'hydra:SupportedProperty', + 1 => 'hydra:IriTemplateMapping', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 11 => [ + '@id' => 'hydra:required', + '@type' => 'rdf:Property', + 'label' => 'required', + 'comment' => 'True if the property is required, false otherwise.', + 'range' => 'xsd:boolean', + 'domainIncludes' => [ + 0 => 'hydra:SupportedProperty', + 1 => 'hydra:IriTemplateMapping', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 12 => [ + '@id' => 'hydra:readable', + '@type' => 'rdf:Property', + 'label' => 'readable', + 'comment' => 'True if the client can retrieve the property\'s value, false otherwise.', + 'domain' => 'hydra:SupportedProperty', + 'range' => 'xsd:boolean', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 13 => [ + '@id' => 'hydra:writable', + '@type' => 'rdf:Property', + 'label' => 'writable', + 'comment' => 'True if the client can change the property\'s value, false otherwise.', + 'domain' => 'hydra:SupportedProperty', + 'range' => 'xsd:boolean', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 14 => [ + '@id' => 'hydra:writeable', + 'subPropertyOf' => 'hydra:writable', + 'label' => 'writable', + 'comment' => 'This property is left for compatibility purposes and hydra:writable should be used instead.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'archaic', + ], + 15 => [ + '@id' => 'hydra:supportedOperation', + '@type' => 'hydra:Link', + 'label' => 'supported operation', + 'comment' => 'An operation supported by instances of the specific Hydra class, or the target of the Hydra link, or IRI template.', + 'range' => 'hydra:Operation', + 'domainIncludes' => [ + 0 => 'rdfs:Class', + 1 => 'hydra:Class', + 2 => 'hydra:Link', + 3 => 'hydra:TemplatedLink', + 4 => 'hydra:SupportedProperty', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 16 => [ + '@id' => 'hydra:operation', + '@type' => 'hydra:Link', + 'label' => 'operation', + 'comment' => 'An operation supported by the Hydra resource', + 'domain' => 'hydra:Resource', + 'range' => 'hydra:Operation', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 17 => [ + '@id' => 'hydra:Operation', + '@type' => 'hydra:Class', + 'label' => 'Operation', + 'comment' => 'An operation.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 18 => [ + '@id' => 'hydra:method', + '@type' => 'rdf:Property', + 'label' => 'method', + 'comment' => 'The HTTP method.', + 'domain' => 'hydra:Operation', + 'range' => 'xsd:string', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 19 => [ + '@id' => 'hydra:expects', + '@type' => 'hydra:Link', + 'label' => 'expects', + 'comment' => 'The information expected by the Web API.', + 'domain' => 'hydra:Operation', + 'rangeIncludes' => [ + 0 => 'rdfs:Resource', + 1 => 'hydra:Resource', + 2 => 'rdfs:Class', + 3 => 'hydra:Class', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 20 => [ + '@id' => 'hydra:returns', + '@type' => 'hydra:Link', + 'label' => 'returns', + 'comment' => 'The information returned by the Web API on success', + 'domain' => 'hydra:Operation', + 'rangeIncludes' => [ + 0 => 'rdfs:Resource', + 1 => 'hydra:Resource', + 2 => 'rdfs:Class', + 3 => 'hydra:Class', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 21 => [ + '@id' => 'hydra:Status', + '@type' => 'hydra:Class', + 'label' => 'Status code description', + 'comment' => 'Additional information about a status code that might be returned.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 22 => [ + '@id' => 'hydra:statusCode', + '@type' => 'rdf:Property', + 'label' => 'status code', + 'comment' => 'The HTTP status code. Please note it may happen this value will be different to actual status code received.', + 'domain' => 'hydra:Status', + 'range' => 'xsd:integer', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 23 => [ + '@id' => 'hydra:title', + '@type' => 'rdf:Property', + 'subPropertyOf' => 'rdfs:label', + 'label' => 'title', + 'comment' => 'A title, often used along with a description.', + 'range' => 'xsd:string', + 'domainIncludes' => [ + 0 => 'hydra:ApiDocumentation', + 1 => 'hydra:Status', + 2 => 'hydra:Class', + 3 => 'hydra:SupportedProperty', + 4 => 'hydra:Operation', + 5 => 'hydra:Link', + 6 => 'hydra:TemplatedLink', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 24 => [ + '@id' => 'hydra:description', + '@type' => 'rdf:Property', + 'subPropertyOf' => 'rdfs:comment', + 'label' => 'description', + 'comment' => 'A description.', + 'range' => 'xsd:string', + 'domainIncludes' => [ + 0 => 'hydra:ApiDocumentation', + 1 => 'hydra:Status', + 2 => 'hydra:Class', + 3 => 'hydra:SupportedProperty', + 4 => 'hydra:Operation', + 5 => 'hydra:Link', + 6 => 'hydra:TemplatedLink', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 25 => [ + '@id' => 'hydra:Error', + '@type' => 'hydra:Class', + 'subClassOf' => 'hydra:Status', + 'label' => 'Error', + 'comment' => 'A runtime error, used to report information beyond the returned status code.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 26 => [ + '@id' => 'hydra:Collection', + '@type' => 'hydra:Class', + 'subClassOf' => 'hydra:Resource', + 'label' => 'Collection', + 'comment' => 'A collection holding references to a number of related resources.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 27 => [ + '@id' => 'hydra:collection', + '@type' => 'hydra:Link', + 'label' => 'collection', + 'comment' => 'Collections somehow related to this resource.', + 'range' => 'hydra:Collection', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 28 => [ + '@id' => 'hydra:memberAssertion', + 'label' => 'member assertion', + 'comment' => 'Semantics of each member provided by the collection.', + 'domain' => 'hydra:Collection', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 29 => [ + '@id' => 'hydra:manages', + 'subPropertyOf' => 'hydra:memberAssertion', + 'label' => 'manages', + 'comment' => 'This predicate is left for compatibility purposes and hydra:memberAssertion should be used instead.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'archaic', + ], + 30 => [ + '@id' => 'hydra:subject', + 'label' => 'subject', + 'comment' => 'The subject.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 31 => [ + '@id' => 'hydra:object', + 'label' => 'object', + 'comment' => 'The object.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 32 => [ + '@id' => 'hydra:member', + '@type' => 'hydra:Link', + 'label' => 'member', + 'comment' => 'A member of the collection', + 'domain' => 'hydra:Collection', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 33 => [ + '@id' => 'hydra:view', + '@type' => 'hydra:Link', + 'label' => 'view', + 'comment' => 'A specific view of a resource.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 34 => [ + '@id' => 'hydra:PartialCollectionView', + '@type' => 'hydra:Class', + 'subClassOf' => 'hydra:Resource', + 'label' => 'PartialCollectionView', + 'comment' => 'A PartialCollectionView describes a partial view of a Collection. Multiple PartialCollectionViews can be connected with the the next/previous properties to allow a client to retrieve all members of the collection.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 35 => [ + '@id' => 'hydra:totalItems', + '@type' => 'rdf:Property', + 'label' => 'total items', + 'comment' => 'The total number of items referenced by a collection.', + 'domain' => 'hydra:Collection', + 'range' => 'xsd:integer', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 36 => [ + '@id' => 'hydra:first', + '@type' => 'hydra:Link', + 'label' => 'first', + 'comment' => 'The first resource of an interlinked set of resources.', + 'domain' => 'hydra:Resource', + 'range' => 'hydra:Resource', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 37 => [ + '@id' => 'hydra:last', + '@type' => 'hydra:Link', + 'label' => 'last', + 'comment' => 'The last resource of an interlinked set of resources.', + 'domain' => 'hydra:Resource', + 'range' => 'hydra:Resource', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 38 => [ + '@id' => 'hydra:next', + '@type' => 'hydra:Link', + 'label' => 'next', + 'comment' => 'The resource following the current instance in an interlinked set of resources.', + 'domain' => 'hydra:Resource', + 'range' => 'hydra:Resource', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 39 => [ + '@id' => 'hydra:previous', + '@type' => 'hydra:Link', + 'label' => 'previous', + 'comment' => 'The resource preceding the current instance in an interlinked set of resources.', + 'domain' => 'hydra:Resource', + 'range' => 'hydra:Resource', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 40 => [ + '@id' => 'hydra:search', + '@type' => 'hydra:TemplatedLink', + 'label' => 'search', + 'comment' => 'A IRI template that can be used to query a collection.', + 'range' => 'hydra:IriTemplate', + 'domain' => 'hydra:Resource', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 41 => [ + '@id' => 'hydra:freetextQuery', + '@type' => 'rdf:Property', + 'label' => 'freetext query', + 'comment' => 'A property representing a freetext query.', + 'range' => 'xsd:string', + 'domain' => 'hydra:Resource', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 42 => [ + '@id' => 'hydra:TemplatedLink', + '@type' => 'hydra:Class', + 'subClassOf' => [ + 0 => 'hydra:Resource', + 1 => 'rdf:Property', + ], + 'label' => 'Templated Link', + 'comment' => 'A templated link.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 43 => [ + '@id' => 'hydra:IriTemplate', + '@type' => 'hydra:Class', + 'label' => 'IRI Template', + 'comment' => 'The class of IRI templates.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 44 => [ + '@id' => 'hydra:template', + '@type' => 'rdf:Property', + 'label' => 'template', + 'comment' => 'A templated string with placeholders. The literal\'s datatype indicates the template syntax; if not specified, hydra:Rfc6570Template is assumed.', + 'seeAlso' => 'hydra:Rfc6570Template', + 'domain' => 'hydra:IriTemplate', + 'range' => 'hydra:Rfc6570Template', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 45 => [ + '@id' => 'hydra:Rfc6570Template', + '@type' => 'rdfs:Datatype', + 'label' => 'RFC6570 IRI template', + 'comment' => 'An IRI template as defined by RFC6570.', + 'seeAlso' => 'http://tools.ietf.org/html/rfc6570', + 'range' => 'xsd:string', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 46 => [ + '@id' => 'hydra:variableRepresentation', + '@type' => 'rdf:Property', + 'label' => 'variable representation', + 'comment' => 'The representation format to use when expanding the IRI template.', + 'range' => 'hydra:VariableRepresentation', + 'domain' => 'hydra:IriTemplateMapping', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 47 => [ + '@id' => 'hydra:VariableRepresentation', + '@type' => 'hydra:Class', + 'label' => 'VariableRepresentation', + 'comment' => 'A representation specifies how to serialize variable values into strings.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 48 => [ + '@id' => 'hydra:BasicRepresentation', + '@type' => 'hydra:VariableRepresentation', + 'label' => 'BasicRepresentation', + 'comment' => 'A representation that serializes just the lexical form of a variable value, but omits language and type information.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 49 => [ + '@id' => 'hydra:ExplicitRepresentation', + '@type' => 'hydra:VariableRepresentation', + 'label' => 'ExplicitRepresentation', + 'comment' => 'A representation that serializes a variable value including its language and type information and thus differentiating between IRIs and literals.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 50 => [ + '@id' => 'hydra:mapping', + '@type' => 'rdf:Property', + 'label' => 'mapping', + 'comment' => 'A variable-to-property mapping of the IRI template.', + 'domain' => 'hydra:IriTemplate', + 'range' => 'hydra:IriTemplateMapping', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 51 => [ + '@id' => 'hydra:IriTemplateMapping', + '@type' => 'hydra:Class', + 'label' => 'IriTemplateMapping', + 'comment' => 'A mapping from an IRI template variable to a property.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 52 => [ + '@id' => 'hydra:variable', + '@type' => 'rdf:Property', + 'label' => 'variable', + 'comment' => 'An IRI template variable', + 'domain' => 'hydra:IriTemplateMapping', + 'range' => 'xsd:string', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 53 => [ + '@id' => 'hydra:resolveRelativeUsing', + '@type' => 'rdf:Property', + 'label' => 'relative Uri resolution', + 'domain' => 'hydra:IriTemplate', + 'range' => 'hydra:BaseUriSource', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 54 => [ + '@id' => 'hydra:BaseUriSource', + '@type' => 'hydra:Class', + 'subClassOf' => 'hydra:Resource', + 'label' => 'Base Uri source', + 'comment' => 'Provides a base abstract for base Uri source for Iri template resolution.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 55 => [ + '@id' => 'hydra:Rfc3986', + '@type' => 'hydra:BaseUriSource', + 'label' => 'RFC 3986 based', + 'comment' => 'States that the base Uri should be established using RFC 3986 reference resolution algorithm specified in section 5.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 56 => [ + '@id' => 'hydra:LinkContext', + '@type' => 'hydra:BaseUriSource', + 'label' => 'Link context', + 'comment' => 'States that the link\'s context IRI, as defined in RFC 5988, should be used as the base Uri', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 57 => [ + '@id' => 'hydra:offset', + '@type' => 'rdf:Property', + 'label' => 'skip', + 'comment' => 'Instructs to skip N elements of the set.', + 'range' => 'xsd:nonNegativeInteger', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 58 => [ + '@id' => 'hydra:limit', + '@type' => 'rdf:Property', + 'label' => 'take', + 'comment' => 'Instructs to limit set only to N elements.', + 'range' => 'xsd:nonNegativeInteger', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 59 => [ + '@id' => 'hydra:pageIndex', + '@type' => 'rdf:Property', + 'subPropertyOf' => 'hydra:pageReference', + 'label' => 'page index', + 'comment' => 'Instructs to provide a specific page of the collection at a given index.', + 'range' => 'xsd:nonNegativeInteger', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 60 => [ + '@id' => 'hydra:pageReference', + '@type' => 'rdf:Property', + 'label' => 'page reference', + 'comment' => 'Instructs to provide a specific page reference of the collection.', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 61 => [ + '@id' => 'hydra:returnsHeader', + '@type' => 'rdf:Property', + 'label' => 'returns header', + 'comment' => 'Name of the header returned by the operation.', + 'domain' => 'hydra:Operation', + 'rangeIncludes' => [ + 0 => 'xsd:string', + 1 => 'hydra:HeaderSpecification', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 62 => [ + '@id' => 'hydra:expectsHeader', + '@type' => 'rdf:Property', + 'label' => 'expects header', + 'comment' => 'Specification of the header expected by the operation.', + 'domain' => 'hydra:Operation', + 'rangeIncludes' => [ + 0 => 'xsd:string', + 1 => 'hydra:HeaderSpecification', + ], + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 63 => [ + '@id' => 'hydra:HeaderSpecification', + '@type' => 'rdfs:Class', + 'subClassOf' => 'hydra:Resource', + 'label' => 'Header specification', + 'comment' => 'Specifies a possible either expected or returned header values', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 64 => [ + '@id' => 'hydra:headerName', + '@type' => 'rdf:Property', + 'label' => 'header name', + 'comment' => 'Name of the header.', + 'domain' => 'hydra:HeaderSpecification', + 'range' => 'xsd:string', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 65 => [ + '@id' => 'hydra:possibleValue', + '@type' => 'rdf:Property', + 'label' => 'possible header value', + 'comment' => 'Possible value of the header.', + 'domain' => 'hydra:HeaderSpecification', + 'range' => 'xsd:string', + 'vs:term_status' => 'testing', + ], + 66 => [ + '@id' => 'hydra:closedSet', + '@type' => 'rdf:Property', + 'label' => 'closed set', + 'comment' => 'Determines whether the provided set of header values is closed or not.', + 'domain' => 'hydra:HeaderSpecification', + 'range' => 'xsd:boolean', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + 67 => [ + '@id' => 'hydra:extension', + '@type' => 'rdf:Property', + 'label' => 'extension', + 'comment' => 'Hint on what kind of extensions are in use.', + 'domain' => 'hydra:ApiDocumentation', + 'isDefinedBy' => 'http://www.w3.org/ns/hydra/core', + 'vs:term_status' => 'testing', + ], + ], +]; diff --git a/src/JsonLd/composer.json b/src/JsonLd/composer.json index d6566f62a41..7b27cfca087 100644 --- a/src/JsonLd/composer.json +++ b/src/JsonLd/composer.json @@ -32,6 +32,9 @@ "psr-4": { "ApiPlatform\\JsonLd\\": "" }, + "files": [ + "./HydraContext.php" + ], "exclude-from-classmap": [ "/Tests/" ] diff --git a/tests/Behat/HydraContext.php b/tests/Behat/HydraContext.php index 1a208159690..a0425ac2b13 100644 --- a/tests/Behat/HydraContext.php +++ b/tests/Behat/HydraContext.php @@ -301,4 +301,26 @@ private function getLastJsonResponse(): \stdClass return $decoded; } + + /** + * @Then the Hydra context matches the online resource :url + */ + public function assertHydraContextIsCorrect(string $url): void + { + $opts = [ + 'http' => [ + 'method' => 'GET', + 'header' => "User-Agent: Mozilla/5.0\r\n", + ], + ]; + + $context = stream_context_create($opts); + $upstream = json_decode(file_get_contents($url, false, $context)); + $actual = $this->getLastJsonResponse(); + $local = $actual->{'@context'}[0]; + Assert::assertEquals( + $upstream, + $local + ); + } } diff --git a/tests/JsonLd/ContextBuilderTest.php b/tests/JsonLd/ContextBuilderTest.php index 34fe89535f6..e5ba3a59326 100644 --- a/tests/JsonLd/ContextBuilderTest.php +++ b/tests/JsonLd/ContextBuilderTest.php @@ -35,6 +35,8 @@ use Prophecy\Prophecy\ObjectProphecy; use Symfony\Component\PropertyInfo\Type; +use const ApiPlatform\JsonLd\HYDRA_CONTEXT; + /** * @author Markus Mächler */ @@ -291,7 +293,7 @@ public function testResourceContextWithoutHydraPrefix(): void $contextBuilder = new ContextBuilder($this->resourceNameCollectionFactoryProphecy->reveal(), $this->resourceMetadataCollectionFactoryProphecy->reveal(), $this->propertyNameCollectionFactoryProphecy->reveal(), $this->propertyMetadataFactoryProphecy->reveal(), $this->urlGeneratorProphecy->reveal(), null, null, [ContextBuilder::HYDRA_CONTEXT_HAS_PREFIX => false]); $expected = [ - 'http://www.w3.org/ns/hydra/context.jsonld', + HYDRA_CONTEXT, [ '@vocab' => '#', 'hydra' => 'http://www.w3.org/ns/hydra/core#', diff --git a/update-hydra-context.php b/update-hydra-context.php new file mode 100644 index 00000000000..f1e5013c205 --- /dev/null +++ b/update-hydra-context.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +$opts = [ + 'http' => [ + 'method' => 'GET', + 'header' => "User-Agent: Mozilla/5.0\r\n", + ], +]; + +$context = stream_context_create($opts); +$hydraContext = json_decode(file_get_contents('http://www.w3.org/ns/hydra/context.jsonld', false, $context), true); +file_put_contents('src/JsonLd/HydraContext.php', '