Definice

Obdobně jako například konfigurační systém aplikace využívá i Jet DataModel atributy (PHP 8) pro které má Jet svou malou nadstavbu Jet\Attributes.

I zde platí, že definiční atributy musí mít jak třída reprezentující konkrétní datovou entitu, tak její její vlastnosti, které představují (dá se říct) datové sloupce. (Pochopitelně třída může mít i vlastnosti, které nemají s DataModel nic společného a jsou určené například pouze pro interní potřeby logiky třídy).

V případě Jet DataModel jsou samozřejmě možnosti definic o poznání širší než v případě zmíněného konfiguračního systému. Ale mám pro vás dobrou zprávu. Protože definice datových entit je vlastně základní práce při návrhu aplikace, tak Jet Studio samozřejmě disponuje nástrojem, kde se vše dá "naklikat" a ušetřit si tak opravdu spoustu času.

Tedy není nutné znát všechny definice nazpaměť. Ale je dobré znát princip jak to funguje a ideálně si umět poradit i bez nástroje Jet Studio.

Definice třídy (a entity jako takové)

Definice třídy - entity samotné je úplný základ a zahrnuje několik atributů, které musí být definovány. Zde je ukázka definice velice jednoduché entity article (článek) z ukázkové aplikace, jde o třídu JetApplication\Content_Article. namespace JetApplication;

use 
Jet\DataModel;
use 
Jet\DataModel_Definition;
use 
Jet\DataModel_IDController_UniqueString;

/**
 *
 */
#[DataModel_Definition(
    
name'article',
    
database_table_name'articles',
    
id_controller_classDataModel_IDController_UniqueString::class,
    
id_controller_options: [
        
'id_property_name' => 'id'
    
]
)]
class 
Content_Article extends DataModel
{
      
// ... ... ...
}

V první řadě entita musí dědit od třídy Jet\DataModel, nebo pokud je to vnitřní relace a tedy subentita, pak buď od třídy Jet\DataModel_Related_1toN, nebo Jet\DataModel_Related_1to1 podle toho o jakou vnitřní relaci se jedná.

A teď už se pojďme kouknout jaké atributy třída musí mít a jaké mít může.

name

Jedná se o povinný atribut. Každá datová entita potřebuje nějaké interní pojmenování nezávislé na názvu třídy. Pojmenování pak slouží při odkazování na entity a jejich vlastnosti například při tvorbě dotazů. Jméno nemusí být unikátní v rámci celé vaší aplikace. Pokud budou existovat dvě třídy dědící od DataModel, budou mít stejný název entity, ale reálně se spolu tak říkajíc "nesetkají", tak to není problém. Ovšem rozhodně lze doporučit jména vytvářet unikátní a výstižná.

database_table_name

Opět se jedná o povinný atribut. Jak název napovídá, tak takto je definován název databázové tabulky ve které budou data entity pomocí backendu fyzicky uložena. Nebo jednoduše řečeno: název databázové tabulky, které k dané třídě patří.

V praxi to bude většinou stejná hodnota jako název entity, ale není to nutné. Entita může mít jiný název než tabulka. K čemu je to dobré? V určitých situacích může být entita uložena v několikra různých tabulkách s různými názvy a až při inicializaci aplikace lze vybrat, se kterou tabulkou bude aplikace reálně pracovat. Ale díky tomu, že v dotazech se používá název entity a ne název tabulky, tak aplikace může zůstat konstantní a transparentní - je možné změnit název tabulky (třeba i dynamicky), ale není nutné upravovat aplikaci (tedy měnit podobu dotazů).

id_controller_class

Taktéž povinný atribut. ID kontrolery jsou samostatné téma. Tedy zde pouze stručně, že tato vlastnost určije název třídy použitého ID kontroleru.

id_controller_options

Opět kontext se samostatným tématem ID kontrolerů jsou samostatné téma. ID kontroler může vyžadovat další nastavení. V takovém případě je tento atribut povinný.

parent_model_class

Tento atribut se týká pouze subentit, tedy o vnitřní relace a tedy potomky třídy Jet\DataModel_Related_1toN, nebo Jet\DataModel_Related_1to1. Pro subenetity je atribut povinný a určuje jaká entita je dané subentitě přímo nadřazená - tedy jaká já třída je rodičovská.

Ukažme si to opět konkrétně na reálném příkladu z ukázkové aplikace. Entita článek / article počítá s tím, že může mít víc lokalizací. Tedy hlavní třída JetApplication\Content_Article zastřešuje obecné věci a agreguje subentity představující již obsah vázaní na konkrétní lokalizace. Takový obsah představuje třída JetApplication\Content_Article_Localized.: namespace JetApplication;

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

#[
DataModel_Definition(
    
name'article_localized',
    
database_table_name'articles_localized',
    
id_controller_classDataModel_IDController_Passive::class,
    
parent_model_classContent_Article::class
)]
class 
Content_Article_Localized extends DataModel_Related_1toN
{
     
//... ... ... ... 
}
A jak vidíte, je jasně definováno jaká třída je nadřazenou entitou.

default_order_by

Tento atribut se týká pouze subentity ve vnitřní relaci 1:N. Definuje řazení subentit při jejich načítání z databáze. Definice řazení je stejná jako při obecném načítání.

relation

Definuje vnější relaci, tedy provázání s jinou entitou, která není k dané entitě podřízená, což si opět říká o samostatné téma. Definice vnější relace je již trochu složitější, alespoň pro představu si ukažme příklad. Opět reálný příklad z ukázkové aplikace a to provázání galerie a obrázku: namespace JetApplication;

use 
Jet\DataModel;
use 
Jet\DataModel_Definition;
use 
Jet\DataModel_IDController_UniqueString;

#[
DataModel_Definition(
    
name'gallery',
    
database_table_name'image_galleries',
    
id_controller_classDataModel_IDController_UniqueString::class,
    
relation: [
        
'related_to_class_name' => Content_Gallery_Image::class,
        
'join_by_properties'    => ['id' => 'gallery_id'],
        
'join_type'             => DataModel_Query::JOIN_TYPE_LEFT_OUTER_JOIN
    
]
)]
class 
Content_Gallery extends DataModel
{
    
//... ... ...
}

key

Jak si ukážeme za chvíli, tak na jednotlivých vlastnostech entity je možné určit, že se bude jednat o klíče / databázové indexy. Ale někdy je třeba vytvořit složený klič. Tedy klíč / index tvořený několika vlastnostmi (z pohledu DB sloupci). I to je samozřejmě možno definovat, ale opět je to samostatné téma.

Definice vlastností třídy (a prvnků entity)

A nyní si ukážeme definice vlastností třídy. Definice má v praxi například tuto podobu: //... ... ... 
class Content_Article extends DataModel
{
    #[
DataModel_Definition(
        
typeDataModel::TYPE_ID,
        
is_idtrue
    
)]
    protected 
string $id '';

    #[
DataModel_Definition(
        
typeDataModel::TYPE_DATE_TIME,
    )]
    #[
Form_Definition(
        
typeForm_Field::TYPE_DATE_TIME,
        
label'',
        
error_messages: [
            
Form_Field::ERROR_CODE_INVALID_FORMAT => 'Invalid date format'
        
]
    )]
    protected ?
Data_DateTime $date_time null;

    #[
DataModel_Definition(
        
typeDataModel::TYPE_DATA_MODEL,
        
data_model_classContent_Article_Localized::class
    )]
    #[
Form_Definition(is_sub_forms:true)]
    protected array 
$localized = [];

    
//... ... ... 
    //... ... ... 
    //... ... ... 
}
Jak vidíte, tak příklad zahrnuje rovnou i definici formulářů (#[Form_Definition( ... )]), protože v běžné praxi ne na DataModel většinou nějaký formulář napojen. Ale nás teď pochopitelně bude zajímat primárně definice DataModel, tedy #[DataModel_Definition( ... )].

Tak si opět ukažme možné atributy a jejich význam.

type

Dá se říct naprosto základní atribut určující typ vlastnosti z pohledu definice DataModel a tedy je logicky povinný

Seznam typů

Typ Význam
DataModel::TYPE_IDTextový identifikátor záznamu. Tedy unikátní textový řetězec.
DataModel::TYPE_ID_AUTOINCREMENTČíselný identifikátor záznamu. Tedy staré dobré známé autoincrement číslo.
DataModel::TYPE_STRINGObecný textový řetězec.

Maximální délka textu musí být určena atributem max_len
DataModel::TYPE_BOOLLogické ano / ne.
DataModel::TYPE_INTCelé číslo.
DataModel::TYPE_FLOATDesetinné číslo.
DataModel::TYPE_LOCALETextový řetězec představující kód lokalizace - jako textový kód lokalizace bude uložen v databázi.
Ovšem v rámci vlastnosti třídy se jedná o instanci třídy Jet\Locale.
Tedy jednoduše řečeno: V databázi je uložen kód lokalizace, ale s hodnotou se pracuje zásadně jako s instancí třídy Jet\Locale. Konverzi z / na řetězec provádí backend automaticky.

Deklarace by tedy měla mít například tuto podobu:
#[DataModel_Definition(
    
typeDataModel::TYPE_LOCALE,
    
is_idtrue,
    
do_not_exporttrue
)]
protected ?
Locale $locale null;
DataModel::TYPE_DATETyp představuje datum bez času.
Tomu bude odpovídat příslušný databázový typ.
Ovšem v rámci třídy se bude operovat s instancí Jet\Data_DateTime s indikací, že se jedná pouze o datum bez časového údaje.

Deklarace by tedy měla mít tuto podobu:
#[DataModel_Definition(
    
typeDataModel::TYPE_DATE,
)]
protected ?
Data_DateTime $some_date null;
DataModel::TYPE_DATE_TIMETyp představuje datum a čas.
Tomu bude opět odpovídat příslušný databázový typ.
V rámci třídy se bude operovat s instancí Jet\Data_DateTime.

Deklarace by tedy měla mít tuto podobu:
#[DataModel_Definition(
    
typeDataModel::TYPE_DATE_TIME,
)]
protected ?
Data_DateTime $user_is_blocked_till null;
DataModel::TYPE_CUSTOM_DATALibovolná data, která budou před uložením do databáze serializována a po načtení deserializována (serializaci i deserializaci řeší backend automaticky).

Tedy například se může jednat o pole, asociované pole a podobně.
DataModel::TYPE_DATA_MODEL Již jsme narazili na téma vnitřní relace, které je samostatné.
Vnitřní relace ovšem souvisí i s definicí parametrů entity. Vraťme se k příkladu článku z ukázkové aplikace. Jak již bylo řečeno, tak článek má své lokalizované verze. A ty je nutné na samotný článek (tedy na hlavní entitu) navázat a to se dělá právě pomocí vlastnosti s tímto speciálním typem, který se používá takto: /**
 * @var Content_Article_Localized[]
 */
#[DataModel_Definition(
    
typeDataModel::TYPE_DATA_MODEL,
    
data_model_classContent_Article_Localized::class
)]
protected array 
$localized = [];
Tedy definice vyžaduje i atribut data_model_class, který určuje jaká třída (tedy definice subentity) je vázána na danou vlastnost.

max_len

Určuje maximální délku textového řetězce pro typ DataModel::TYPE_STRING.

Atribut je povinný a samozřejmě platný pouze pro daný typ.

data_model_class

Viz typ DataModel::TYPE_DATA_MODEL.

Atribut je povinný a samozřejmě platný pouze pro daný typ.

database_column_name

Standardně název sloupce v databázové tabulce na nějž je vlastnost mapována odpovídá názvu vlastnosti. Ovšem pokud je třeba, je volitelně možné určit vlastní název sloupce pomocí tohoto atributu.

is_id

Indikuje zda vlastnost je brána jako ID, respektive zda se jedná o jednu z vlastností, které se berou jako ID záznamu. Více se dočtete v kapitole o ID kontrolerech.

related_to

Zde se opět dostáváme k tématu vnitřních relací. Již jsme si řekli, že subentita musí mít určenou nadřazenou entitu pomocí atributu třídy parent_model_class. A to samé platí i pro vlastnosti. Subentita musí mít vlastnost (nebo vlastnosti), které jí svazují s rodičovskou entitou (případně s hlavní entitou - viz příslušná kapitola). A je tedy nutné určit, že právě ta a ta vlastnost je vázána na určitou nadřazenou vlastnost.

Ale ukažme si to opět prakticky. Opět se vracíme k ukázkové aplikaci a k její entitě article / článek. Konkrétně k lokalizovaným verzím článku, tedy k entitě articles_localized a třídě JetApplication\Content_Article_Localized. Lokalizovaná verze článku musí mít ID článku ke kterému náleží a taktéž lokalizaci které se text týká. A právě ID článku musí být navázáno na ID hlavní entity: #[DataModel_Definition(
    
typeDataModel::TYPE_ID,
    
is_idtrue,
    
related_to'main.id',
    
do_not_exporttrue
)]
protected 
string|null $article_id '';

Hodnota atributu related_to má jednoduchou strukturu: Před tečkou je buď hodnota main, nebo parent. Podle toho zda jde o návaznost na hlavní entitu (main), nebo o návaznost na nadřazenou subentitu (parent). Za tečkou je pak název vlastnosti návazné entity.

is_key

Indikuje zda bude vlastnost, přesněji řečeno příslušný sloupeček databázové tabulky, brána jako klíč / index. Jedná se o jednoduchý, nesložený klíč. Jak již bylo uvedeno výše, tak složené klíče se definují jinak. Toto je opravdu pouze pro definici jednoduchého klíče.

key_type

Viz is_key. Tento atribut dále definuje jakého typu má jednoduchý index / klíč být.

Možné typy:

Konstanta Význam
DataModel::KEY_TYPE_INDEXBěžný index (výchozí hodnota)
DataModel::KEY_TYPE_PRIMARYPrimární klíč
DataModel::KEY_TYPE_UNIQUEUnikátní klíč

do_not_export

Určuje, že v například v případě serializace objektu do JSON (či exportu do XML a podobně) se daná vlastnost nemá být exportována.

K čemu je to dobré? Například heslo uživatele by určitě nikdy nikam nemělo být exportováno a to ani jako hash.

Export do JSON, který provádí Jet toto zohledňuje automaticky. Pokud budete implementovat vlastní exportní mechanismy, tak je určitě nutné tento atribut zohledňovat.

backend_options

Specální atribut umožňující jednotlivým typům backendů předat speciální nastavení pro danou vlastnost (z pohledu backendu pro daný sloupeček tabulky). Konkrétní možnosti jsou závislé na konkrétním backendu. Není to však standardní postup a není doporučován. Případné použití nechám na vás a na vašem vlastním průzkumu jak to funguje.

Předchozí kapitola
Princip modelování
Další kapitola
ID kontrolery