Vnitřní relace
V kapitolách Principy modelování jsme na téma vnitřních relací již narazili. Tedy již patrně víte, že entita může mít (v praxi často má) své subentity a ty mohou mít další subentity a že mezi těmito entitami jsou vztahy, kterým se říká vnitřní relace.
V kapitole Principy modelování jsme si ukazovali příklad faktury. A toho se budeme držet i zde, jen si totéž rozebereme do detailu a ukážeme si reálnou podobu definic.
Připomeňme si uspořádání entity faktura:
A teď si již ukažme jednotlivé definice entity (subentit), které určují vnitřní relaci.
Hlavní entita
Faktura musí mít:
- Vlastní identifikátor - tedy ID faktury.
- Číslo dokladu pro účetnictví
- Datum vystavení faktury
- Datum splatnosti faktury
- ID zákazníka
- Fakturační údaje zákazníka platné v době vystavení faktury
- ... a celou řadu dalších údajů (pro stručnost definice nebude obsahovat vše)
namespace JetApplication;
use Jet\DataModel;
use Jet\DataModel_Definition;
use Jet\DataModel_Fetch_Instances;
use Jet\DataModel_IDController_AutoIncrement;
use Jet\Form;
use Jet\Form_Field;
use Jet\Data_DateTime;
#[DataModel_Definition(
name: 'invoice',
database_table_name: 'invoice',
id_controller_class: DataModel_IDController_AutoIncrement::class,
id_controller_options: [
'id_property_name' => 'invoice_id'
]
)]
class Invoice extends DataModel
{
#[DataModel_Definition(
type: DataModel::TYPE_ID_AUTOINCREMENT,
is_id: true
)]
protected int $invoice_id = 0;
#[DataModel_Definition(
type: DataModel::TYPE_STRING,
is_key: true,
max_len: 50
)]
protected string $invoice_number = '';
#[DataModel_Definition(
type: DataModel::TYPE_DATE
)]
protected ?Data_DateTime $date_of_invoice = null;
#[DataModel_Definition(
type: DataModel::TYPE_DATE
)]
protected ?Data_DateTime $expiry_date = null;
#[DataModel_Definition(
type: DataModel::TYPE_INT,
is_key: true
)]
protected int $customer_id = 0;
#[DataModel_Definition(
type: DataModel::TYPE_STRING,
max_len: 255
)]
protected string $customer_name = '';
#[DataModel_Definition(
type: DataModel::TYPE_DATA_MODEL,
data_model_class: Invoice_Items::class
)]
protected array $items = [];
#[DataModel_Definition(
type: DataModel::TYPE_DATA_MODEL,
data_model_class: Invoice_Payments::class
)]
protected array $payments = [];
//...........
}
Za pozornost stojí zejména vlastnost $items (a také $payments - stejný princip). Ta navazuje subentitu invoice_item (položky faktury) směrem dolů v relaci 1:N.
Subentita 1. úrovně
V našem příkladu je subentita 1. úrovně (tedy přímo náležící pod hlavní entitu) položka faktury. Co o položce faktury potřebujeme vědět?
- Určitě musí mít vlastní ID
- Je nutné vědět, k jaké faktuře patří. Tedy znát ID nadřazené entity.
- Určitě bude mít několik dalších specifických parametrů jako například popis, cenu za jednotku, počet jednotek a tak dále.
namespace JetApplication;
use Jet\DataModel;
use Jet\DataModel_Definition;
use Jet\DataModel_IDController_AutoIncrement;
use Jet\DataModel_Related_1toN;
#[DataModel_Definition(
name: 'invoice_items',
database_table_name: 'invoice_items',
parent_model_class: Invoice::class,
id_controller_class: DataModel_IDController_AutoIncrement::class,
id_controller_options: [
'id_property_name' => 'item_id'
]
)]
class Invoice_Items extends DataModel_Related_1toN
{
#[DataModel_Definition(
type: DataModel::TYPE_ID_AUTOINCREMENT,
is_id: true
)]
protected int $item_id = 0;
#[DataModel_Definition(
related_to: 'main.invoice_id',
is_key: true
)]
protected int $invoice_id = 0;
#[DataModel_Definition(
type: DataModel::TYPE_INT,
is_key: true
)]
protected int $goods_id = 0;
#[DataModel_Definition(
type: DataModel::TYPE_STRING,
max_len: 255
)]
protected string $item_name = '';
#[DataModel_Definition(
type: DataModel::TYPE_FLOAT
)]
protected float $price_per_unit = 0.0;
#[DataModel_Definition(
type: DataModel::TYPE_FLOAT
)]
protected float $number_of_units = 0.0;
#[DataModel_Definition(
type: DataModel::TYPE_FLOAT
)]
protected float $vat_rate = 0.0;
public function getArrayKeyValue() : string
{
return $this->item_id;
}
//... ... ...
}
A tady už je to trochu zajímavější. Subentita musí definovat návaznost na rodičovskou entitu a to dvěma způsoby:
První je definice rodiče (rodičovské třídy) v atributech třídy:
#[DataModel_Definition(
.... ... ...
parent_model_class: Invoice::class
)]
A druhou nutností je definovat návaznost příslušné vlastnosti (nebo vlastností) na ID vlastnost (nebo vlastnosti) nadřazené entity a to takto:
#[DataModel_Definition(
related_to: 'main.invoice_id',
is_key: true
)]
protected int $invoice_id = 0;
Subentita 2. úrovně (a libovolné další úrovně)
A nyní si ukážeme jak řešit situaci, kdyby položka faktory měla další na ni navázanou subentitu.
- Musí znát ID nadřazené entity - tedy ID položky faktory.
- Musí znát ID hlavní entity - tedy ID faktury.
- A samozřejmě další specifické vlastnosti dané subentity.
namespace JetApplication;
use Jet\DataModel;
use Jet\DataModel_Definition;
use Jet\DataModel_IDController_Passive;
use Jet\DataModel_Related_1toN;
#[DataModel_Definition(
name: 'invoice_items_subentty',
database_table_name: 'invoice_items_subentty',
parent_model_class: Invoice_Items::class,
id_controller_class: DataModel_IDController_Passive::class,
)]
class Invoice_Items_Subentty extends DataModel_Related_1toN
{
#[DataModel_Definition(
type: DataModel::TYPE_STRING,
is_id: true
)]
protected string $subitem_id = '';
#[DataModel_Definition(
related_to: 'main.invoice_id',
is_key: true
)]
protected int $invoice_id = 0;
#[DataModel_Definition(
related_to: 'parent.item_id',
is_key: true
)]
protected int $item_id = 0;
#[DataModel_Definition(
type: DataModel::TYPE_STRING,
max_len: 255
)]
protected string $something = '';
public function getArrayKeyValue() : string
{
return $this->subitem_id;
}
//... ... ...
}
Důležitá je dvojí vazba. Subentita 2. a každé další úrovně musí být vázána na svou přímo nadřazenou (rodičovskou) entitu:
#[DataModel_Definition(
related_to: 'parent.item_id',
is_key: true
)]
protected int $item_id = 0;
Stejně tak jako musí být vázána na entitu hlavní:
#[DataModel_Definition(
related_to: 'main.invoice_id',
is_key: true
)]
protected int $invoice_id = 0;
Shrnutí
Pro vnitřní vazby stačí dodržovat tyto principy:
- Z rodiče definovat vazbu na potomka pomocí k tomu určené vlastnosti třídy.
- Z potomka definovat vazbu na rodiče atributu třídy.
- Provázat příslušné vlastnosti potomka na ID vlastnosti rodiče.
- V každé další úrovni subentit vždy provázat příslušné vlastnosti na ID vlastnosti hlavní entity.
A pozor, dobrá zpráva! Nic z toho nemusíte dělat ručně ;-) Vše za vás vyřeší nástroj Jet Studio.