Začíname so Zend Frameworkom – tutoriál [1/3]

23.12.2007 11:33 | blackhole

Nastal čas Vianoc, obdobie, keď sme odbremenení od pracovných záležitostí a máme more času venovať sa vlastým záujmom. Ak ste hľadali schodný a jednoduchý spôsob ako preniknúť do tajov Zend Frameworku, hľadať už nemusíte. Ako vianočný darček Vám prinášam tento krátky seriál s tutoriálom v Slovenčine.

Text vznikol s láskavým dovolením pána Roba Allena. Jeho originálnu anglickú verziu môžete nájsť na jeho stránkach.

<prelozeny-text>
Tento tutoriál si kladie za cieľ, byť veľmi základným vstupným bodom pri používaní Zend Framework k písaniu webových a databázových aplikácií v PHP.

Pozn. Tento tutoriál bol testovaný so Zend Frameworkom verzie 1.0.0 Je vysoká pravdepodobnosť, že bude pracovať správne aj ďalšími verziami, napriek tomu je prednostne určený pre túto verziu.

Pozn. prekladateľa: Tutoriál som kompletne otestoval a funguje aj s najnovšou aktuálnou verziou Zend Framework 1.0.3.

Architektúra MVC (model, view, controller)
Tradičný spôsob písania PHP aplikácií vypadá ako napr. tento kód:

<?php
  include "common-libs.php";
  include "config.php";
  mysql_connect($hostname, $username, $password);
  mysql_select_db($database);
?>
<?php include "header.php"; ?>
<h1>Home Page</h1>
<?php
  $sql = "SELECT * FROM news";
  $result = mysql_query($sql);
?>
<table>
<?php
  while ($row = mysql_fetch_assoc($result)) {
?>
<tr>
<td><?php echo $row['date_created']; ?></td>
<td><?php echo $row['title']; ?></td>
</tr>
<?php
}
?>
</table>
<?php include "footer.php"; ?>

Počas života aplikácie tohto typu, sa kód stáva čoraz viac ťažšie udržiavateľný , tak ako od klienta prichádzajú ďalšie a ďalšie požiadavky, ktoré musíme zložito hekovať na rôznych miestach do pôvodného kódu.

Jednou z metód ako zlepšiť spravovateľnosť aplikácie je rozdeliť kód do troch separátnych sekcií (a zvyčajne aj separátnych súborov):

Model
Model je časť aplikácie, ktorá má čo dočinenia s údajmi, ktoré chceme zobrazovať/ukladať. V predchádzajúcom príklade sa jedná o údaje z tabuľky news. Model sa týka tzv. biznis časti logiky našej aplikácie a stará sa teda o funkcie LOAD/STORE nad databázou
View
View je časť aplikácie, ktorá ma starosti zobrazenie údajov užívateľovi. Tie sú najčastejšie prezentované vo forme HTML
Controller
Controller má na starosti prácu s modelom a view-om, tak aby pri špecifickom požiadavku dostal užívateľ správne údaje v správnej forme.

Zend Framework využíva architektúru MVC. Využíva ju k tomu aby oddelil rozličné časti aplikácie, tak aby boli vývoj a údržba jednoduchšie.

Požiadavky
Zend Framework má nasledovné požiadavky:

  • PHP verzie 5.1.4 (alebo vyššia)
  • WEB server so zapnutou funkciou mod_rewrite

Predpoklady tutoriálu
Predpokladám, že používate PHP verzie 5.1.4 alebo vyššie, spolu s webovým serverom Apache. Vaša inštalácia Apache web servera musí mať povolené a nakonfigurované rozšírenie mod_rewrite. Musíte tiež overiť, že Apache podporuje súbory .htaccess
Toto sa väčšinou dosiahne nasledujúcou konfiguračnou direktívou v konfigurácii servera:
AllowOverride None

prepíšte za

AllowOverride All

Preštuduje si dokumentáciu vašej distribúcie pre zmenu tejto konfigurácie. Pamätejte, že nebudete schopný zobraziť inú ako titulnú stránku bez podpory mod_rewrite a .htaccess.

Získanie Frameworku
Zend Framework je možné získať zo stránky http://framework.zend.com/download vo formáte .zip alebo .tar.gz.

Adresárová štruktúra
Zend Framework neprikazuje presnú adresárovú štruktúru, ale manuál odporúča využívať všeobecne doporučenú štruktúru. Táto štruktúra predpokladá, že máte plnú kontrolu nad konfiguráciou web servera, napriek tomu si život trocha zpriemnime a toto odporučenie mierne modifikujeme.

Začnite vytvorením adresára zf-tutoriál vo vašom web_root adresári. To znamená, že URL na tento adresár bude mať tvar http://localhost/zf-tutorial.
Ďalej vytvorte nasledovnú štruktúru podadresárov:

zf-tutorial/
    /application
        /controllers
        /models
        /views
            /filters
            /helpers
            /scripts
    /library
    /public
        /images
        /scripts
        /styles

Ako vidíte, v aplikácii máme samostatné adresáre pre súbory model, view a controller. Obrázky, javascript a CSS súbory sú uložené vo vlastných adresároch podadresára public. Knižnice stiahnutého Zend Frameworku sú uložené v adresári library. Ak budete potrebovať vytvárať vlastné knižnice a triedy, umiestnite ich tiež do tohto adresára. Stiahnutý archív rozbaľte do dočasného adresára. Všetky súbory sú umiestnené v podadresári v mojom prípade ZendFramework-1.0.0. Skopírujte adresár library/Zend do vašej aplikácie, do adresára library. Váš adresár zf-tutorial/library by tak mal obsahovať nový adresár nazvaný Zend.

Bootstrap
Controller Zend Frameworku, Zend_Controller je navrhnutý na pre podporu internetových stránok s peknými URL. Aby sme toto dosiahli, musíme všetky požiadavky (requesty) vybavovať cez jediný súbor index.php, nazývaný tiež bootstrapper. Toto nám poskytne centrálny bod pre všetky stránky a zaručí, že prostredie bude pre aplikáciu správne nakonfigurované. Takéto správanie dosiahneme použitím súboru .htaccess v adresári web_root.

zf-tutorial/.htaccess

RewriteEngine on
RewriteRule .* index.php
php_flag magic_quotes_gpc off
php_flag register_globals off

Prepisovacie pravidlo je veľmi jednoduché môžeme ho interpretovať takto: „pre ľubovoľnú URL použi index.php“.

Zmenili sme tiež niekoľko direktív z php.ini. Mali by byť už správne nastavené v php.ini ale chceme mať istotu. Je treba pamätať na to, že prepisovanie konfiguračných direktív PHP v súbore .htaccess je funkčné iba ak PHP beží ako modul Apache servera. Ak PHP beží ako CGI/FastCGI, overte tieto nastavenia v php.ini.

Napriek tomuto nastaveniu je vhodné aby javascript, CSS a obrázkové súbory neboli presmerované bootstraperom. Tým, že sme tieto súbory umiestnili do samostatného adresára public, môžeme Apache server jednoducho nakonfigurovať aby tieto súbory poskytoval priamo. Použijeme k tomu ďalší súbor .htaccess v adresári zf-tutorial/public:

zf-tutorial/public/.htaccess

RewriteEngine off

Ďalšie nastavenie nie je striktne potrebné, ale pre lepšiu ochranu našej aplikácie vytvoríme ešte niekoľko súborov s rewrite pravidlami:

zf-tutorial/application/.htaccess

Deny From All

zf-tutorial/library/.htaccess

Deny From All

Pamätajte, že pre využívanie súborov .htaccess je potrebné aby mal Apache vo svojom hlavnom konfiguračnom súbore httpd.conf nastavenú direktívu AllowOverride na hodnotu All. Táto myšlienka s využívaním mnohých súborov .htaccess je podrobne popísaná v článku Jaysona Minarda, Blueprint for PHP Applications: Bootstrapping (Part 2). Odporúčam vám aby ste si prečítali obe časti.

Bootstrap súbor: index.php
Súbor zf-tutorial/index.php je naším bootstrapovým súborom. Naplňte ho nasledujúcim kódom:

zf-tutorial/index.php

<?php
  error_reporting(E_ALL|E_STRICT);
  date_default_timezone_set('Europe/Bratislava');
  set_include_path('.' . PATH_SEPARATOR . './library'
    . PATH_SEPARATOR . './application/models/'
    . PATH_SEPARATOR . get_include_path());
  include "Zend/Loader.php";
  Zend_Loader::loadClass('Zend_Controller_Front');
  // setup controller
  $frontController = Zend_Controller_Front::getInstance();
  $frontController->throwExceptions(true);
  $frontController->setControllerDirectory('./application/controllers');
  // run!
  $frontController->dispatch();

Všimnite si, že sme nepoužili ukončovacie ?>, nakoľko to nie je potrebné a ponechanie otvoreného konca nás ochráni pred rôznymi ťažko laditeľnými chybami, ktoré sa objavia pri presmerovaní cez funkciu header() ak ponecháme na konci súboru nejaké biele znaky.

Popíšme si obsah súboru:

error_reporting(E_ALL|E_STRICT);
date_default_timezone_set('Europe/Bratislava');

Tieto riadky zaručia, že uvidíme akúkoľvek chybu, ktorú urobíme (predpokladom je nastavená direktíva display_errors v php.ini na hodnotu on). Okrem toho nastavíme miestnu časovú zónu, nakoľko je to požiadavka PHP 5.1 a vyšších. Môžete samozrejme nastaviť vlastnú časovú zónu.

set_include_path('.' . PATH_SEPARATOR . './library'
    . PATH_SEPARATOR . './application/models/'
    . PATH_SEPARATOR . get_include_path());
include "Zend/Loader.php";

Zend Framework je navrhnutý tak, že súbory sa nachádzajú v tzv. include ceste. Do tejto cesty sme tiež pridali náš model adresár, takže môžeme jednoducho nahrávať naše triedy z model adresára. Pokračujeme inkludovaním súboru Zend/Loader.php, čo nám dáva prístup ku triede Zend_Loader, ktorá poskytuje potrebné statické funkcie pre nahrávanie ostatných tried Zend Frameworku.

Zend_Loader::loadClass('Zend_Controller_Front');

Tento príkaz načíta vymenovanú triedu. To je dosiahnuté skonvertovaním podtržítok v názve triedy na oddeľovače cesty a pridaním koncovky .php. To znamená, že trieda Zend_Controller_Front sa inkluduje zo súboru Zend/Controller/Front.php. Ak dodržíte rovnakú mennú konvenciu, môžete takto načítavať vlastné triedy využitím s Zend_Loader::loadClass()
Prvou triedou, ktorú budeme potrebovať je front controller.

Front controller používa routovaciu triedu na mapovanie požadovaného URL na PHP funkciu, ktorá bude použitá na zobrazenie stránky. Pre správnu funkciu routra mu potrebujeme povedať, ktorá časť URL smeruje na index.php, takže sa môže na URL elementy pozerať za týmto bodom. Toto zabezpečuje tzv. Request objekt. Ten odvádza veľmi dobrú prácu pri auto detekcii základu URL, ale ak zlyhá, môžete ho manuálne nastaviť pomocou funkcie $frontController->setBaseUrl().

Front controller potrebujeme nastaviť aby vedel, kde má hľadať ďalšie controllery.

// setup controller
$frontController = Zend_Controller_Front::getInstance();
$frontController->throwExceptions(true);
$frontController->setControllerDirectory('./application/controllers');

Nakoľko naša aplikácia beží v testovacom móde, rozhodol som sa nastaviť front controller tak aby vyhadzoval všetky výnimky, ktoré sa objavia. Defaultne tak front controller bude pre nás odchytávať výnimky a ukladať ich do člena _exceptions objektu Response, ktorý vytvorí. Objekt Response drží všetky informácie o odpovedi na požadovanú URL. To zahŕňa http hlavičky, obsah stránky a výnimky. Front controller pošle hlavičky a obsah stránky až nakoniec, takže sa všetky výnimky zobrazia hneď na vrchu stránky. Ale na produkčnom serveri by užívateľ nemal nikdy žiadnu výnimku vidieť!

Nakoniec sa dostávame k tomu hlavnému – aplikáciu spustíme:

// run!
$frontController->dispatch();

Ak si v browseri zobrazíte adresu http://localhost/zf-tutorial/ dostanete chybovú hlášku podobnú tejto:
Fatal error: Uncaught exception 'Zend_Controller_Dispatcher_Exception' with
message 'Invalid controller specified (index)' in…

Tá nám vraví, že sme aplikáciu ešte nenastavili. Predtým ako tak spravíme, popíšem aplikáciu, ktorú ideme napísať a aké bude mať funkcie.

Stránka
Ideme si napísať veľmi jednoduchú aplikáciu, inventárny systém pre našu kolekciu CD. Hlavná stránka nám vylistuje kolekciu a umožní pridať, editovať a zmazať záznamy kolekcie. Kolekcia je uložená v databáze v takejto tabuľke:

Meno stĺpca    Dátový typ    Null?              Misc
-------------------------------------------------------------------
    Id            Int          No      Primary key, autoincrement
  Artist      Varchar(100)    No
  Title      Varchar(100)    No

Jednotlivé stránky
Budeme potrebovať tieto stránky:

Home page
Zobrazí listovanie kolekcie, poskytuje linky na editáciu a zmazanie albumu. A okrem toho zobrazuje aj link na pridanie nového albumu.
Add new album
Táto stránka zobrazí formulár na pridanie albumu
Edit album
Táto stránka zobrazí formulár na editovanie albumu
Delete album
Táto stránka zobrazí potvrdenie, či chceme zmazať album

Organizácia stránok
Predtým ako si napíšeme kód jednotlivých súborov, popíšeme si ako Framework očakáva, že budú stránky organizované. Každá stránka v aplikácii je istou akciou a akcie sú zoskupené v controlleroch. Napr. pri URL http://localhost/zf-tutorial/news/add, controllerom je news a akcia je add. To umožňuje zoskupovať podobné akcie. Napr. controller news môže obsahovať akcie current, archived a add. Zend Framework okrem toho podporuje systém modulov pre zoskupovanie controllerov, ale toto nie je dostatočné rozsiahla aplikácia aby sme to potrebovali využívať.

Zend Framework si rezervuje špeciálnu akciu nazývanú index ako predvolenú (default) akciu. Takže pri požiadavke URL http://localhost/zf-tutorial/news/ sa vykoná práve index akcia controllera news. Zend Framework si okrem toho rezervuje predvolený názov controlleru, ak nie je poskytnuté žiadne meno controlleru. Nie je prekvapením, že je to opäť reťazec index, takže po zadaní URL http://localhost/zf-tutorial/ sa vykoná akcia index v controlleri index.

V tomto tutoriáli nebudeme veci komplikovať funkciami ako prihlasovanie. Necháme si to pre ďalší tutoriál.

Nakoľko sme si definovali 4 stránky pre obsluhu albumov, zoskupíme si ich do jedného controlleru ako 4 akcie. Použijeme predvolený názov pre controller, pričom názvy akcií budú:

  Stránka      Controller      Akcia
----------------------------------------
Home page        Index          Index
Add new album    Index          Add
Edit album        Index          Edit
Delete album      Index        Delete

Pekné a jednoduché.
</prelozeny-text>

Na tomto mieste tutoriál prerušíme a budeme pokračovať v ďalšej časti. Dôvodom je, že vygenerovanie článku zaťažuje server BH (to potrebuje nejaký CPU time), takže si nemôžem dovoliť napísať ľubovoľne dlhý článok. Obmedzil by som komfort ostatných návštevníkov BH. Už takto som dosť na hrane (zaujímal by ma názor admina, keď na článok klikne 20 ľudí naraz).

    • Re: Začíname so Zend Frameworkom – tutoriál [1/3] 23.12.2007 | 13:51
      Avatar blackhole   Návštevník

      Ospravedlnujem sa za formu tabulkovych udajov, ale BH system neumoznuje pouzivat tabulkove HTML elementy. Co som testoval zobrazenie, ludia s rozlisenim 1024x768 budu mat dost rozsypany text, od 1280x1024 je to uz O.K.

      ----------------------
      Ja len v dobrom.

      • Re: Začíname so Zend Frameworkom – tutoriál [1/3] 24.12.2007 | 00:57
        Avatar y   Používateľ

        formatovanie clankov riesim, je pravdepodobne, ze pribudnu nejake dalsie moznosti. inak, html tagy mozes pouzit v podstate lubovolne a potom napisat admin userovi, co to potom da zobrazovat vo "full html" mode. teoreticky podobne php
        ==
        Don't buy drugs...Become a pop star and get them for free!

        == Don't buy drugs...Become a pop star and get them for free!
    • Re: Začíname so Zend Frameworkom – tutoriál [1/3] 23.12.2007 | 14:45
      Avatar blackhole_tommyhot   Používateľ

      Ja len chcem reagovat na tie posledne vety. Moj clanok (cast serialu) ktory pisem uz par mesiacov ma zatial vyse 600 riadkov (v textovom editore kate pri maximalizovanom okne), takze este len to bude zataz na server :D

      Inak pekny clanok, uz davnejsie som chcel vediet co je to zend framework :)
      ----------
      tommyhot@hackingmachine:~$ microsoft &> /dev/null

    • Re: Začíname so Zend Frameworkom – tutoriál [1/3] 24.12.2007 | 14:36
      Avatar ehmo   Používateľ

      srigi skusal si niekedy aj nieco ine ako zend? nechem byt ten co furt a vsade kritizuje ale za tie roky som si uz zvykol
      zend ako aj v pripade php (dokazom je posledny navrh namespaces) nie je schopny urobit kvalitny a logicky kod, tento framework je vysmech fm logike. som rad ze si spokojny a ze si si dal namahu, ja ostatnym odporucam cakePHP alebo symfony

      inak stastne a vesele :)
      ------------------------------
      http://blog.synopsi.com

      ------------------------------ http://blog.synopsi.com
    • Re: Začíname so Zend Frameworkom – tutoriál [1/3] 25.12.2007 | 07:36
      Avatar blackhole   Návštevník

      hmm zaujimave.. so zendom som pracoval dobre 4 mesiace a musim povedat ze ma SRACKOVU model vrstvu..

      fakt tiez odporucam symfony, ktore vyuziva propel..