feat(12.2-03): add parent-scoped child show, update, delete and pivot routes

- loadChild finds a child with one query carrying the parent predicate; a foreign child is 404
- GET/PUT .../records/{child} and POST .../delete (all or nothing) per relation kind
- hasMany link adopts NULL-key rows and unlink clears the key; pending created children are never candidates
- link accepts pivot values for one id through the pivot.form whitelist; GET/PUT .../pivot/{child}
- Link and Unlink share linkRelated/unlinkRelated for the deferred commit
This commit is contained in:
Jakub Zych
2026-10-02 18:44:34 +02:00
parent 48a5b8045a
commit afb05b6ee4
13 changed files with 2327 additions and 90 deletions

View File

@@ -99,15 +99,18 @@ func TestPhase10Coverage(t *testing.T) {
"POST /{vendor}/{plugin}/{controller}/widgets/{field}",
"POST /{vendor}/{plugin}/{controller}/{id}/files/{field}",
"POST /{vendor}/{plugin}/{controller}/{id}/files/{field}/reorder",
"POST /{vendor}/{plugin}/{controller}/{id}/relations/{name}/delete",
"POST /{vendor}/{plugin}/{controller}/{id}/relations/{name}/link",
"POST /{vendor}/{plugin}/{controller}/{id}/relations/{name}/records",
"POST /{vendor}/{plugin}/{controller}/{id}/relations/{name}/unlink",
"PUT /settings/{code}",
"PUT /{vendor}/{plugin}/{controller}/{id}",
"PUT /{vendor}/{plugin}/{controller}/{id}/files/{field}/{file}",
"PUT /{vendor}/{plugin}/{controller}/{id}/relations/{name}/pivot/{child}",
"PUT /{vendor}/{plugin}/{controller}/{id}/relations/{name}/records/{child}",
}
if strings.Join(unsafe, "\n") != strings.Join(want, "\n") {
t.Fatalf("unsafe routes changed; extend TestPhase10CSRF (it expects 16 besides login):\n%s", strings.Join(unsafe, "\n"))
t.Fatalf("unsafe routes changed; extend TestPhase10CSRF (it expects 19 besides login):\n%s", strings.Join(unsafe, "\n"))
}
// The routes added in Phase 10 are safe reads: GET /lang and the shared
// nested pattern serving field options, filter options and relation lists.