feat(12.2-03): add hasMany relation contracts, relation forms and child create

- RelationContract gains Kind (empty is belongsToMany) and ForeignKey, with kind-aware boot checks
- manage.form, view.form and pivot.form compile against the related or pivot model; $/ paths resolve inside the plugin
- view toolbarButtons accept create|update|delete|link|unlink, each the capability of its routes
- POST .../relations/{name}/records creates a child through the manage form; the server sets the hasMany key
- relation schema carries kind, deferrable and the localized forms; 17 new relation message keys in en and pl
This commit is contained in:
Jakub Zych
2026-10-02 18:37:13 +02:00
parent 0b4ef9c311
commit 48a5b8045a
23 changed files with 1621 additions and 100 deletions

View File

@@ -275,6 +275,10 @@ func (s *service) mount(r pact.Router) {
constrainRelation(g)
g.Post("/{vendor}/{plugin}/{controller}/{id}/relations/{name}/unlink", requireAjax(s.relationUnlink))
constrainRelation(g)
// Relation child routes (D-11, D-12): create through the relation's
// manage form.
g.Post("/{vendor}/{plugin}/{controller}/{id}/relations/{name}/records", requireAjax(s.relationChildCreate))
constrainRelation(g)
// File routes of `type: fileupload` fields (D-09). {id} 0 is the
// record being created in the X-Session-Key session.
g.Post("/{vendor}/{plugin}/{controller}/{id}/files/{field}", requireAjax(s.fileUpload))
@@ -577,7 +581,7 @@ func (s *service) relations() (RelationService, error) {
if err != nil {
return RelationService{}, err
}
return RelationService{DB: db}, nil
return RelationService{DB: db, bucket: s.bucket(), tr: s.translator()}, nil
}
func (s *service) formSchema(w http.ResponseWriter, r *http.Request) {