Portál AbcLinuxu, 6. května 2024 23:40

CakePHP: tvoríme CMS - 5 (Controller a View)

1. 8. 2008 | Tibor Piňo
Články - CakePHP: tvoríme CMS - 5 (Controller a View)  

V predchádzajúcej časti seriálu sme si navrhli a vytvorili databázu, ku každej databázovej tabuľke sme si vytvorili model a veľmi stručne sme si predstavili controller. V dnešnej časti sa budeme controlleru venovať podrobne a predstavíme si taktiež ďalšiu časť architektúry MVC, a to konkrétne view.

Ako som už spomínal, v predchadzajúcej časti seriálu sme si controller stručne predstavili, v tomto prípade sme si ukázali použitie tzv. scaffolding. V tejto časti si controller predstavíme podrobne.

URL ako rozhranie aplikácie

Controller je tá časť aplikácie, ktorá ako prvá prichádza do styku s požiadavkami, ktoré prichádzajú do našej aplikácie z vonkajšieho sveta. Najčastejším prípadom takéhoto požiadavku z vonkajšieho sveta je URL adresa. Ak teda budeme pristupovať k našej aplikácii prostredníctvom URL, potrebujeme nejaký mechanizmus, ktorý nám na základe tejto URL určí, že aplikácia „pozná“, na aké prvky aplikácie má smerovať dané požiadavky. Takýto mechanizmus sa nazýva routing.

V minulosti sa formátu URL adresy veľká pozornosť nevenovala. Často sme boli svedkami podobných URL ako môžeme vidieť na ukážke

http://www.example.com/index.php?action=list&template=comments&page=2&order=DESC

URL adresa v takomto tvare bola možno jednoduchá pre programátora, určite však nie pre užívateľa. V súčasnosti je trend iný a hlavne moderné frameworky sa snažia vytvárať a používať tzv. user friendly URL. Príklad takejto adresy môžeme vidieť na ukážke

http://www.example.com/articles/mvc-model-view-controller-v-cakephp

Určite nám je jasné, že takáto adresa je oveľa viac čitateľnejšia a zrozumiteľnejšia nie len pre užívateľa. Bližšie štúdium o tejto problematike ponechám na samotných čitateľov, pretože by to presahovalo záber tohto článku. Avšak výhody takýchto URL sú nespochybniteľné. Ako sme už určite vytušili, CakePHP používa taktiež user friendly URL. Poďme sa teda bližšie pozrieť, akým spôsobom pristupujeme v CakePHP k našej aplikácii prostredníctvom URL

cakephp 05 url

V našom prípade by URL adresa pre zobraznie článku v aplikácii v CakePHP mohla vyzerať tak, ako môžeme vidieť na obrázku vyššie. Z URL nám môže byť napríklad hneď jasné, že sa bude jednať o zobrazenie určitého článku. Obrázok taktiež demonštruje fungovanie routingu v samotnom CakePHP. Prvá časť adresy označená zelenou farbou nám určuje konkrétny controller v našej aplikácii, druhá časť označená červenou farbou nám určuje konkrétnu akciu v controlleri a posledná časť označená modrou farbou nám určuje parameter vkladaný do tejto akcie. Aby sme si vedeli túto situáciu predstaviť konkrétne, pozrime sa na nasledovný kód, ktorý by bol vykonaný pri použití URL adresy z obrázku:

class ArticlesController extends AppController{
     var $name="Articles";
     function show($id){
           $this>set("article",$this>Article>findById($id));

     }
}

Mechanizmus routingu by zabezpečil, že by sa zavolala metóda show triedy ArticlesController a zároveň by bol metóde predaný parameter s hodnotou 43.

URL 100× inak

CakePHP nám v súvislosti s routingom ponúka ešte jednú veľmi užitočnú vlastnosť, a to sú tzv. routovacie pravidlá. Na základe týchto pravidiel môžeme ovplyvňovať samotné routovanie a v neposlednom rade nás routovacie pravidlá zbavujú povinnosti ručne modifikovať súbory .htaccess, čím nám značne uľahčujú prácu, pretože používajú oveľa prehľadnejšiu syntaxu. Treba však poznamenať, že routavacie pravidlá zďaleka nenahradzajú možnosti súboru .htaccess, pretože to nie je ani ich cieľom. Ich cieľom je poskytnúť z jednodušenú syntaxu pri pravidlách, ktoré sa týkajú routovania a spracovávania samotných URL adries.

Samotné routovacie pravidlá sa definujú v súbore app/config/routes.php. Pozrime sa na ukážkový kód

Router::connect('/sites/*', array('controller' => 'articles', 'action' => 'index'));
Router::connect('/', array('controller' => 'articles', 'action' => 'index'));

Pomocou vyššie uvedených pravidiel sme určili, že URL v tvare www.example.com/sites/* (kde znak * značí ľubovoľný tvar zvyšku adresy) bude routovaná na controller articles a že sa bude v tomto controlleri volať metóda index. Taktiež sme určili, že URL v tvare www.example.com bude routovaná na vyšie spomínaný controller articles a jeho metódu index. Podrobné vysvetlenie všetkých možností použitia routovacích pravidiel je nad rámec tohto článku, ale určite v budúcnosti pripravím článok, ktorý vás kompletne prevedie svetom routovacích pravidiel v CakePHP.

Na záver tejto časti pripomeniem, že celý mechanizmus spracovávania požiadavku v CakePHP som rozoberal v článku MVC model view controller v CakePHP.

Vytvárame controller

Od minulého článku máme vytvorené jednotlivé controllere, a to konkrétne ArticlesController, UsersController, CommentsController a TagsController. Avšak ako môžeme vidieť, naše controllere neobsahujú žiadne metódy resp. akcie, ktoré sú potrebné na správne fungovanie aplikácie tak, ako sme to spomínali v časti preberanej vyššie (aplikácia nám samozrejme fungovala aj tak, pretože sme využili scaffolding). Poďme si preto jednotlivé metódy vytvoriť a pripraviť si tak pôdu pre ich zobrazenie vo view.

V controlleri ArticlesController si vytvoríme dve metódy index a view, kde prvá bude reprezentovať akciu zobrazenie všetkých článkov a druhá bude reprezentovať akciu zobrazenie konkrétneho článku. Kód bude vyzerať následovne

class ArticlesController extends AppController {

        var $name = 'Articles';
        var $helpers = array('Html', 'Form');

        function index() {
                $this->set('articles', $this->paginate());
        }

        function view($id = null) {
                if (!$id) {
                        $this->Session->setFlash(__('Invalid Article.', true));
                        $this->redirect(array('action'=>'index'));
                }
                $this->set('article', $this->Article->read(null, $id));
        }
}

V controlleri CommentsController si vytvoríme 3 metódy, kde metóda index sa bude starať o zobrazenie všetkých komentárov, druhou metódou bude metóda view, ktorá sa bude starať o zobrazenie konkrétneho komentára a poslednou treťou metódou bude metóda add, ktorá nám pridá nový komentár. Kód bude vyzerať následovne:

class CommentsController extends AppController {

        var $name = 'Comments';
        var $helpers = array('Html', 'Form');

        function index() {
                $this->Comment->recursive = 0;
                $this->set('comments', $this->paginate());
        }

        function view($id = null) {
                if (!$id) {
                        $this->Session->setFlash(__('Invalid Comment.', true));
                        $this->redirect(array('action'=>'index'));
                }
                $this->set('comment', $this->Comment->read(null, $id));
        }

        function add() {
                if (!empty($this->data)) {
                        $this->Comment->create();
                        if ($this->Comment->save($this->data)) {
                                $this->Session->setFlash(__('The Comment has been saved', true));
                                $this->redirect(array('action'=>'index'));
                        } else {
                                $this->Session->setFlash(__('The Comment could not be saved. Please, try again.', true));
                        }
                }
                $articles = $this->Comment->Article->find('list');
                $this->set(compact('articles'));
        }
}

Posledným upravovaným controllerom bude controller TagsController, ktorému pre jednoduchosť vytvoríme len dve metódy, metóda index ktorá nám zobrazí všetky dostupné tagy a metóda view, ktorá nám zobrazí všetky články prislúchajúce k danému tagu. Kód bude vyzerať následovne:

class TagsController extends AppController {

        var $name = 'Tags';
        var $helpers = array('Html', 'Form');

        function index() {
                $this->Tag->recursive = 0;
                $this->set('tags', $this->paginate());
        }

        function view($id = null) {
                if (!$id) {
                        $this->Session->setFlash(__('Invalid Tag.', true));
                        $this->redirect(array('action'=>'index'));
                }
                $this->set('tag', $this->Tag->read(null, $id));
        }
}

K vyššie uvedeným kódom bližšie vysvetlím význam niektorých použitých metód, ktoré majú pre správne pochopenie celého mechanizmu zásadný význam.

Metódou set() posielame dáta do view. Metóda prijíma dva parametre, kde prvý označuje názov premennej vo view a druhý parameter sú samotné dáta uložené do premennej s názvom určenom v prvom parametri (bližšie si túto časť vysvetlíme neskôr, kedy budeme dáta zobrazovať).

Metóda paginate() sa nám stará o stránkovanie veľkého množstva dát (túto vlastnosť si predstavíme v niektorej z ďalších častí nášho seriálu).

Metóda Session->setFlash() nám nastaví chybovú hlášku pre layout, ktorú môžeme jednoducho v našom layoute zobraziť na mieste, kde budeme chcieť.

Metóda redirect() sa postará o presmerovanie behu našej aplikácie buď pomocou zadanej URL adresy alebo pomocou určenia controllera a akcie.

Premenná $this->data reprezentuje dáta odoslané formulárom z view.

Určite vás napadlo, že sme v našich controlleroch nikde neuvádzali akcie pre pridanie článku, pridanie tagu, administrácie užívateľov atď. Je to náš zámer, pretože dané akcie patria do administračného rozhrania, ktorému sa budeme venovať v nasledujúcej časti seriálu.

Zobrazujeme dáta

Už sme si spomenuli metódu, ktorá nám posiela dáta do view pochádzajúce z našich modelov. Správne tušíte, že sa jedná o metódu set() a pochopenie jej práce je pre ďalšie časti kľúčové. Ako som spomenul, príjíma dva parametre, prvý parameter je názov premennej vo view a druhým parametrom sú samotné dáta, ktoré sa vložia do premennej s názvom určenom v prvom parametri. Aby sme neostali len pri teórii, poďme si ich význam ukázať na príklade.

Zoberme kód nášho controllera ArticlesController a jeho metódu view, ktorá reprezentuje akciu pre zobrazenie konkrétneho článku. Užívateľ zadá do prehliadača URL www.example.com/articles/view/1, čím určí, že chce zobraziť článok s id 1. Mechanizmus routingu správne vyhodnotí URL a určí, že sa vykoná metóda view v controlleri ArticlesController. Táto metóda najprv otestuje, či sme zadali nejaké id článku. Ak áno, pomocou modelu vyberie dáta z tabuľky articles ($this->Article->read(null, $id)) a následne ich vloží do view pod premennou article ($this->set(‚article‘, $this->Article->read(null, $id))). Potom už je naša práca veľmi jednoduchá a dáta možeme zobraziť.

Súbory s našimi šablónami sa ukladajú do adresára app/views. V našom prípade pre zobrazenie článku to bude adresár app/views/articles/view.ctp. Náš súbor view.ctp, ktorý zobrazuje konkrétny článok, by mohol vyzerať následovne:

<div class="articles view">
<h2><?php  __('Article');?></h2>
        <dl><?php $i = 0; $class = ' class="altrow"';?>

                <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Id'); ?></dt>
                <dd<?php if ($i++ % 2 == 0) echo $class;?>>
                        <?php echo $article['Article']['id']; ?>
                        &nbsp;
                </dd>

                <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Title'); ?></dt>
                <dd<?php if ($i++ % 2 == 0) echo $class;?>>
                        <?php echo $article['Article']['title']; ?>
                        &nbsp;
                </dd>

                <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Text'); ?></dt>
                <dd<?php if ($i++ % 2 == 0) echo $class;?>>
                        <?php echo $article['Article']['text']; ?>
                        &nbsp;
                </dd>

                <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('User'); ?></dt>
                <dd<?php if ($i++ % 2 == 0) echo $class;?>>
                        <?php echo $html->link($article['User']['id'], array('controller'=> 'users', 'action'=>'view', $article['User']['id'])); ?>

                        &nbsp;
                </dd>
                <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Created'); ?></dt>
                <dd<?php if ($i++ % 2 == 0) echo $class;?>>
                        <?php echo $article['Article']['created']; ?>

                        &nbsp;
                </dd>
        </dl>
</div>

Teraz nám už je jasné, akým spôsobom zobraziť dáta vo view. V controlleri sme si vložili do view dáta pod premennou article a vo view sme na základe tejto premennej dáta jednoducho zobrazovali (napr. $article[‚Article‘][‚title‘] zobrazí titulok článku). Ešte poznamenám, že nám nemusí byť jasné, aký význam má metóda __(‚Created‘). Táto metóda súvisí s internacionalizáciou stránky a CakePHP na toto myslí už od počiatku vývoja aplikácie. Bližšie sa o internacionalizácii môžete dočítať v článku Viacjazyčný web v cakePHP.

Formát zobrazovaných dát

Už vieme, ako vložiť dáta do view. Poďme sa pozrieť nato, v akom formáte sa nám dáta z modelu do view dostávajú. Model všeobecne mapuje dáta do viacrozmerných polí. V podstate nám nastávajú dve možnosti pri vkladaní dát z modelu do view. Prvou možnosťou je, že nám model vráti jeden záznam, a druhou možnosťou je, že nám model vráti viac záznamov. Obidva prípady si ukážeme priamo na príklade.

Pozrime sa na situáciu, kedy nám model vráti jeden záznam. Predstavme si, že chceme zobraziť jeden článok, formát dát bude nasledovný:

Array
(
    [Article] => Array
        (
            [id] => 46
            [seo_link] => 5-tvorime-cms-s-cakephp-controller-a-view
            [title] => 5. Tvoríme CMS s CakePHP - Controller a View
            [intro_text] => V predchádzajúcej časti seriálu sme si navrhli a vytvorili databázu...
        )
)

Ako môžeme vidieť vyššie, model nám vratil dvojrozmerné pole, kde prvý index je názov modelu, z ktorého data pochádzajú, a druhý index je názov stĺpca v databázovej tabuľke.

Odlišná situácia nastane, keď nám model vracia viac záznamov. Predstavme si, že chceme zobraziť zoznam článkov, formát dát bude nasledovný

Array
(
    [0] => Array
        (
            [Article] => Array
                (
                    [id] => 46
                    [seo_link] => 5-tvorime-cms-s-cakephp-controller-a-view
                    [title] => 5. Tvoríme CMS s CakePHP - Controller a View
                    [intro_text] => V predchádzajúcej časti seriálu sme si navrhli a vytvorili databázu...
                 )
         )
    [1] => Array
        (
            [Article] => Array
                (
                    [id] => 41
                    [seo_link] => ako-poslat-email-s-prilohou
                    [title] => Ako poslať email s prílohou
                    [intro_text] => Nedávno som v jednom z mojich projektov riešil situáciu, kedy bolo potrebné k odosielanému emailu pripojiť aj prílohu...
                 )
         )
)

Ako môžeme vidieť vyššie, model nám vrátil trojrozmerné pole, kde prvý index určuje index záznamu v poli v rozmädzí od [0;n-1], kde n-1 je počet vrátených záznamov. Druhý index je názov modelu, z ktorého dáta pochádzajú, a posledný tretí index je názov stĺpca v databázovej tabuľke.

Treba ešte poznamenať, že model nám môže vrátiť aj zložitejšie štruktúry, avšak práca s nimi je obdobná. Keď si nebudeme istý formátom dát vo view, môžeme použiť metódu var_dump() resp. pri zapnutom debug móde metódu debug() priamo z CakePHP.

Záver

Týmto je táto časť nášho seriálu u konca. Jej cieľom bolo pochopenie základných princípov archiktúry MVC, a to konkrétne controller a view. Nedotkli sme sa niektorých tém, ktoré s danými časťami súvisia, akú sú napr. helpery, komponenty atď. Nemusíte sa obávať, určite sa k nim dostaneme v niektorej z ďalších častí.

Rád uvítam vaše námety a pripomienky k článku.

Seriál CakePHP: tvoríme CMS (dílů: 6)

První díl: CakePHP: tvoríme CMS - 1 (úvod), poslední díl: CakePHP: tvoríme CMS - 6 (admin rozhranie).
Předchozí díl: CakePHP: tvoríme CMS - 4 (Model)
Následující díl: CakePHP: tvoríme CMS - 6 (admin rozhranie)

Související články

Seriál: Ruby pro začátečníky
Seriál: PEAR
Seriál: Smarty, šablonovací systém

Odkazy a zdroje

CakePHP.org
Začíname s CakePHP

Další články z této rubriky

LLVM a Clang – více než dobrá náhrada za GCC
Ze 4 s na 0,9 s – programovací jazyk Vala v praxi
Reverzujeme ovladače pro USB HID zařízení
Linux: systémové volání splice()
Programování v jazyce Vala - základní prvky jazyka

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.