📑 Master-Detail Relationship in Ragnos
This guide explains how to create a screen where you have a main record (like a Purchase Order) and a list of related items (the Details or products of that order).
Relationship Architecture
(Orders)"] Master -->|Renders| View["Main View"] View -->|Contains| Form["Master Form"] subgraph Linkage ["Linkage Logic"] direction TB Form -->|"Order ID"| Logic{"Order Exists?"} Logic -- NO --> Info("Only shows Form") Logic -- "YES (ID=100)" --> LoadDetails["Load Detail Controller"] end LoadDetails -->|"Injects ID=100 as $this->master"| Detail["Detail Controller
(OrderDetails)"] subgraph Detail ["Detail Zone"] direction TB Detail -->|Apply Filter| Filter["WHERE orderNumber = 100"] Filter -->|Shows| Grid["Product Grid"] Grid -->|New Record| NewLine["Detail Form"] NewLine -->|Hidden Field| Hidden["orderNumber = 100"] end %% Professional Styles classDef mainNode fill:#f9f,stroke:#333,stroke-width:2px; classDef detailNode fill:#bbf,stroke:#333,stroke-width:2px; classDef logicNode fill:#fff9c4,stroke:#fbc02d,stroke-width:2px; style Master fill:#e1bee7,stroke:#4a148c,stroke-width:2px style Detail fill:#bbdefb,stroke:#0d47a1,stroke-width:2px style Hidden fill:#c8e6c9,stroke:#2e7d32,stroke-dasharray: 5 5
The basic idea is to have two controllers:
- The Master (Orders): Controls general information (date, customer, total).
- The Detail (OrderDetails): Controls the list of products within that order.
1. Configuring the Master (Orders Controller)
This is the "parent" of the relationship. Here we define the invoice header.
- Basic Configuration: We tell Ragnos to use the
orderstable and that the primary key isorderNumber. - Fields: We define normal fields like date (
orderDate), status (status), and customer (customerNumber). - Total Field (Calculated): To show the order total without saving it manually, we use a small SQL query within the field configuration. This query sums
quantity * pricefrom the details table. - Activate Detail Mode:
There is a key line you must add to your master controller to warn that it will have "children":
This tells Ragnos that the
OrderDetailscontroller will handle the details related to each order. The relationship is based on theorderNumberfield in both controllers being the same, and this is the primary key in the master.
2. Configuring the Detail (OrderDetails Controller)
This is the "child". It controls each product line.
- The Hidden Field Trick:
We need each product to know which order it belongs to. For that, in the
orderNumberfield of the detail, we do two things: - We set it as
hiddenso the user doesn't touch it. - We assign the default value
$this->master. What does this do? When you create a detail from order #100, Ragnos automatically fills this field with the number 100. - Filter Data:
We don't want to see all products from all orders. In the
_filters()method, we add a rule so that only products matching the current master ID ($this->master) are loaded.
In this snippet, $this->modelo->builder() allows you to interact directly with the SQL query that the grid will generate. The $this->master variable is automatically injected by the framework when it detects that this controller is running as a "child", and contains the ID of the record being viewed in the master (in this case, the order number).
- Update Changes:
We use special functions (called hooks) like
_afterInsertor_afterUpdateto clear the cache. This ensures that if you add a product, the main order total is recalculated correctly. 👉 See Hooks Guide
Custom JavaScript Hooks (Optional)
The following function has been added to the custom.js file: