Skip to content

Commit 680544f

Browse files
test(api): add regression test for owl:onProperty bare term bug
Adds a failing PHPUnit test that exposes the bug in api-platform/hydra's DocumentationNormalizer: with hydra_prefix disabled (default), owl:onProperty is emitted as {"@id": "member"} instead of {"@id": "hydra:member"}, which jsonld.js cannot expand to hydra:member (vocab=false for @id values), causing api-doc-parser to throw and HydraAdmin to fail to initialize. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4a9060d commit 680544f

2 files changed

Lines changed: 77 additions & 2 deletions

File tree

api/config/reference.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -993,8 +993,8 @@
993993
* }
994994
* @psalm-type MercureConfig = array{
995995
* hubs?: array<string, array{ // Default: []
996-
* url?: scalar|Param|null, // URL of the hub's publish endpoint
997-
* public_url?: scalar|Param|null, // URL of the hub's public endpoint // Default: null
996+
* url?: scalar|Param|null, // URL of the hub's publish endpoint // Default: null
997+
* public_url?: scalar|Param|null, // URL of the hub's public endpoint
998998
* jwt?: string|array{ // JSON Web Token configuration.
999999
* value?: scalar|Param|null, // JSON Web Token to use to publish to this hub.
10001000
* provider?: scalar|Param|null, // The ID of a service to call to provide the JSON Web Token.

api/tests/Api/HydraDocumentationTest.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,81 @@ public function hydraDocumentationIsValid(): void
5858
self::assertNotContains('https://schema.org/Person', $classNames, 'User should not use full IRI as class name');
5959
}
6060

61+
/**
62+
* Regression test for api-platform/hydra DocumentationNormalizer bug.
63+
*
64+
* When `serializer.hydra_prefix` is false (the default since API Platform 4.x), the
65+
* `DocumentationNormalizer` emits:
66+
*
67+
* "owl:onProperty": {"@id": "member"}
68+
*
69+
* instead of:
70+
*
71+
* "owl:onProperty": {"@id": "hydra:member"}
72+
*
73+
* The bare term `"member"` cannot be expanded by jsonld.js to
74+
* `http://www.w3.org/ns/hydra/core#member` because `@id` values are expanded
75+
* with `vocab=false`, which skips term definitions. Only compact IRIs (prefix:localname)
76+
* are always resolved. This causes `@api-platform/api-doc-parser`'s `findRelatedClass`
77+
* to throw "Cannot find the class related to …#Entrypoint/book", breaking HydraAdmin.
78+
*
79+
* @see https://github.com/api-platform/hydra/blob/main/src/Serializer/DocumentationNormalizer.php
80+
*/
81+
#[Test]
82+
public function entrypointOwlOnPropertyIsMemberCompactIriNotBareTerm(): void
83+
{
84+
$response = $this->client->request('GET', '/docs.jsonld');
85+
86+
self::assertResponseIsSuccessful();
87+
88+
$docs = $response->toArray();
89+
90+
// Find the Entrypoint class in supportedClass
91+
$entrypointClass = null;
92+
foreach ($docs['supportedClass'] as $class) {
93+
if ('#Entrypoint' === ($class['@id'] ?? null)) {
94+
$entrypointClass = $class;
95+
break;
96+
}
97+
}
98+
99+
self::assertNotNull($entrypointClass, 'Entrypoint class should exist in supportedClass');
100+
101+
$supportedProperties = $entrypointClass['supportedProperty'] ?? [];
102+
self::assertNotEmpty($supportedProperties, 'Entrypoint should have supported properties');
103+
104+
foreach ($supportedProperties as $supportedProperty) {
105+
$property = $supportedProperty['property'] ?? null;
106+
if (null === $property) {
107+
continue;
108+
}
109+
110+
foreach ($property['range'] ?? [] as $rangeEntry) {
111+
$onPropertyId = $rangeEntry['owl:equivalentClass']['owl:onProperty']['@id'] ?? null;
112+
if (null === $onPropertyId) {
113+
continue;
114+
}
115+
116+
// A bare "member" cannot be expanded to http://www.w3.org/ns/hydra/core#member
117+
// by jsonld.js because @id values are resolved with vocab=false (term definitions
118+
// are ignored). Only compact IRIs like "hydra:member" or the full IRI work.
119+
// Fix in DocumentationNormalizer: replace `$hydraPrefix.'member'` with `'hydra:member'`
120+
// (or ContextBuilderInterface::HYDRA_NS.'member') for owl:onProperty.
121+
self::assertNotSame(
122+
'member',
123+
$onPropertyId,
124+
\sprintf(
125+
'owl:onProperty @id for entrypoint property "%s" is the bare term "member". '
126+
.'jsonld.js cannot expand it to http://www.w3.org/ns/hydra/core#member '
127+
.'(@id values use vocab=false, which skips term definitions). '
128+
.'Use "hydra:member" instead.',
129+
$property['@id'] ?? '?'
130+
)
131+
);
132+
}
133+
}
134+
}
135+
61136
#[Test]
62137
public function booksResourceHasCorrectShortNameAndTypes(): void
63138
{

0 commit comments

Comments
 (0)