Group Office - vytváříme vlastní modul - část 2.

V předchozím díle jsme si rozebrali, jak vypadá základní struktura modulu v Group Office. Dnešní díl popíše databázovou strukturu a práci s modely.

Základem návrhu celého modulu (a nejen jeho ale i jakéhokoli jiného projektu), by měla být databázová struktura. Sama o sobě Vám dá představu o tom, co samotný projekt bude dělat, do jakých se bude dělit částí apod.

U Group Office má databázová struktura nemalou úlohu. Díky novému frameworku ve verzi 4 a PDO dochází k automatickému načítání sloupců v tabulkách, a tedy není nutné vytvářet proměnné popisující samotnou tabulku v rámci jednotlivých tříd a definice relací Vám příjemně zjednoduší práci. Vše si ukážeme na jednoduchých příkladech.

Group Office v základu používá dva typy tříd, ze kterých modely dědí. V první řadě se jedná o třídu GO_Base_Db_ActiveRecord, která je základním stavebním kamenem i třídy druhé GO_Base_Model_AbstractUserDefaultModel.

Nejprve si projdeme třídu AbstractUserDefaultModel, která je používána pro skupiny, adresáře apod., jinými slovy pro takové takové modely, u kterých je definován sloupec user_id a které mají být automaticky zakládány a mazány spolu se záznamem uživatele. Mezi zajímavé funkce patří getDefault, která je volána automaticky po uložení modelu s uživatelem. Funkci samozřejmě můžete overridovat a tím změnit její funkčnost.

AbstractUserDefaultModel a většina modelů obecně vychází ze třídy ActiveRecord. Tato třída přináší rozsáhlé možnosti mezi které patří například:

  • definice primárního klíče
  • název tabulky
  • relace mezi tabulkami
  • a další

Obecně se jedná o základní stavební kámen při komunikaci s databází.
Nyní přejdeme k praktické části, ve které budeme mít k dispozici:

  • kategorii záznamu
  • záznam

U kategorie počítáme s tím, že bude zakládána pro každého uživatele automaticky.

class GO_Example_Model_Category extends GO_Base_Model_AbstractUserDefaultModel
{
    public static function model($className = __CLASS__)
    {
        return parent::model($className);
    }

    //u modelu budeme resit opravneni
    public function aclField()
    {
        return 'acl_id';
    }

    //nazev tabulky
    public function tableName()
    {
        return 'ex_categories';
    }

    //relace
    public function relations()
    {
         return array(
            'records' => array(
                'type' => self::HAS_MANY,
                'model' => 'GO_Example_Model_Record',
                'field' => 'category_id',
                'delete' => true
            )            
        );
    }

    //validace a popis jednotlivych sloupcu
    protected function init()
    {
        //nazev kategorie musi byt unikatni
        $this->columns['name']['unique'] = true;
        return parent::init();
    }
}

Funkce relations vrací pole relací. Relace jsou pak definovány následujícími typy:

  • BELONGS_TO - N:1
  • HAS_MANY - 1:N
  • HAS_ONE - 1:1
  • MANY_MANY - M:N

Krom samotného typu relace se u relace mohou vyskytnout následující atributy:

  • model - definuje vzdálený model relace
  • field - zdrojový nebo cílový sloupec relace v závislosti na relaci. Druhým sloupcem pro relaci je pak primární klíč
  • linkModel - pro relaci M:N
  • delete = true pro relaci 1:N, čímž říkáme, že při smazání modelu dochází ke smazání i slinkovaných modelů - kaskádově
class GO_Example_Model_Record extends GO_Base_Db_ActiveRecord
{
    public static function model($className = __CLASS__)
    {
        return parent::model($className);
    }

    protected function init()
    {
        //sloupec/pole category_id je povinne
        $this->columns['category_id']['required'] = true;
        return parent::init();
    }

    public function getLocalizedName()
    {
        //prelozeny nazev modelu - hledame string record v modulu example
        return GO::t('record', 'example');
    }

    //nazev tabulky
    public function tableName()
    {
        return 'ex_records';
    }

    //acl field v ramci relace
    public function aclField()
    {
        return 'category.acl_id';
    }

    //relace
    public function relations()
    {
        return array(
            'category' => array(
                'type' => self::BELONGS_TO,
                'model' => 'GO_Example_Model_Category',
                'field' => 'category_id'
            )
        );
    }
}

Tím máme k dispozici dva jednoduché modely kategorie - záznam spolu s oprávněními pro jednotlivé uživatele/skupiny. Samotnou práci s modelem si probereme v rámci dalšího dílu s controllery. Mezi zajímavé funkce, které Vám pomohou vyřešit problémy při práci s modelem patří následující:

  • afterSave($wasNew) - funkce volaná po uložení modelu do databáze
  • defaultAttributes - v rámci této funkce jsou definovány výchozí hodnoty prázdého modelu
  • beforeSave - funkce volaná těsně před uložením modelu
  • beforeDelete - funkce volaná před uložením modelu - např pro ověření práv
  • afterDbInsert - funkce volaná po zavolání SQL, které vkládá záznam do DB
  • hasLinks - definuje zda jsou v rámci modelu povoleny GO linky
  • hasFiles - definuje zda jsou použity soubory (je nutné definovat sloupec files_folder_id)

Databázová struktura musí existovat ještě před prací se samotnými modelu. Kvůli tomu je zde adresář install se skriptem install.sql, které obsahuje samotnou definice tabulky.