CustomOperationHydraFactory marks namespaced item routes as custom actions.
isCustomOperation() decides by counting URI segments:
// /resource/{id}
if (2 === $count && str_starts_with($segments[1], '{')) {
return false;
}
return true;
That only recognises an item route when the resource sits at the URI root. A resource under a namespace has three segments, so its plain item GET is classified as a custom action and gets @type: ["hydra:Operation", "schema:Action"].
Observed in mlr/za7-fogu-api (bundle 0.3.1) — five facade resources, each with exactly one bogus "action" that is just its item route:
FoguFacadeVorgang ACTION [GET] /api/fogu/vorgang/{businessKey}
FoguFacadeAufgabe ACTION [GET] /api/fogu/aufgabe/{taskId}
FoguFacadeBenutzer ACTION [GET] /api/fogu/benutzer/{id}
FoguFacadeJob ACTION [GET] /api/fogu/job/{id}
FoguFacadeProtokoll ACTION [GET] /api/fogu/protokoll/{id}
Consequence for consumers: hrzg/vue-za7-admin-ui renders these in the Actions dropdown, so every namespaced resource carries one meaningless entry. No wrong behaviour — clicking it issues the GET it already offers — but it makes the dropdown untrustworthy, and a real custom action is harder to spot among the noise.
Suggested fix: decide on the last segment rather than the count — a URI whose final segment is a placeholder is an item route regardless of depth. Collection routes stay covered by the 1 === $count branch only if the resource is at the root, so that branch needs the same treatment (compare against the resource's own collection template instead of assuming depth 1).
Worth a test matrix over /a, /a/{id}, /a/b, /a/b/{id}, /a/b/verb — the middle two are the ones that currently disagree with intent.
CustomOperationHydraFactorymarks namespaced item routes as custom actions.isCustomOperation()decides by counting URI segments:That only recognises an item route when the resource sits at the URI root. A resource under a namespace has three segments, so its plain item GET is classified as a custom action and gets
@type: ["hydra:Operation", "schema:Action"].Observed in
mlr/za7-fogu-api(bundle 0.3.1) — five facade resources, each with exactly one bogus "action" that is just its item route:Consequence for consumers:
hrzg/vue-za7-admin-uirenders these in the Actions dropdown, so every namespaced resource carries one meaningless entry. No wrong behaviour — clicking it issues the GET it already offers — but it makes the dropdown untrustworthy, and a real custom action is harder to spot among the noise.Suggested fix: decide on the last segment rather than the count — a URI whose final segment is a placeholder is an item route regardless of depth. Collection routes stay covered by the
1 === $countbranch only if the resource is at the root, so that branch needs the same treatment (compare against the resource's own collection template instead of assuming depth 1).Worth a test matrix over
/a,/a/{id},/a/b,/a/b/{id},/a/b/verb— the middle two are the ones that currently disagree with intent.