Začínáme se Zend Framework 1.5

15.6.2011 – Vyšel aktualizovaný překlad od Martina Hujera – Začínáme se Zend Frameworkem

Před necelým rokem jsem tu zveřejnil překlad skvělého tutoriálu na Zend Framework 1.0 od Rob Allen – Začínáme se Zend Framework 1.0 (originál). Nicméně vývoj Zend Framework se naštěstí nezastavil a k dispozici je ve verzi 1.5. Přináším vám tedy aktualizovanou verzi překladu.

Co je nového?

Tak tuhle otázku si položí asi každý, kdo už pracoval s předchozí verzí tutoriálu. Rob Allen se v nové revizi zaměřil na nové komponenty Zend_Layout a Zend_Form. Asi nemá cenu komponenty blíže představovat, protože to za mě udělali jiní – Zend_Layout a Zend_Form .

Tak a teď už vzhůru k tvorbě aplikace pro Zend Framework 1.5!

Originál je pouze jeden a ten najdete: Getting Started with the Zend Framework 1.5.

Verze Zend Framework Poslední aktualizace
1.5.2 1.5 a novější 2.6.2008

Tento tutoriál byl vytvořen proto, aby vám poskytl základní představu o použití Zend Framework (dále pod slovem framework je automaticky myšleno Zend Framework není-li uvedeno jinak). Jeho využití si budeme demonstrovat na základní aplikaci využívající databázi.

Tento tutoriál byl vytvořen a otestován na Zend Frameworku ve verzi 1.5. Na nižší verzi nebude fungovat.

MVC (Model-View-Controller) architektura aplikace

Tradiční způsob tvorby PHP aplikací je asi takový:

<?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"; ?>

Během vývoje aplikace ale zjistíme, že tento postup je neefektivní, pokud provádíme nějaké změny. Tyto změny musí být provedeny napříč celou aplikací.

Jednou z možností, jak si vývoj aplikace usnadnit je rozdělit kód na stránce do 3 různých částí (a většinou i samostatných souborů):

Model Model je část aplikace, která je zodpovědná za výběr dat, která budou zobrazena. Na příkladu uvedeném o pář řádku výše by se jednalo o výběr novinek z databáze a jejich uložení do pole.
View View se stará o způsob, jakým jsou data prezentována uživateli. Nejčastěji se tedy jedná o HTML.
Controller Controller se stará o vytvoření modelu a zároveň volá správný view.

Zend Framework využívá MVC (Model-View-Controller) architekturu. Ta se používá pro oddělení rozdílných částí aplikace a tím také snažší vývoj a údržbu.

Požadavky

Zend Framework požaduje:

  • PHP 5.1.4 (a novější)
  • Webový server podporující mod_rewrite. V tomto tutoriálu je použit Apache.

Předpoklady pro úspěšné fungování vaší aplikace

Při psání tutoriálu jsem vycházel z toho, že aplikaci spouštíte na serveru, kde běží minimálně PHP 5.1.4 spolu s webovým serverem Apache. Poslední dobou se množí dotazy, že vám funguje pouze hlavní stránka aplikace. Zkontrolujte, zda máte aktivováno mod_rewrite pod Apache. Dále tento problém může být způsoben tím, že nemáte povoleno použití souboru .htaccess.

Podívejte se do souboru httpd.conf, jestli direktivita AllowOverride je nastavena na All.

Začínáme se Zend Framework

Zend Framework si můžete stáhnout ze stránek http://framework.zend.com/download ve formátu .zip nebo .tar.gz.

Adresářová struktura

Zend Framework vám nenařizuje striktně používat jednotnou strukturu aplikace, ale je doporučené držet se navrhované struktury v manuálu. Budeme tedy vycházet z dané struktury, která počítá s tím, že máte plnou kontrolu nad Apache serverem a můžete aplikaci umístit mimo web root adresář.

Začneme vytvořením adresáře zf-tutorial v kořenovém adresáři webového serveru (Apache). To znamená, že URL námi vytvořené aplikace bude dostupné na adrese http://localhost/zf-tutorial.

Vytvořte následující podadresáře:

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

Jak vidíte, vytvořili jsme rozdílné adresáře pro model, view a controller soubory naší aplikace. Podporované obrázky, skripty a CSS soubory jsou uloženy ve zvláštních adresářích ve složce public. Soubory Zend Framework budou uloženy v adresáři library. Pokud budeme potřebovat nějaké další knihovny, je vhodné umístit je do složky library. Důležité je si uvědomit, že hlavní stránka naší aplikace se bude nacházet na adrese http://localhost/…rial/public/ a je vhodné tedy zamezit přístup přes web do ostatních složek kvůli bezpečnosti.

Rozbalte soubory z archivu ZendFramework-1.5.0.zip do dočasné složky. Všechny soubory jsou umístěny v podadresáři ZendFramework-1.5.0. Zkopírujte obsah adresáře library/Zend do zf-tutorial/library/. V adresáři zf-tutorial/library/ tedy budete mít podadresář Zend.

Bootstrap

Zend Framework a jeho controller Zend_Controller byl vytvořen tak, aby podporoval hezká URL. Pokud tohoto chcete dosáhnout, musí jít veškeré požadavky na aplikaci přes soubor index.php, kterému se říká bootstrap soubor. Veškeré požadavky tedy budou přesměrovány na tento soubor pomocí souboru .htaccess v adresáři zf-tutorial/public:

zf-tutorial/public/.htaccess

# Rewrite rules for Zend Framework
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php

# Security: Don't allow browsing of directories
Options -Indexes

# PHP settings
php_flag magic_quotes_gpc off
php_flag register_globals off
php_flag short_open_tag on

Pravidlo RewriteRule je velmi jednoduché a slovně ho lze vyjádřit „vezmi jakoukoliv URL a přesměruj na index.php“.

Také definujeme několik PHP ini nastavení kvůli bezpečnosti. Tyto parametry jsou pravděpodobně již nastaveny, ale my se potřebujeme ujistit, že tomu skutečně tak je. Poznámka: php_flag nastavení v souboru .htaccess funguje pouze pokud používáte mod_php. Pokud používáte CGI/FastCGI, budete muset nastavení provést v konfiguračním souboru php.ini.

Bootstrap soubor: index.php

zf-tutorial/public/index.php je náš bootstrap soubor a my nyní začneme s následujícím kódem:

zf-tutorial/public/index.php

<?php

error_reporting(E_ALL|E_STRICT);
ini_set('display_errors', 1);
date_default_timezone_set('Europe/London');

// directory setup and class loading
set_include_path('.' . PATH_SEPARATOR . '../library/'
     . PATH_SEPARATOR . '../application/models'
     . PATH_SEPARATOR . get_include_path());
include "Zend/Loader.php";
Zend_Loader::registerAutoload();

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

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

Určitě jste si všimli, že na konci souboru chybí ?>. Uzavření není potřeba a dokážeme jejím vynecháním předejít mnoha složitě odhalitelných chyb pokud používáme přesměrování přes header() a na konci souboru se vyskytuje „prázdné místo“.

Pojďme si projít soubor index.php

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

Tyto řádky slouží k tomu, že budeme informováni o všech chybách, které ať už úmyslně nebo neúmyslně vytvoříme (direktivita display_errors musí být nastavena na on v souboru php.ini). Také zvolíme naše časové pásmo, jak požaduje specifikace PHP 5.1+.

// directory setup and class loading
set_include_path('.' . PATH_SEPARATOR . '../library/'
     . PATH_SEPARATOR . '../application/models'
     . PATH_SEPARATOR . get_include_path());
include "Zend/Loader.php";
Zend_Loader::registerAutoload();

Zend Framework je koncipován tak, že cesty k jeho souborům musí být definovány v include_path. Pro usnadnění si do include_path přidáme i cestu k model, takže budou naše třídy později snadno dostupné. Jako první připojíme soubor Zend/Loader.php, který nám spřístupní třídu Zend_Loader. Pak můžeme použít její metodu registerAutoload() pro automatické nahrávání potřebných tříd.

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

Protože se jedná pouze o ukázkovou aplikaci, nastavíme front controller tak, aby se zobrazovaly veškeré vyjímky. Defaultně front controller vyjímky zachytí a přesměruje je do ErrorController. To může být matoucí pro nováčky, proto raději zobrazíme všechny. Nicméně na produkčním serveru by uživatel nikdy neměl žádnou vyjímku spatřit!

Front controller používá třídu router pro analýzu URL a vytvoření cesty k funkci, která zobrazí správnou stránku. Aby mohla třída router správně analyzovat URL, musí vědět, která část URL vede k index.php a od tohoto místa začít. Za normálních okolností by měl Request object zjistit umístění souboru index.php sám. V některých případech je ale potřeba tuto cestu manuálně nastavit $frontController->setBaseUrl().

Nakonec se dostaneme k tomu hlavnímu – aplikaci spustíme:

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

Pokud nyní načtete stránku http://localhost/…orial/public měla by se vám zobrazit tato chyba:

Fatal error: Uncaught exception 'Zend_Controller_Dispatcher_Exception' with
message 'Invalid controller specified (index)' in…

Tato chyba se nám zobrazuje z důvodu toho, že jsme ještě neprovedli veškeré potřebné nastavení aplikace. Nejdříve si ale popíšeme to, co bude naše aplikace vlastně dělat.

Co to vůbec vytváříme za aplikaci?

Naše aplikace bude fungovat jako jednoduchý organizér nějaké sbírky CD nebo DVD. Na hlavní stránce bude zobrazen obsah naší sbírky, a také možnost přidání, editace nebo smazání jednotlivých položek. Pro uložení dat o naší sbírce využijeme databázi, která bude obsahovat tabulku album s následující strukturou:

Sloupec Typ Nulový Poznámka
id Integer Ne Primary key, Autoincrement
artist Varchar(100) Ne  
title Varchar (100) Ne  

Jednotlivé stránky

Home page Na hlavní stránce se zobrazí obsah naší sbírky spolu s odkazy na přidání, editaci nebo smazání jednotlivých položek.
Add New Album Tato stránka bude obsahovat formulář pro přidání nového alba.
Edit Album Tato stránka bude obsahovat formulář pro editaci alba.
Delete Album Na této stránce potvrdíte, jestli opravdu chcete album smazat.

Umístění jednotlivých stránek

Ještě předtím než začneme vytvářet jednotlivé soubory, je důležité, aby jste pochopili, kde framework bude hledat vaše soubory a proč. Každá stránka se nazývá „action“ a actions jsou sdruženy do „controllers“. Když tedy budeme chtít zobrazit stránku http://localhost/…al/news/view tak pro nás controller bude news a action view. To nám umožňuje sdružovat podobné actions. Například controller news může mít action current, archived a view. Zend Framework a jeho MVC struktura také podporuje moduly, které nám pro změnu umožňují sdružovat controllers dohromady. Tato aplikace ale pro toto použítí není dostatečně rozsáhlá.

Zend Framework a jeho controller obsahuje speciální action nazvanou index která je použita jako výchozí. To znamená, že pro URL http://localhost/…torial/news/ je controller news a action index. Jak už možná tušíte, Zend Framework obsahuje i výchozí controller, který je opět nazvaný index. Pokud tedy zadáte URL http://localhost/zf-tutorial/ jako controller se použije index a jako action také index. Je doporučeno defaultní controller nebo action vynechávat.

Protože se jedná o základní tutoriál, nebudeme u aplikace zacházet do takových detailů, jako je přihlašování a odhlašování uživatelů. Nicméně pokud vás to zajímá, pokračování tohoto tutoriálu se právě touto funkcí zabývá – Getting Started with Zend_Auth (pokud bude zájem, jsem ochoten přeložit)

Máme tedy čtyři stránky, které pracují s naší aplikací pro organizování CD. Bude tedy vhodné sdružit je do jediného controlleru a čtyř action. Použijeme výchozí controller index a následující actions:

Stránka Controller Action
Home page Index index
Add New Album Index add
Edit Album Index edit
Delete Album Index delete

Vidíte jak je to jednoduché 🙂

Nastavujeme Controller

V frameworku je controller třída a musí být nazvána {název Controlleru}Controller. {název Controlleru} musí začínat velkým písmenem. Tento controller musí být uložen v souboru nazvaném {název Controlleru}Controller.php uvnitř adresáře určeného pro controllery. Nezapomeňte na to, že první písmeno musí být velké a ostatní malá! Každá action je public function, kterou obsahuje třída controller. Akce musí být pojmenována {název action}Action. Pro název action používáme hned od začátku malá písmena.

Nyní již máme vytvořenou třídu IndexController, která je uložena v souboru zf-tutorial/application/controllers/IndexController.php:

zf-tutorial/application/controllers/IndexController.php

<?php

class IndexController extends Zend_Controller_Action
{
    function indexAction()
    {
    }

    function addAction()
    {
    }

    function editAction()
    {
    }

    function deleteAction()
    {
    }
}

Nyní jsme vytvořili čtyři akce, které zatím nebudou fungovat. Musíme jim definovat views.

URL pro jednotlivé akce jsou:

URL Action
http://localhost/…rial/public/ IndexController::indexAction()
http://localhost/…ic/index/add IndexController::addAction()
http://localhost/…c/index/edit IndexController::editAction()
http://localhost/…index/delete IndexController::deleteAction()

Nyní máme vytvořený funkční router a je čas na přípravu views.

Nastavujeme Views

Komponenta view frameworku je nazvána vcelku logicky Zend_View. Ta nám umožňuje oddělit kód, který se stará o zobrazení stránky (nejčastěji HTML) od kódu v příslušné action a tím aplikaci spřehlednit.

Základní použití Zend_View je následující:

$view = new Zend_View();
$view->setScriptPath('/path/to/view_files');
echo $view->render('viewScipt.php');

Tento kód bychom jednoduše mohli umístit do každé action, bylo by to ale zbytečné. Mnohem lepší je inicializovat třídu view někde jinde a v action jen přistupovat na objekt třídy view. Vývojáři Zend Framework to vyřešili tím, že vytvořili tzv. „action helper“.

Zend_Controller_Action_Helper_ViewRenderer se nám tedy postárá o inicializaci objektu view($this->view) a zároveň vygeneruje view skript. Dále nastaví objektu Zend_View cestu k view skriptu views/scripts/{controller name}. Tento se ve výchozím nastavení nachází views/scripts/{controller name}/{action_name}.phtml. Výsledný obsah stránky je přidán do objektu Response. Objekt Response sdružuje všechny HTTP hlavičky, obsah stránky a vyjímky vzniklé v důsledku použítí MVC. Front Controller poté automaticky pošle hlavičku a obsah body na konci dispatchingu.

Abychom si ověřili, že views fungují správně, vytvoříme si pro každý view samostatný soubor a dále v action specifický obsah.

Změníme soubor IndexController naslédovně:

zf-tutorial/application/controllers/IndexController.php

<?php

class IndexController extends Zend_Controller_Action
{
    function indexAction()
    {
        $this->view->title = "My Albums";
    }

    function addAction()
    {
        $this->view->title = "Add New Album";
    }

    function editAction()
    {
        $this->view->title = "Edit Album";
    }

    function deleteAction()
    {
        $this->view->title = "Delete Album";
    }
}

V každé funkci jsme přiřadili proměnnou title objektu view. Nezapomínejte na to, že tento text se zobrazí teprve až projde přes Front Controller na konci procesu nazvaném dispatching, který se volá až na úplném konci běhu aplikace.

Nyní potřebujeme vytvořit view soubory pro naší aplikaci. Tyto soubory můžeme také nazvat šablony. Metoda render() očekává, že šablony jsou pojmenovány podle přidružených action s koncovkou .phtml. Soubory musí být umístěny v podadresáři, který je pojmenován podle controlleru.

zf-tutorial/application/views/scripts/index/index.phtml

<html>
<head>
 <title><?php echo $this->escape($this->title); ?></title>
</head>
<body>
 <h1><?php echo $this->escape($this->title); ?></h1>
</body>
</html>

zf-tutorial/application/views/scripts/index/add.phtml

<html>
<head>
 <title><?php echo $this->escape($this->title); ?></title>
</head>
<body>
 <h1><?php echo $this->escape($this->title); ?></h1>
</body>
</html>

zf-tutorial/application/views/scripts/index/edit.phtml

<html>
<head>
 <title><?php echo $this->escape($this->title); ?></title>
</head>
<body>
 <h1><?php echo $this->escape($this->title); ?></h1>
</body>
</html>

zf-tutorial/application/views/scripts/index/delete.phtml

<html>
<head>
 <title><?php echo $this->escape($this->title); ?></title>
</head>
<body>
 <h1><?php echo $this->escape($this->title); ?></h1>
</body>
</html>

Pokud nyní otestujete jednotlivé URL vypsané výše v tabulce, měly by se zobrazit title definované v controlleru a k přidružené action.

Pár řádků HTML kódu

Je tedy jasné, že view obsahují velké množství HTML kódu. A co s tím provedeme? Nyní přichází na řadu NOVINKA v Zend Framework 1.5 a to komponenta Zend_Layout. Ta nám umožňuje umístit veškerý kód typický pro header a footer do layout view scriptu, který je pak přístupný specifickým actions.

Následující změny provedeme, aby jsme předchozí odstavec uplatnili v naší aplikaci. Jako první si musíme zvolit, kde se budou nacházet naše layout view scripty. V manuálu je doporučené vytvořit složku layouts v adresáři zf-tutorial/application, budeme se ho tedy držet.

Zároveň musíme komponentu Zend_Layout inicializovat v boostrap souboru. Doplníme tedy následující řádky do souboru public/index.php.

zf-tutorial/public/index.php

...
$frontController->throwExceptions(true);
$frontController->setControllerDirectory('../application/controllers');
Zend_Layout::startMvc(array('layoutPath'=>'../application/layouts'));

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

Funkce startMvc() provede na pozadí několik změn ve front controller, aby správně fungovaly naše layout view scripty v adresáři zf-tutorial/application/layouts

Nyní už se dostáváme k vytvoření prvního layout view scriptu, který se defaultně jmenuje layout.phtml.

Vytvoříme si jej.

zf-tutorial/application/layouts/layout.phtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <title><?php echo $this->escape($this->title); ?></title>
</head>
<body>
<div id="content">
    <h1><?php echo $this->escape($this->title); ?></h1>
    <?php echo $this->layout()->content; ?>
</div>
</body>
</html>

Poznámka: Jelikož se nadpis <h1> vyskytuje na každé stránce na stejném místě, je vhodné umístit ho přímo sem. Abychom se ujistili, že se nadpis zobrazí správně, aplikujeme na něj view helper escape().

Obsah sdružuje layout() view helper: echo $this->layout()->content;. Znamená to, že view scripty pro zvolenou action proběhnou dříve než samotný layout view script.

V následujícím kroku si ověříme funkčnost. Smažte obsah souborů index.phtml, add.phtml, edit.phtml a delete.phtml.

Znovu vyzkoušejte všechny 4 URL adresy v tabulce výše. Vidíte nějakou změnu? Pokud ne, tak je to správně, protože vše funguje, tak jak má. Jediná změna je v tom, že jsme využili komponentu Zend_Layout, která nám podstatně zjednodušila práci. Škoda, že ve frameworku nebyla už dříve.

Stylování

Sice se jedná pouze o tutoriál, ale neodpoustil jsem si malé grafické vylepšení aplikace pomocí CSS. Na tomto příkladu si můžeme zároveň ukázat, jak odkazovat na externí soubory.

Protože URL neodkazují na správný root adresář, musíme si vytvořit view helper nazvaný baseUrl(), který nám vytvoří správnou URL adresu.

View helpers se nachází ve složce application/views/helpers a jsou pojmenovány následovně {Název helper}.php (první písmeno musí být velké) a třída ve které se view helper nachází se musí jmenovat Zend_Controller_Helper_{Název helper} (opět první písmeno velké). Ve třídě se musí nacházet metoda nazvaná {Název helper}() (pozor změna – první písmeno malé!). V tomto případě se soubor bude jmenovat BaseUrl.php.

zf-tutorial/application/views/helpers/BaseUrl.php

<?php

class Zend_View_Helper_BaseUrl
{
    function baseUrl()
    {
        $fc = Zend_Controller_Front::getInstance();
        return $fc->getBaseUrl();
    }
}

Jak vidíte, není to složitá metoda. Jednoduše jsme zavolali instanci front controller a vrátili hodnotu metody getBaseUrl().

Nyní již můžeme přidat do <head> odkaz na CSS soubor. Editujeme soubor application/layouts/layout.phtml.

zf-tutorial/application/layouts/layout.phtml

...
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <title><?php echo $this->escape($this->title); ?></title>
    <link rel="stylesheet" type="text/css" media="screen"
             href="<?php echo $this->baseUrl();?>/css/site.css" />
</head>
...

A nakonec samozřejmě vytvoříme CSS soubor.

zf-tutorial/public/css/site.css

body,html {
    margin: 0 5px;
    font-family: Verdana,sans-serif;
}
h1 {
    font-size:1.4em;
    color: #008000;
}
a {
    color: #008000;
}

/* Table */
th {
    text-align: left;
}
td, th {
    padding-right: 5px;
}

/* style form */
form dt {
    width: 100px;
    display: block;
    float: left;
    clear: left;
}
form dd {
    margin-left: 0;
    float: left;

}
form #submitbutton {
    margin-left: 100px;
}

Tak a teď už to vypadá trošku lépe.

Databáze

Nyní, když jsme oddělili ovládání aplikace a zobrazení použitím views se vrhneme na model. Opakování je matka moudrosti, takže model ja ta část aplikace, která má na starost data. Je to objekt(kolekce objektů), který je volán ve view. V naší aplikaci bude tedy pracovat s databází. K tomu použijeme třídu Zend_Db_Table, která má v Zend Framework na starost práci s databází.

Nastavení

Nyní provedeme konfiguraci třídy Zend_Db_Table. Třídě musíme nastavit typ databáze, který použijeme(MySQL) a přihlašovací údaje do databáze. Na tomto příkladu si ukážeme použití další třídy přímo ze Zend Framework – Zend_Config. Ta nám rychle objektově spřístupní veškeré konfigurační soubory. Konfigurační soubor může být buď INI nebo XML. My použijeme INI.

zf-tutorial/application/config.ini

[general]
db.adapter = PDO_MYSQL
db.params.host = localhost

db.params.username = rob
db.params.password = 123456
db.params.dbname = zftest

Nezapomeňte použít vaše vlastní přihlašovací údaje do databáze! V rozsáhlejších aplikacích je vhodné pro konfigurační soubory vytvořit vlastní adresář.

Použítí Zend_Config je následně velmi jednoduché:

$config = new Zend_Config_Ini('config.ini', 'section');

V této konfiguraci Zend_Config_Ini načte pouze jednu sekci s názvem section(naše sekce má název general). Dále je také podporováno použití poznámky u jména section, pomocí které můžeme načíst další section. Pro oddělení hiearchické struktury se používá tečka, což znamená že podobné direktivity můžeme sdružit. V našem příkladě bude host, username, password a dbname sdruženo pod objekt $config->params->config.

A kam umístit načtení třídy Zend_Config? No přece do bootstrap souboru(public/index.php):

zf-tutorial/public/index.php

...
include "Zend/Loader.php";
Zend_Loader::registerAutoload();

// load configuration
$config = new Zend_Config_Ini('../application/config.ini', 'general');
$registry = Zend_Registry::getInstance();
$registry->set('config', $config);

// setup controller
$frontController = Zend_Controller_Front::getInstance();
...

Nejprve načteme třídy, které budeme potřebovat – Zend_Registry a Zend_Config_Ini. Jako parametr pro třídu Zend_Config_Ini použijeme cestu k souboru config.ini a jako název section general čímž vše načteme do objektu $config. Nakonec objekt $config přiřadíme do objektu $registry s pomocí třídy Zend_Registry a to z důvodu toho, že nyní budeme mít ke konfiguraci přístup v celé aplikaci.

Poznámka: V této ukázkové aplikaci je zbytečné, aby přihlašovací údaje do databáze byly globálně přístupné. Můžeme si tak ale demonstrovat případ, kdy bude konfigurační soubor obsahovat mnohem více nastavení, ke kterému budeme potřebovat přístupovat v celé aplikaci.

Nastavujeme Zend_Db_Table

Pro použití Zend_Db_Table potřebujeme nejdříve předat konfigurační údaje, které jsme právě načetli. Vytvoříme instanci Zend_Db a pak ji přiřadíme statickou metodou Zend_Db_Table:: setDefaultAdapter(). Tohle všechno opět provedeme v boostrap souboru(public/index.php):

zf-tutorial/public/index.php

...
$registry = Zend_Registry::getInstance();
$registry->set('config', $config);

// setup database
$db = Zend_Db::factory($config->db);
Zend_Db_Table::setDefaultAdapter($db);

// setup controller
$frontController = Zend_Controller_Front::getInstance();
...

Vytvoříme tabulku

Nejdříve vytvoříme, pokud jste ještě tak neučinili, databázi zftest. Pak v ní tabulku album například pomocí aplikace PhpMyAdmin.

CREATE TABLE albums (
  id int(11) NOT NULL auto_increment,
  artist varchar(100) NOT NULL,
  title varchar(100) NOT NULL,
  PRIMARY KEY (id)
);

Naplníme tabulku

Do tabulky si vložíme několik položek. Můžeme třeba použít první dvě z Hot 100” CDs from Amazon.co.uk.

INSERT INTO albums (artist, title)
VALUES
('Duffy', 'Rockferry'),
('Van Morrison', 'Keep It Simple');

Model

Zend_Db_Table je abstraktní třída, musíme ji tedy rozšířit tak, aby pracovala s naší vzorovou aplikací. Vytvoříme si tedy třídu pojmenovanou Albums podle názvu tabulky v databázi. Třídě Zend_Db_Table nastavíme protected proměnnou $_name, která bude obsahovat název tabulky. Zend_Db_Table počítá s tím, že primární klíč je pojmenován id a má hodnotu auto increment. Sloupec s primárním klíčem si ale můžete pojmenovat i podle sebe, jen pak jeho název musíte předat tříde Zend_Db_Table.

Naši třídu Albums tedy uložíme v adresáři určeném pro models:

zf-tutorial/application/models/Albums.php

<?php

class Albums extends Zend_Db_Table
{
    protected $_name = 'albums';
}

Pro naši jednoduchou aplikaci nepotřebujeme třídu více rozšiřovat. Pokud budete mít nějaké další plány s modelem, je tohle to pravé místo, kde tak učinit.

Výpis alb

Nyní se konečně dostáváme k cíli naší aplikace a zobrazíme si výpis alb. To provedeme ve třídě IndexController a action nazvané indexAction().

zf-tutorial/application/controllers/IndexController.php

...
function indexAction()
{
    $this->view->title = "My Albums";
    $albums = new Albums();
    $this->view->albums = $albums->fetchAll();

}
...

Metoda fetchAll() navrací Zend_Db_Table_Rowset, který nám umožňuje procházet postupně všechny řádky pomocí iterace. Naplníme tedy soubor index.phtml.

zf-tutorial/application/views/scripts/index/index.phtml

<p><a href="<?php echo $this->url(array('controller'=>'index',
        'action'=>'add'));?>">Add new album</a></p>
<table>
<tr>
    <th>Title</th>
    <th>Artist</th>
    <th>&nbsp;</th>
</tr>
<?php foreach($this->albums as $album) : ?>
<tr>
    <td><?php echo $this->escape($album->title);?></td>
    <td><?php echo $this->escape($album->artist);?></td>
    <td>
        <a href="<?php echo $this->url(array('controller'=>'index',
            'action'=>'edit', 'id'=>$album->id));?>">Edit</a>
        <a href="<?php echo $this->url(array('controller'=>'index',
            'action'=>'delete', 'id'=>$album->id));?>">Delete</a>
    </td>
</tr>
<?php endforeach; ?>
</table>

Jako první jsme vytvořili odkaz na přidání nového alba. View helper url() nám automaticky poskládá správnou URL, jestliže mu v poli předáme jednotlivé parametry. Pak vytvoříme tabulku, která bude zobrazovat název alba, umělce a dále odkaz na editaci nebo smazání záznamu. Pro zobrazení všech alb je použit cyklus foreach. Pokud jste někde neudělali chybu, na hlavní stránce se vám právě zobrazil výpis alb (jsou dvě).

Přidáváme nové album

Nyní se vrhneme na tvorbu obslužné části pro přidání nového alba. Ta má dvě části:

  • Vypíše se jednoduchý formulář pro přidání alba
  • Data od uživatele se uloží do databáze

Tak tady využijeme další NOVINKY v Zend Framework 1.5 a to komponenty Zend_Form. Zend_Form nám usnadňuje práci s vytvářením formulářů a jejich následné kontrole. Vytvoříme si tedy novou třídu nazvanou AlbumForm, která se v naší MVC struktuře řadí do části model (viz. tabulka úplně na začátku).

Naše třída AlbumForm bude potomek Zend_Form:

zf-tutorial/application/models/AlbumForm.php

<?php

class AlbumForm extends Zend_Form
{
    public function __construct($options = null)
    {
        parent::__construct($options);
        $this->setName('album');

        $id = new Zend_Form_Element_Hidden('id');

        $artist = new Zend_Form_Element_Text('artist');
        $artist->setLabel('Artist')
        ->setRequired(true)
        ->addFilter('StripTags')
        ->addFilter('StringTrim')
        ->addValidator('NotEmpty');

        $title = new Zend_Form_Element_Text('title');
        $title->setLabel('Title')
        ->setRequired(true)
        ->addFilter('StripTags')
        ->addFilter('StringTrim')
        ->addValidator('NotEmpty');

        $submit = new Zend_Form_Element_Submit('submit');
        $submit->setAttrib('id', 'submitbutton');

        $this->addElements(array($id, $artist, $title, $submit));
    }
}

Přímo v konstruktoru naší třídy AlbumForm vytvoříme 4 prvky – id, artist, title a submit. Pro každý prvek definujeme potřebné atributy včetně popisku v <label>. Pro textový prvek definujeme dva filtry – StripTags(odstranění html tagů) a StringTrim(odstranění mezer na začátku a konci řetězce), poté nastavíme, že prvek musí být zadaný(Required) a nakonec přidáme validátor na prázdnost řetězce.

Model máme hotový a teď se vrhneme na controller. Upravujeme metodu addAction() v souboru indexController.php:

zf-tutorial/application/controllers/IndexController.php

...
    function addAction()
    {
        $this->view->title = "Add New Album";

        $form = new AlbumForm();
        $form->submit->setLabel('Add');
        $this->view->form = $form;

        if ($this->_request->isPost()) {
            $formData = $this->_request->getPost();
            if ($form->isValid($formData)) {
                $albums = new Albums();
                $row = $albums->createRow();
                $row->artist = $form->getValue('artist');
                $row->title = $form->getValue('title');
                $row->save();

                $this->_redirect('/');
            } else {
                $form->populate($formData);
            }
        }
    }
...

Nyní si výše uvedený kód rozebeme řádek po řádku, protože je velmi důležitý.

$form = new AlbumForm();
$form->submit->setLabel('Add');
$this->view->form = $form;

Jako první si vytvoříme novou instanci naší třídy AlbumForm. Následně si definujeme popisek tlačítka submit. Poslední řádek přidá naše atributy do view pro zobrazení.

if ($this->_request->isPost()) {
    $formData = $this->_request->getPost();
    if ($form->isValid($formData)) {

Pokud nabývá metoda isPost() hodnotu true, formulář byl odeslán ke zpracování. Nyní můžeme k odeslaným datům přistupovat přes metodu getPost() a zkontrolovat zadané údaje pomocí metody isValid().

$albums = new Albums();
$row = $albums->createRow();
$row->artist = $form->getValue('artist');
$row->title = $form->getValue('title');
$row->save();
$this->_redirect('/');

Pokud náš formulář prošel kontrolou, vytvoříme si instanci třídy Albums (v MVC se jedná o model). Použijeme metodu této třídy createRow(). Předáme ji naše atributy artist a title a uložíme save(). Nakonec přesměrujeme na hlavní stránku pomocí metody controlleru _redirect().

} else {
    $form->populate($formData);
}

Pokud data z formuláře nejsou validní, vrátíme uživateli formulář včetně nesprávně vyplněných dat.

Nyní máme i úpravu controlleru za sebou a je čas se vrhnout na poslední část a tou je vytvoření view v souboru add.phtml

zf-tutorial/application/views/scripts/index/add.phtml

<?php echo $this->form ;?>

No povězte, není to mnohem jednodušší než datlovat ručně html kód 🙂 Dalo by se to přirovnat jak když hážete lopatou a pak přijede bagr a má stejnou práci hotovou mnohem dříve.

Editujeme album

Editování alba je velmi pobodné, takže ho nemusíme rozebírat:

zf-tutorial/application/controllers/IndexController.php

...
   function editAction()
   {
       $this->view->title = "Edit Album";

       $form = new AlbumForm();
       $form->submit->setLabel('Save');
       $this->view->form = $form;

       if ($this->_request->isPost()) {
           $formData = $this->_request->getPost();
           if ($form->isValid($formData)) {
               $albums = new Albums();
               $id = (int)$form->getValue('id');
               $row = $albums->fetchRow('id='.$id);
               $row->artist = $form->getValue('artist');
               $row->title = $form->getValue('title');
               $row->save();

               $this->_redirect('/');
           } else {
               $form->populate($formData);
           }
       } else {
           // album id is expected in $params['id']
           $id = (int)$this->_request->getParam('id', 0);
           if ($id > 0) {
               $albums = new Albums();
               $album = $albums->fetchRow('id='.$id);
               $form->populate($album->toArray());
           }
       }
   }
   ...

Výše uvedený kód nebudeme rozebírat řádek po řádku, protože kód je velmi podobný metodě addAction(). Rozebeme si akorát několik rozdílů. Jako první musíme informace o požadovaném záznamu získat z databáze a uložit je do proměnných formuláře.

// album id is expected in $params['id']
$id = (int)$this->_request->getParam('id', 0);
if ($id > 0) {
    $albums = new Albums();
    $album = $albums->fetchRow('id='.$id);
    $form->populate($album->toArray());
}

Aby tento kód fungoval, nesmí být id předáváno metodou POST. Dále využíváme námi vytvořené třídy Albums() pro získání informací o záznamu z databáze. Data vybraná z db můžeme přímo vložit do formuláře přes metodu toArray() třídy Zend_Db_Table_Row.

A nakonec změněná data uložíme na původní místo do databáze.

$albums = new Albums();
$id = (int)$form->getValue('id');
$row = $albums->fetchRow('id='.$id);

Nejlepší na tom je, že šablona pro editaci je stejná jako pro přidání.

zf-tutorial/application/views/scripts/index/edit.phtml

<?php echo $this->form ;?>

Teď už by vám mělo fungovat přidávání a editace alb.

Mazání alb

Aby naše aplikace byla kompletní, musíme uživatelům umožnit alba smazat. Vedle výpisu každého alba se zobrazuje odkaz na editaci a smazání každé položky. Po kliknutí na tlačítko smazat se nejprve objeví potvrzovací stránka a až poté se položka definitivně smaže z databáze.

zf-tutorial/application/controllers/IndexController.php

...
    function deleteAction()
    {
        $this->view->title = "Delete Album";

        if ($this->_request->isPost()) {
            $id = (int)$this->_request->getPost('id');
            $del = $this->_request->getPost('del');
            if ($del == 'Yes' && $id > 0) {
                $albums = new Albums();
                $where = 'id = ' . $id;
                $albums->delete($where);
            }
            $this->_redirect('/');
        } else {
            $id = (int)$this->_request->getParam('id');
            if ($id > 0) {
                $albums = new Albums();
                $this->view->album = $albums->fetchRow('id='.$id);
            }
        }
    }
...

Použijeme metodu isPost(), na jejichž základě rozhodneme, zda teprve vypíšeme potvrzení nebo už máme potvrzeno, že záznam můžeme smazat. Vlastní smazání je řešené metodou delete() třídy Zend_Db_Table. Ještě bych tu rád zmínil, že pokud není použita metoda post, zkusíme získat id z URL a načíst korektní data z db.

A na závěr view skript:

zf-tutorial/application/views/scripts/index/delete.phtml

<?php if ($this->album) :?>
<p>Are you sure that you want to delete
  '<?php echo $this->escape($this->album->title); ?>' by
  '<?php echo $this->escape($this->album->artist); ?>'?
</p>
<form action="<?php echo $this->url(array('action'=>'delete')); ?>"
method="post">
<div>
  <input type="hidden" name="id" value="<?php echo $this->album->id; ?>" />
  <input type="submit" name="del" value="Yes" />
  <input type="submit" name="del" value="No" />
</div>
</form>
<?php else: ?>
<p>Cannot find album.</p>
<?php endif;?>

Po kliknutí na tlačítko smazat ve výpisu alb se nám nejdříve zobrazí dotaz, jestli chceme záznam opravdu smazat. Pokud ho potvrdíme, dojde k fyzickému smazání záznamu z databáze.

A jsme u konce. Právě máte před sebou plně funkční aplikaci postavenou na nejnovějším Zend Framework. Oproti starší verzi jsme se naučili používat Zend_Layout a Zend_Form.

Řešení problémů

Pokud máte problém s tím, že fungují všechny stránky kromě hlavní (index/index) je pravděpodobné, že router není schopen určit ve kterém podadresáři se nachází vaše aplikace. Trochu jsem pátral, proč tomu tak je a zjistil jsem, že se to stává, když URL na vaše stránky se liší od kořenového adresáře, kde je aplikace umístěna. Mělo by pomoct nastavit $baseURL.

zf-tutorial/public/index.php

...
// setup controller
$frontController = Zend_Controller_Front::getInstance();
$frontController->throwExceptions(true);
$frontController->setControllerDirectory('../application/controllers');
$frontController->setBaseUrl('/mysubdir/zf-tutorial/public');
Zend_Layout::startMvc(array('layoutPath'=>'../application/layouts'));
...

Nahraďte ‚/mysubdir/zf-tutorial/public‘ správnou URL k index.php. Pokud je index.php dostupný na adrese http://localhost/…ic/index.php ,pak správná hodnota $baseUrl je ‚/~ralle/zf-tutorial/public‘.

Závěr

Doufám, že byl tento tutoriál pro vás užitečný. Pokud naleznete jakukoliv chybu v mém překladu, budu rád, když mi o tom dáte vědět, abych ji mohl opravit.



Komentáře

  1. janko 02.06.08 21:16

    Comment Arrow

    Nevím jak to je v originále, ale doctype se doporučuje nastavit v bootstrapu $template->doctype(‚XHTML1_STRICT‘); a v šabloně volat pomocí echo $this->doctype();. Na nastavení docytpe se totiž vážou i jiná vykreslení (např. Zend_Form).

    K volání css, nestačí místo helperu BaseURL použít jenom relativní cesty? A na vykreslení v templatu se od 1.5 dá použít hezký helper $this->headLink().

    Mimochodem je fajn že to překládáš dál, jak jsem se do tajů ZF zasvěcoval prvně, tvůj překlad mi dost pomohl ;)


  2. Pari 02.06.08 21:35

    Comment Arrow

    janko Díky za reakci a doplnění. Tvé informace se určitě spoustě čtenářů budou hodit.


  3. Ondra 11.06.08 15:04

    Comment Arrow

    Ahoj. Vše funguje v pohodě do té doby bnež chci načíst Zend_Config_Ini…vyhodí mi to error Fatal error: Class ‚Zend_Config_Ini‘ not found in C:\dev\www\opensource\zend\my\public\index.php on line 14. Nevíš co s tím?


  4. Pari 11.06.08 20:16

    Comment Arrow

    A to mas vytvorene podle tohoto tutorialu samostatne nebo sis stahnul uz hotovou aplikaci a nefunguje? Podle toho zalezi jestli je chyba v aplikaci nebo v nastaveni LAMP.


  5. Visitor 12.06.08 06:48

    Comment Arrow

    Pekne… vcera jsem sotva dodelal ten tutorial 1.0 a muzu na neho zapomenout a zacit s 1.5 :)


  6. Visitor 12.06.08 07:48

    Comment Arrow

    Tak jsme se tim prokousal… Vypada to moc dobre a moc dekuji…

    Ale dovoluji si upozornit na par chyb v nezobrazeni casti kodu ve spravnem formatovani (samozrejme jen technicka pripominka).
    1/ /---code php $form = new AlbumForm();…
    2/ $albums = new Albums(); …

    Dale si neodpustim komentovat zmenu oproti 1.0.

    1/ Proc nyni musime zacinat na http://www.example.com/public/ a ne jen http://www.example.com Asi by to melo byt resene Rewritem ne?
    2/ Take uz chybi „bezpecnostni“ .htaccess ve slozkach library, … Pokud napr. dam adresu: http://localhost/…Zend/Acl.php tak mi vypise nepekne chybove hlaseni misto chyby 403.

    Samozrejme toto je jen preklad ale jako zacatecnik bych tam tyto rady cekal nebo alespon upozorneni ze to neni osetrene.


  7. Pari 12.06.08 08:50

    Comment Arrow

    Diky za upozornění na chybky, opraveno.

    ad 1/ a 2/ Programování není exaktní, a proto vždy existuje několik přístupů, jak se dobrat ke stejnému výsledku. Je normální, že jakmile něco naprogramujeme, už přemýšlíme, že jsme to mohli napsat lépe. Tohle řešení je mnohem lepší než předešlé, protože nespoléhá na fungování mod rewrite. Kdyby nefungovalo, mohlo by se stát, že by útočník o naší aplikaci zjistil příliš mnoho. Jednoduše root domény nasměrujeme přímo na adresář public v administraci webhostingu. Z webu se pak nedá dostat na nadřazené adresáře. Navíc to má také výhodu v tom, že se přímo nabízí možnost provozování na jednom webhostingu několika aplikací, které běží na ZF současně (místo public by byl třeba adresář web1,web2,web3,…)

    Článek nemůže obsáhnout vše a je zaměřen především na ZF, kdyby rozebíral i takové věci, byl by příliš dlouhý…

    Díky za komentář.


  8. psxxsp 24.06.08 16:47

    Comment Arrow

    ak nahram na webhosting zend framework tka mi vadi jedno ze stranka bude potom http://www.mojadomena.sk/public/

    ale ja nechcem aby bola v public alebo normalne hned na http://www.mojadomena.sk

    ako to dosiahnut ? vdaka


  9. Pari 25.06.08 11:17

    Comment Arrow

    Je třeba aby to podporoval hosting, že root domény si můžeš nasměrovat do jakékoliv složky. Podporuje to třeba Savana.cz Jinak toho stejného lze samozřejmě docílit přes mod-rewrite, ale pak to ztrací opodstatnění. Pokud tedy hosting nepodporuje nasměrování do vlatního adresáře, je nejlepší použít stejnou strukturu jako v http://weblog.pari.cz/…nd-framework (index.php a .htaccess v hlavním adresáři a náležitě upravené konfigurační proměnné)


  10. plasmo 25.06.08 14:59

    Comment Arrow

    Ahoj, jak dosáhnu toho aby mi fungovalo $template->doctype(‚XHTML1_STRICT‘);, kterou třídu musím zinicializovat ?


  11. fero 26.06.08 09:49

    Comment Arrow

    Ahoj, měl bych dotaz ohledně view helperu Zend_View_Helper_Url. Pokud použiju helper $this->url(array(‚controller‘=>‚clanek‘, ‚action‘=>‚edit‘, ‚id‘=>5)); vytvoří se mi krásná adresa (např. http://domena.cz/…k/edit/id/5/), kterou můžu použít třeba do odkazu. V případě, že na tuto stránku přejdu a zde vytvořím pomocí helperu odkaz typu $this->url(array(‚controller‘=>‚diskuze‘)); výsledný odkaz je typu http://domena.cz/diskuze//id/5/.
    Zjistil jsem, že v Request objektu jsou parametry controller, action,… které url helper automaticky použije pro generování dalšího odkazu. Nezbývá proto nic jiného než tyto parametry ručně vynulovat.
    Chtěl bych se proto poradit, zda nevíte jak efektivně řešit takovéto generování odkazů, případně zda není jednodušší napsat si vlastní helper, který by využíval pouze předané parametry, nikoliv parametry obsažené již v Request objektu.

    Jinak mockrát díky za článek. Je opravdu super a hlavně popisuje reálný příklad!


  12. Dracek 15.07.08 14:54

    Comment Arrow

    Ja mam jednu dobnou otazecku. Kdyz jsem priklad vyzkousel, tak to vsechno krasne chodi. Ale nelibi se mi, ze add.phtml a edit.phtml jsou totozne, ale presto tam jsou uvedeny 2×. Prece ukolem frameworku je co nejmene psat kod. Je nejaka jednoducha moznost, jak to spojit do jednoho souboru?


  13. Lubo 16.07.08 08:44

    Comment Arrow

    zdravim .. mam problem s tymto frameworkom.. zacal som podla tutorialu na framework.zend.com (ten video tutorial ktory tam je).. vsetko bolo v poriadku.. avsak na druhy den ked som sa vratil k svojej app, aky kolvek iny controller ako IndexController my vypisal 404 Not Found.. a neviem prist na dovod.. nemate niekto skusenosti?

    dakujem,
    L


  14. Ondra 16.07.08 12:24

    Comment Arrow

    Ahoj. U kroku kdy se připojuje k databázi a vypisují se alba na indexAction mi to hodí chybu…
    Fatal error: Uncaught exception ‚Zend_Db_Adapter_Exception‘ with message ‚The PDO extension is required for this adapter but the extension is not loaded‘ in C:\dev\www\zf-tutorial\library\Zend\Db\Adapter\Pdo\Abstract.php:94 Stack trace: #0 C:\dev\www\zf-tutorial\library\Zend\Db\Adapter\Abstract.php(389):


  15. Ondra 16.07.08 13:50

    Comment Arrow

    Vyřešeno. Šlo o povolení pdo_mysql.dll v php.ini


  16. Siki 05.08.08 00:01

    Comment Arrow

    to Fero: sice je to trochu pozde, ale tvuj problem ma jedoduche reseni. Staci tvuj prikaz $this->url(array(‚controller‘=>‚clanek‘, ‚action‘=>‚edit‘, ‚id‘=>5)) zmenit na $this->url(array(‚controller‘=>‚clanek‘, ‚action‘=>‚edit‘, ‚id‘=>5), null, true) … 3 parametr (true) resetuje predchozi nataveni a vytvori cestu podle zadanych parametru.


  17. Ondra 07.08.08 11:25

    Comment Arrow

    Díky, jako začátečník s PHP i ZF jsem si lepší tutoriál než budu pokračovat dále knihou ZF in action nemohl přát.


  18. Vlada 10.08.08 10:20

    Comment Arrow

    Ahoj, rad bych se zeptal, co kdyz nestaci mit jeden hlavni layout v aplikaci (tedy vlastne jednu hlavni sablonu, do ktere se vsechny obsahy vkladaji), ale je potreba mit pro ruzna view (nebo i kontrolery) ruzne sablony (layouty) do ktzerych se obsah view generuje? Pak jeste doplnujici otazka… Business sluzby (napr. funkce generujici menu podle udaju v databazi) pouzivane v ruznych views i napric kontrolery se davaji do mych vlastnich trid do adresare library, nebo podle standardu zendu je mozne umistovat je primo do jednoho z kontroleru a z ostatnich kontroleru tento kontroler a tuto fci volat? To asi ne co?:)


  19. psxxsp 15.08.08 16:01

    Comment Arrow

    caute

    mam jednu otazku
    v tomto tutorialy sa formular uklada do models/formular.php

    ked ale citam tento turoial
    http://akrabat.com/…oad-example/
    tak tuna je formular ulozeny asi niekd euplne inde hmm – neviem nejako sa mi to nezda

    preco je to tak ?

    vdaka


  20. Fabian 18.09.08 00:08

    Comment Arrow

    Zdravim,
    moc diky za tutorial, ktery mi v mych zacatcich se ZF moc pomohl.
    Mam ale jeden problem: vytvoril jsem si web spolupracujici s MySQL databazi. Collation v ni mam utf8_czech_ci, ale ZF mi tam uklada nejak jinak. Zaznamy, ktere uz v db byly a jsou v utf8, vypisuje se spatnym kodovanim. Muze mi nekdo poradit, kde v ZF muzu nastavit, ze db je utf8? Diky


  21. Tomas Fejfar 02.11.08 12:01

    Comment Arrow

    Uděláš to stejně, jako bys to dělal v čístém MySQL – $db->query(‚SET NAMES utf8‘); :D


  22. Fabian 02.11.08 12:03

    Comment Arrow

    Jjj uz jsem na to prisel. Akorat jsem to sem mel napsat:) Dik


  23. liska-cz 11.11.08 09:52

    Comment Arrow

    moc pekny tutorial.) jen podotknu, pokud se vam bude zobrazovat jen hlavni stranka zkontrolujte nazev .htaccess, ne .htaccess.txt..) a u vytvoreni modelu Albums je potreba jeste v IndexControlleru nahrat tridu Albums..) a jeste jednou diky Parimu za preklad.)


  24. M.Holec 16.12.08 13:46

    Comment Arrow

    Nemůžu Zend frameworku přijít na chuť. Ohromná knihovna, která vyžaduje precizní přístup. PHP zdroj je možná o něco málo přehlednější ale neskutečně dlouhý. Pohled na způsob odstranění alba mě rozesmál. Očekával jsem lepší oddělení aplikace od šablony vzhledu ale ani to mě nenadchlo. V podstatě kodéři mohou rovnou upravovat procedurální smršť, jelikož žádné zlepšení přehlednost v Zend FW nevidím.

    Mám z toho pocit, že jednoduchou aplikaci tento framwork zneefektivní a zpomalí, byť do budoucna umožní lepší rozšiřitelnost? Na opravdu rozsáhlé aplikace si Zend stejně nedovedu představit, když například ASP.NET 2.0 má framework neskutečně komplexnější a jeho použitelnost je více než desetkrát rychlejší. Nemluvě o možnost pracovat ve vizuálním prostředí, což nevynahradí ani placený Zend Studio for Eclipse.

    Snad mě Zend Framework během týdne, který mu chci věnovat přesvědčí o opaku.


  25. jz 29.01.09 13:53

    Comment Arrow

    Tutorial som prepísal, ale keď chcem zobraziť hlavnú stránku, resp. http://localhost/…orial/public tak výsledkom je prázdna stránka a nasledovná chyba:
    Vyskytol sa problém s aplikáciou Apache HTTP Server, a preto je ju nutné ukončiť.
    Nastavil som aj setBaseUrl (použil som absolútnu cestu)
    $frontController->setBaseUrl(‚C:\tools\xampp\htdocs\zf-tutorial\public‘);
    Vyskúšal som aj opačné lomítka, ale nepomohlo. Používam WIN XP + XAMPP. Dík za akúkoľvek odpoveď.


  26. jz 29.01.09 14:17

    Comment Arrow

    Stiahol som si originál z http://akrabat.com/…rk-tutorial/ mám rovnaký problém, Apache v XAMPPe padá.


  27. jz 29.01.09 23:15

    Comment Arrow

    Problém vyriešený inštaláciou EasyPHP namiesto XAMPP. Tam sa úvodná stránka korektne zobrazí.


  28. Filip 26.02.09 10:09

    Comment Arrow

    asi dělám něco blbě ale došel jsem k tvorbě wievs a funguje mi jen index.phtml ostatní 3 stránky pod adrsami z tabulky nefungují a netuším proč vše mám uplně stejně jak to má být… index reaguje na změny vzhledu ve wievs ale ostatní se nezobrazují čím by to mohlo být?


  29. Cavalier 04.03.09 18:34

    Comment Arrow

    Problém s načtením třídy Albums. V souboru IndexController v metodě indexAction mám problém s voláním třídy $albums = new Albums(), kterou mám umístěnou v adresáři models. Vůbec se tato třída nenačte a vyhodí se chybová hláška

    Warning: Zend_Loader::include_once() [function.include]: Failed opening ‚Albums.php‘ for inclusion (include_path=‚......./bin/php5/lib/php‘) in /Users/cavalier/Sites/cms/library/Zend/Loader.php on line 83

    Se ZF úplně začínám, tak jestli mi nechybí nastavení cesty k models v bootscript souboru.


  30. Mch81 18.03.09 12:15

    Comment Arrow

    Diky moc, skvela prace, vse funguje jak ma, pro vsechny kterym se zobrazuje chyba, tak maji bud spatne nastaveny apache, nebo neco spatne opsali (zkopirovali) :) jelikoz tohle je muj uplne prvni programek, tak jsem si troufl na male zmeny a jede to. Nyni uz chapu vice souvislosti v ZF in action. Jeste jednou diky


  31. AT 26.06.09 16:12

    Comment Arrow

    Problem s nacitanim triedy Albums som vyriesil takto:

    function indexAction() {

    Zend_Loader::loadClass(„Albums“);

    $this->view->title = „My Albums“;

    $albums = new Albums();

    $this->view->albums = $albums->fetchAll();
    }


  32. AT 03.07.09 16:49

    Comment Arrow

    Takze som prisiel na pohodlnejsi sposob, cize nechat toto tak ako je (bez inicializacie triedy Albums):

    function indexAction()
    {
    $this->view->title = „My Albums“;
    $albums = new Albums();
    $this->view->albums = $albums->fetchAll();
    }

    a v bootstrape(?), v mojom pripade index.php:

    require_once „Zend/Loader/Autoloader.php“;
    $autoloader = Zend_Loader_Autoloader::getInstance();

    //If you need generic autoloading ability, for instance because your models directory is on your include path and you don't namespace your model classes, then add this:

    $autoloader->setFallbackAutoloader(true);

    //You should also add:
    $autoloader->suppressNotFoundWarnings(false);

    (zdroj: http://akrabat.com/…ramework-18/ )


  33. AT 03.07.09 16:54

    Comment Arrow

    Takze som prisiel na pohodlnejsi sposob, cize nechat toto tak ako je (bez inicializacie triedy Albums):

    function indexAction()
    {
    $this->view->title = „My Albums“;
    $albums = new Albums();
    $this->view->albums = $albums->fetchAll();
    }

    a v mojom index.php:

    require_once „Zend/Loader/Au toloader.php“;
    $autoloader = Zend_Loader_Au toloader::getIn stance();

    //If you need generic autoloading ability, for instance because your models directory is on your include path and you don't namespace your model classes, then add this:

    $autoloader->setFallbackAu toloader(true);

    //You should also add:
    $autoloader->suppressNotFou ndWarnings(fal se);

    (zdroj: http://akrabat .com/…ramework-18/ )


  34. AT 03.07.09 16:55

    Comment Arrow

    sarka, nevsimol som si ze si nemozem zmazat stary prispevok, ak je mozne, nech admin zmaze: AT [03.07.09 16:49].
    A opravi prilozeny link, ach jo…
    Dik.


  35. Mr.Carrot42 22.10.09 17:40

    Comment Arrow

    Palm Profile, and introduces some basic gestures. ,


  36. kar 02.12.09 21:22

    Comment Arrow

    Nevím v čem je problém ale mě se v tomto článku nezobrazuje vetšina zdrojových kódů (vždy pouze slovo code).


  37. korny 06.12.09 22:19

    Comment Arrow

    no me taky ne…zmeniloo se URL..mozna to ma souvislost


  38. fisting 06.12.09 22:21

    Comment Arrow

    no ano..
    tenhle odkaz z zendframework.cz taky nefunguje
    http://weblog.pari.cz/…nd-framework


  39. Bluster 31.12.09 13:11

    Comment Arrow

    Neví někdo, kde by se dal najít podobný tutoriál, ale i s kodem? Tento by mi vyřešil vetsinu problemu, jen ten kod tu chyby…


  40. Dave 17.01.10 18:16

    Comment Arrow

    To je sice hezke, ale nevim proc tady misto kodu vidim tag a nic vic. Takto si to podle toho navodu nemuzu vytvorit ani vyzkouset jak bych chtel.


  41. Pari 22.02.10 21:23

    Comment Arrow

    Tak jsem vám to opravil, komentáře neodebírám automaticky, takže proto jsem o tom dlouho nevěděl. Omlouvám se


Přidej vlastní názor

  • Author Avatar

    Ty


Comment Arrow




O autorovi

Petr Parimucha

Vítejte na mém blogu, rád bych se v krátkosti představil. Je mi 26 let. Momentálně nejvíce času věnuji projektu Lepime.cz - obchod se samolepkami na zeď a tvorbě webů postavených na redakčním systému Drupal pod značkou MEPA.CZ.