Sunday, May 24, 2009

CakePHP: jak upéct PHP aplikaci snadno a rychle

Už od ledna tohoto roku si hraji s PHP frameworkem CakePHP. Kvalitních PHP frameworků je několik, já jsem hledal něco rozšířeného a s minimální dobou nutnou k pochopení. Byl jsem frameworkem příjemně překvapen a už mám za sebou dvě PHP aplikace v tomto frameworku. V tomto článku popíšu ty nejlepší featury Caku a uvidíte, že to je piece of cake.

CakePHP je hodně podobný frameworku Ruby On Rails (ROR). Částečně z něho vychází, ale není to úplná předělávka, protože jazyk PHP má svoje specifika stejně jako jazyk Ruby. Základní principy jsou ale stejné. Především to, že framework má konvence pro pojmenovávání všeho - tříd, tabulek v databázi, sloupců v databázi, proměnných atd. Důležité je ale říct, že vývojář nemusí tyto konvence dodržovat. Když je ale dodržuje, ušetří si tím spoustu práce. Když je všechno pojmenované tak jak má, nastoupí spousta užitečných vlastností, které sami autoři v dokumentaci označují jako "magie". Většina podobných frameworků je založena na návrhovém vzoru Model-View-Controller, stejně tak Cake. Cake poměrně dost vývojáře nutí MVC používat, což je jedině dobře. Dřív jsem si to psal sám a ač jsem se o MVC snažil, mnohdy jsem ulítnul někam jinam. Výhoda těchto konvencí je jasná - kód je pak přehledný a snadno pochopitelný pro jiného vývojáře. Framework tak odstraňuje vlastnost PHP, kdy je jednu věc možno "naprasit" spoustu způsoby a kód je pak velmi nepřehledný. Abych to shrnul - Cake přebírá hlavní výhody Ruby On Rails, ale je to PHP (něco co znáte) a také odpadají problémy s hostingem.

Když jsem s Cakem začínal, překvapila mě podrobná dokumentace CookBook (kuchařka). Není to strohá referenční příručka ale ani spousta zbytečného textu ala Microsoft Help. Je to pěkně stručně psané a u všeho jsou příklady, které lze hned kopírovat a použít. Celá příručka je dobře hiearchicky rozdělená a dobře se čte. Navíc framework má za sebou hodně silnou komunitu. Na serveru Bakery je spousta článků které popisují konkrétní příklady a problémy z praxe a jak je vyřešit v Caku. Takových serverů je víc: Když jsem něco nechápal, vždy se stačilo zeptat Googlu.

Jak začít? Byl jsem až překvapen jak to je jednoduché. Stáhnete si distribuci, zdrojáky nakopírujete na localhost. Spustíte program do příkazové řádky, který se jmenuje "cake". Nebojte nemusíte si pamatovat žádné příkazy, program se na všechno ptá a vy jenom odpovídáte. Nastavíte přístup k databázi, název a cestu k vašemu projektu a cake vygeneruje potřebné adresáře a soubory. Cake podporuje snad všechny myslitelné databáze, má nad databází objektovou abstrakci, takže změna databáze znamená pouze přepsání jednoho slova v konfiguraci. Máte už v databázi nějaké tabulky? Super, tak pro ně uděláme web. Cake stejně jako ROR podporuje metodu zvanou scaffolding. Stačí pro každou tabulku vytvořit controller a model a tadá, máte vygenerovaný kompletní CRUD (create read update delete) nad tabulkou. A to včetně stránkování a pěkného defaultního vzhledu. Jak vytvořit controller a model? Předpokládejme že vaše tabulka se jmenuje users. V adresáři controllers/ vytvořte soubor users_controller.php s obsahem:

<?php

class UsersController extends AppController {

var $scaffold;

}
?>

a v adresáři models/ vytvořte soubor User.php s obsahem:

<?php

class User extends AppModel {
}
?>

Nyní v prohlížeči zadejte http://localhost/users a budete koukat. Alespoň já jsem koukal jako puk. To, co mi vždy trvalo spoustu hodin a hrozně mě nebavilo tady už je hotové. A pokud jste udělali něco špatně, například špatně nastavili přístup k databázi, Cake vás nenechá na holičkách. Vypíše pěknou a přesnou chybovou hlášku, kde je napsáno v jakém souboru na jaké řádce máte co upravit. A jak vidíte z URL, Cake se také stará o pěkné adresy pomocí mod_rewrite. Pěkné, nemyslíte?

Scaffolding je ale pouze tak na ukázku. Vy potřebujete mít plnou kontrolu nad view, modely a controllery abyste mohli napsat plnohodnotnou PHP aplikaci. V jiných frameworcích musíte všechno psát od nuly, v Caku ne. Opět nastupuje skvělý program pro příkazovou řádku "cake". Na příkazové řádce se přesuňte do adresáře vašeho projektu. Poté zadejte příkaz "cake bake" (upéct koláč:D). A můžete vyrábět modely, controllery a view jak na běžícím páse. Program se vás ptá na podrobnosti a vy odpovídáte. Nejdřív je dobré upéct modely. Zde se vás program zeptá na vztahy mezi modely (tabulkami). Cake podporuje základní vztahy belongsTo (N:1), hasMany(1:N), hasOne (1:1) a hasAndBelongsToMany (N:N). To určitě nadefinujte u všech tabulek, později to ušetří hodně práce. U modelů se vás program ještě zeptá na omezení pro jednotlivá data - např. minimální a maximální počet znaků, ale jsou i složitější vzory jako "email", "číslo kreditní karty" atd. Vytvoření modelů proto trvá déle, ale controllery a view máte během chvilky. Pak zadejte do prohlížeče http://localhost a budete koukat podruhé. Máte hotový web nad celou databází, včetně CRUDu všeho. A to včetně vztahů mezi tabulkami! Tzn. Ve formuláři pro vytváření knihy bude rovnou <select> pro vybrání ke kterému autorovi patří. A když si prohlížíte autora rovnou uvidíte seznam souvisejících knih! Zkuste si zadat něco špatně do formuláře - jé ona funguje validace formulářů podle těch kritérií co jste zadali při tvorbě modelu! A koukněte do kódu. Je to všechno přehledné a připravené k úpravě. Tenhle způsob mi hrozně vyhovuje - nemám prázdný projekt kde musím studovat dokumentaci jak se to dělá a podle toho něco tvořit - tady už mám základ hotový a jenom upravuji pěkný přehledný kód a tím se rovnou učím "jak to dělat".

A to jsem možnosti Caku jenom nakousl. Obsahuje další samozřejmé věci - např. správu layoutů, můžete definovat layouty pro různá zobrazení. Správu přihlášení pomocí komponenty Auth - pokud máte databázi správně pojmenovanou (tabulka users, pole username a password), nemusíte ani nic nastavovat, stačí v controlleru definovat metody login() a logout(), vytvořit view pro logovací stránku a tadá, máte přihlašování a odhlašování. Nebo podpora lokalizace, když všechny texty opouzdříte funkcí __ (dvě podtržítka), jste připraveni na lokalizaci webu. Funkce funguje tak, že když najde jazykový ekvivalent, použije ho a když ne, vypíše to, co jste funkci zadali.

Líbí se mi také různí pomocníci, tzv. Helpery. Třeba HtmlHelper generuje pěkné a validní XHTML. Třeba zadáte příkaz $html->image('cake.png') a ono to vytvoří validní HTML obrázek s tím, že se nemusíte starat o URL obrázku i poté, co z localhostu přejdete na na nějaký hosting. Nebo FormHelper je úžasný. Formulář v Caku napíšete asi takhle:

echo $form->create('Building');

echo $form->input('name');

echo $form->input('address');

echo $form->input('public');

echo $form->input('accessible_from');

echo $form->input('company_id');

echo $form->end('Submit');

Tento kód vygeneruje validní XHTML formulář a políčka přizpůsobí typům z tabulky buildings. "name" je string, takže to bude běžný <input type="text" />. "public" je boolean takže to bude checkbox. "accessible_from" je datum takže to bude kalendářík. "company_id" je cizí klíč takže to bude <select> z výběrem existujících companies. Nutno říct že i texty jako nadpisy formulářových políček nebo texty chybových hlášek se inteligentně vygenerují podle databáze. Jak tento formulář vypadá můžete vidět zde.

A poslední věc kterou musím zmínit - jak v Caku získáváte data z databáze? Zapomeňte na SQL, to je moc složité :-) Řekněme, že chceme získat autora který má příjmení Herbert a všechny jeho knihy. V controlleru AuthorsController ve funkci view() napíšeme pouze tento příkaz:

$this->set('author',$this->Author->findBySurname("Herbert"));

Tato funkce vytvoří ve view proměnnou $author obsahující pole dat, které potřebujeme. Funkci findBySurname jsme nikde nedefinovali, máme jenom v databázi tabulku authors a sloupec surname. Cake poskládá SQL dotaz a to včetně všech joinů. Vše vrátí jako přehledné pole.

V souboru views/authors/view.ctp (view pro detail autora) pak už jenom vypíšeme pole foreachem:

echo $author['Author']['firstname'];
echo $author['Author']['surname'].'<br />';
foreach ($author['Book'] as $book)
{
echo '<b>'.$book['title'].'</b><br />';
echo $book['anotation'].'<br />';
}

A to jsem pouze nakousnul jenom ty nejvýraznější featury. CakePHP toho umí mnohem víc a jak budete web tvořit, budete je postupně objevovat. Nutno říct, že spousta věcí jde v Caku generovat, ale nemusíte nic z toho používat. Reálné projekty mají často specifika, na které třeba Cake nemyslí. Nevadí, vše je možné rozšířit a napsat po svém. Ale pak samozřejmě budete psát víc kódu. Například já jsem pracoval v projektu s PostGISem, který má vlastní SQL funkce, které Cake nevygeneruje. Vlastní SQL samozřejmě můžu použít, ale musím si potom například psát vlastní validaci.

Chcete vidět CakePHP v praxi? Pomocí něho už jsem vytvořil dva projekty - GPS hru Catch&Run a systém pro evidenci elektrických zásuvek Juice My Laptop. Catch&Run už je plně přizpůsobený web mým potřebám. Juice My Laptop je ještě v začátcích, je to z velké části vygenerované Cakem. Juice My Laptop jsem celkem tvořil asi 3 hodiny. A z toho hodinu jsem tvořil databázi a zadával vztahy mezi tabulkami. Nesrovnávám CakePHP s jinými PHP frameworky, protože s nimi nemám dostatek zkušeností. Ale s Cakem jsem naprosto spokojený.

No a třešnička na závěr - v celém projektu se tvorba webu přirovnává k pečení koláče. Pekařské termíny se prolínají dokumentací. Není nad to se při čtení dokumentace zasmát :-)