PHP Jet Framework

rychle, jednoduše, přímo, bezpečně, efektivně
čeština
Jak začít Dokumentace Ke stažení Kontakt Diskuze / Fórum Blog
Dokumentace

Vnitřní relace

V kapitolách Principy modelování a Definice 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 reálný příklad z chystané e-commerce platformy Jet Shop a to příklad číselníku. 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 číselník:

A teď si již ukažme jednotlivé definice entity (subentit), které určují vnitřní relaci.

Hlavní entita

Číselník e-shopu musí mít:

  • Vlastní identifikátor - tedy ID číselníku.
  • Interní název číselníku (např.: barvy, velikosti, ....)
  • A samotný seznam možností. Tedy seznam subenetit.
Základ definice této entity může mít třeba tuto podobu (příklad z chystané platformy Jet Shop): namespace JetShop;

use 
Jet\DataModel;
use 
Jet\DataModel_Definition;
use 
Jet\DataModel_IDController_AutoIncrement;

#[
DataModel_Definition(
    
name'option_group',
    
database_table_name'option_groups',
    
id_controller_classDataModel_IDController_AutoIncrement::class,
    
id_controller_options: ['id_property_name'=>'id']
)]
class 
OptionGroup extends DataModel {

    #[
DataModel_Definition(
        
typeDataModel::TYPE_ID_AUTOINCREMENT,
        
is_idtrue,
    )]
    protected 
int $id 0;

    #[
DataModel_Definition(
        
typeDataModel::TYPE_STRING,
        
max_len100,
    )]
    #[
Form_Definition(
        
typeForm_Field::TYPE_INPUT,
        
label'Name:'
    
)]
    protected 
string $name '';

    
/**
     * @var OptionGroup_Option[]
     */
    
#[DataModel_Definition(
        
typeDataModel::TYPE_DATA_MODEL,
        
data_model_classOptionGroup_Option::class,
    )]
    protected array 
$options = [];
    
    
// ... ... ...
}

Na definici hlavní entity není nic zvláštního, kromě vlastnosti $options. Ta navazuje subentitu option_group_option směrem dolů - tedy od nadřazené entity po podřízenou entity a v rámci této vlastnosti (jedná se o relaci 1:N - tedy jde o pole) budou instance subentit - tedy samotné možnosti (barvy, velikosti a tak dále).

Subentita 1. úrovně

V našem příkladu je subentita 1. úrovně (tedy přímo náležící pod hlavní entitu) definice možnosti v rámci daného číselníku. Co o takové možnosti potřebujeme vědět?

  • Určitě musí mít vlastní ID (aby bylo jasné např. o jakou barvu jde)
  • Je nutné vědět, do jakého číselníku patří. Tedy znát ID nadřazené entity.
  • Určitě bude mít několik dalších specifických parametrů jako například příznak zda je aktivní, jakou má prioritu a tak dále.
  • A protože jsme v Evropě (ne-li ve světě), tak určitě potřebujeme nějak lokalizovat popisky a další údaje pro různé jazyky. Ovšem to již budou další subentity.
Ukažme si to názorně: namespace JetShop;

use 
Jet\DataModel_Definition;
use 
Jet\DataModel;
use 
Jet\DataModel_IDController_AutoIncrement;
use 
Jet\DataModel_Related_1toN;

#[
DataModel_Definition(
    
name'option_group_option',
    
database_table_name'option_groups_options',
    
id_controller_classDataModel_IDController_AutoIncrement::class,
    
id_controller_options: ['id_property_name'=>'id'],
    
default_order_by: ['priority'],
    
parent_model_classOptionGroup::class
)]
class 
OptionGroup_Option extends DataModel_Related_1toN {

    #[
DataModel_Definition(
        
typeDataModel::TYPE_ID_AUTOINCREMENT,
        
is_idtrue,
    )]
    protected 
int $id 0;

    #[
DataModel_Definition(
        
typeDataModel::TYPE_INT,
        
is_keytrue,
        
related_to'main.id'
    
)]
    protected 
int $option_group_id 0;

    #[
DataModel_Definition(
        
typeDataModel::TYPE_BOOL,
    )]
    #[
Form_Definition(
        
typeForm_Field::TYPE_INPUT,
        
label'Is active'
    
)]
    protected 
bool $is_active true;

    #[
DataModel_Definition(
        
typeDataModel::TYPE_INT,
        
is_keytrue,
    )]
    protected 
int $priority 0;

    
/**
     * @var OptionGroup_Option_Localized[]
     */
    
#[DataModel_Definition(
        
typeDataModel::TYPE_DATA_MODEL,
        
data_model_classOptionGroup_Option_Localized::class
    )]
    #[
Form_Definition(is_sub_formstrue)]
    protected array 
$localized = [];

    
//... ... ...
}

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_classOptionGroup::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.id'
)]
protected 
int $option_group_id 0;

Jak jsme si již řekli, tak tato subentita má svou subenetitu a platí zde to samé co pro hlavní entitu. Tedy musí definovat návaznost rodič - potomek a to vlastností $localized. Princip je zcela totožný jako u hlavní entity: /**
 * @var OptionGroup_Option_Localized[]
 */
#[DataModel_Definition(
    
typeDataModel::TYPE_DATA_MODEL,
    
data_model_classOptionGroup_Option_Localized::class
)]
#[
Form_Definition(is_sub_formstrue)]
protected array 
$localized = [];

Subentita 2. úrovně (a libovolné další úrovně)

A konečně jsme u subentity subentity. Tedy v našem příkladu u lokalizovaných dat možností z číselníku. Tak co o této subentitě potřebujeme vědět?

  • Nemusí mít své vlastní ID (ve smyslu například autoincrement id). Záznam bude identifikován na základě ostatních údajů. (ale není to dogma, jakákoliv subentita může mít identifikaci záznamu jakoukoliv - jde pouze o tento konkrétní příklad).
  • Musí znát ID nadřazené entity - tedy ID možnosti z číselníku.
  • Musí znát ID hlavní entity - tedy ID číselníku (viz princip modelování).
  • V našem konkrétním případě musí znát kód lokalizace ke kterému popisky (a další údaje) náleží.
  • A samozřejmě ty vlastnosti, které chceme lokalizovat (popisky, nápovědy a tak dále).
Opět si to ukažme názorně: namespace JetShop;

use 
Jet\DataModel;
use 
Jet\DataModel_Definition;
use 
Jet\DataModel_Related_1toN;
use 
Jet\DataModel_IDController_Passive;
use 
Jet\Locale;

#[
DataModel_Definition(
    
name'option_group_option_localized',
    
database_table_name'option_groups_options_localized',
    
id_controller_classDataModel_IDController_Passive::class,
    
parent_model_classOptionGroup_Option::class
)]
class 
OptionGroup_Option_Localized extends DataModel_Related_1toN {


    #[
DataModel_Definition(
        
typeDataModel::TYPE_INT,
        
is_idtrue,
        
related_to'main.id',
    )]
    protected 
int $option_group_id 0;
    
    #[
DataModel_Definition(
        
typeDataModel::TYPE_INT,
        
is_idtrue,
        
related_to'parent.id',
    )]
    protected 
int $option_id 0;

    #[
DataModel_Definition(
        
typeDataModel::TYPE_LOCALE,
        
is_idtrue
    
)]
    protected ?
Locale $locale null;


    #[
DataModel_Definition(
        
typeDataModel::TYPE_STRING,
        
max_len255
    
)]
    protected 
string $filter_label '';
    
    
//... ... ...

}

V atributech třídy jste si patrně všimli pasivního ID kontroleru - to je však specifikum daného použití a daného příkladu. Může být použit jakýkoliv ID kontroler a systém identifikace záznamu.

Jinak návaznost na rodiče je stejná jako u subentity předchozí úrovně. Princip platí dále až do úrovně X. Je stále stejný.

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(
    
typeDataModel::TYPE_INT,
    
is_idtrue,
    
related_to'parent.id'//** !!!!!!! **
)]
protected 
int $option_id 0;

Stejně tak jako musí být vázána na entitu hlavní: #[DataModel_Definition(
    
typeDataModel::TYPE_INT,
    
is_idtrue,
    
related_to'main.id'//** !!!!!!! **
)]
protected 
int $option_group_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.
Krom toho není třeba vnitřní relace extra definovat.

Předchozí kapitola
ID kontrolery
Další kapitola
Vnější relace