Development

Documentation/cs_CZ/book/1.0/02-Exploring-Symfony-s-Code

You must first sign up to be able to contribute.

Kapitola 2 - Zkoumání kódu symfony

Kód pohánějící aplikace postavené na symfony může na první pohled vypadat trochu znepokojivě. Sestává se z mnoha adresářů a skriptů a soubory jsou směsí PHP tříd, HTML a dokonce hybridem obojího. Také můžete vidět odkazy na třídy, které se v adresáři aplikace nevyskytují a hloubka adresářové struktury dosahuje šesti úrovní. Ale jakmile porozumíte důvodům, které se skrývají za vší tou zdánlivou složitostí, najednou ucítíte, že takto je to přirozené a nebudete chtít vyměnit strukturu aplikací v symfony za žádnou jinou. Tato kapitola rozptyluje tyto ustrašené pocity.

Vzor MVC

Symfony je založeno na klasickém webovém návrhovém vzoru, který je znám jako MVC architektura, která se skládá ze tří úrovní:

  • Model představuje informaci podle které aplikace pracuje -- její business logiku.
  • Pohled (view) vykresluje model do webové stránky v závislosti na interakci uživatele.
  • Kontroler (controller) reaguje na akce uživatele a vyvolává vhodné změny modelu nebo pohledu.

Obrázek 2-1 zobrazuje MVC vzor.

Architektura MVC odděluje business logiku (model) a prezentační vrstvu (pohled), výsledkem čehož je větší spravovatelnost. Pokud by například měla vaše aplikace běžet zároveň ve standardních webových prohlížečích a ručních zařízeních a budete potřebovat pouze nový pohled, stávající kontroler a model můžete zachovat. Kontroler umožňuje skrýt detaily protokolu, který je použit pro požadavek (HTTP, konzolový mód, mail, atd.), před modelem a pohledem. A model abstrahuje logiku dat, takže pohled a akce jsou nezávislé, například na použité databázi.

Obrázek 2-1 - MVC vzor

MVC vzor

Rozložení do vrstev MVC

Pojďme se podívat pro lepší porozumění výhodám MVC, jak převést jednoduchou PHP aplikaci na aplikaci s MVC architekturou. Perfektním příkladem bude seznam příspěvků na weblogu.

Špagetový kód

Následuje příklad špagetového kódu v PHP, který zobrazí seznam položek z databáze.

Výpis 2-1 - Špagetový kód

[php]
<?php

// Connecting, selecting database
$link = mysql_connect('localhost', 'myuser', 'mypassword');
mysql_select_db('blog_db', $link);

// Performing SQL query
$result = mysql_query('SELECT date, title FROM post', $link);

?>

<html>
  <head>
    <title>List of Posts</title>
  </head>
  <body>
   <h1>List of Posts</h1>
   <table>
     <tr><th>Date</th><th>Title</th></tr>
<?php
// Printing results in HTML
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
echo "\t<tr>\n";
printf("\t\t<td> %s </td>\n", $row['date']);
printf("\t\t<td> %s </td>\n", $row['title']);
echo "\t</tr>\n";
}
?>
    </table>
  </body>
</html>

<?php

// Closing connection
mysql_close($link);

?>

To se dá rychle napsat, rychle to poběží a je nemožné to spravovat. Toto jsou hlavní problémy s tímto kódem:

  • Není zde žádná kontrola chyb (co když selže spojení s databází?).
  • Kód HTML a PHP je smíchán, dokonce pomíchán navzájem.
  • Kód je svázán s MySQL databází.

Izolace prezentační vrstvy

Příkazy echo a printf volané ve Výpisu 2-1 zhoršují čitelnost kódu. Problémem stávající syntaxe je úprava HTML kódu kvůli rozšíření prezentačních možností. Proto kód rozdělíme do dvou částí. První část, čistý PHP kód s celou business logikou vložíme do skriptu kontroleru, jak je vidět ve Výpisu 2-2.

Výpis 2-2 - Část kontroleru, v index.php

[php]
<?php

 // Connecting, selecting database
 $link = mysql_connect('localhost', 'myuser', 'mypassword');
 mysql_select_db('blog_db', $link);

 // Performing SQL query
 $result = mysql_query('SELECT date, title FROM post', $link);

 // Filling up the array for the view
 $posts = array();
 while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
 {
    $posts[] = $row;
 }

 // Closing connection
 mysql_close($link);

 // Requiring the view
 require('view.php');

 ?>

HTML kód obsahující "šablonovací" PHP syntaxi je uložen ve skriptu pohledu (Výpisu 2-3).

Výpis 2-3 - Část pohledu, ve view.php

[php]
<html>
  <head>
    <title>List of Posts</title>
  </head>
  <body>
    <h1>List of Posts</h1>
    <table>
      <tr><th>Date</th><th>Title</th></tr>
    <?php foreach ($posts as $post): ?>
      <tr>
        <td><?php echo $post['date'] ?></td>
        <td><?php echo $post['title'] ?></td>
      </tr>
    <?php endforeach; ?>
    </table>
  </body>
</html>

Dobré pravidlo pro určení, jestli je pohled dostatečně čistý je, že by měl obsahovat minimální množství PHP kódu, aby byl pochopitelný pro HTML designera, který nemá znalost PHP. Nejběžnější příkazy v pohledu jsou echo, if/endif, foreach/endforeach a to je tak všechno. A také, není zde žádný PHP kód vypisující HTML značky.

Všechna logika je přesunuta do skriptu kontroleru, který obsahuje pouze čistý PHP kód, bez HTML. Skutečně, můžete si představit, že ten samý kontroler by mohl být znovu použit pro úplně jinou prezentaci, třeba v PDF souboru nebo XML strukturu.

Izolování manipulace s daty

Většina skriptu kontroleru je určena pro manipulaci s daty. Ale co když budeme potřebovat seznam příspěvků pro jiný kontroler, řekněme že by to mohl být výstup pro RSS kanál weblogových příspěvků? Co když chceme mít všechny databázové dotazy na jednom místě, abychom se vyhnuli duplikování kódu? Co když se rozhodneme změnit datový model, například tabulku post přejmenujeme na weblog_post? Co když budeme chtít místo MySQL použít PostgreSQL? Aby bylo toto všechno umožněno, budeme potřebovat vyjmout kód pro manipulaci s daty z kontroleru a vložit ho do jiného skriptu nazvaného model (Výpis 2-4).

Výpis 2-4 - Část modelu, v model.php

[php]
<?php

function getAllPosts()
{
  // Connecting, selecting database
  $link = mysql_connect('localhost', 'myuser', 'mypassword');
  mysql_select_db('blog_db', $link);

  // Performing SQL query
  $result = mysql_query('SELECT date, title FROM post', $link);

  // Filling up the array
  $posts = array();
  while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
  {
     $posts[] = $row;
  }

  // Closing connection
  mysql_close($link);

  return $posts;
}

?>

Upravený kontroler je zobrazen ve Výpisu 2-5.

Výpis 2-5 - Část kontroleru, upraveno, v index.php

[php]
<?php

// Requiring the model
require_once('model.php');

// Retrieving the list of posts
$posts = getAllPosts();

// Requiring the view
require('view.php');

?>

Kontroler je nyní čitelnější. Jeho jediným úkolem je získat data z modelu a předat je pohledu. V komplexnějších aplikacích má kontroler na starost také požadavky, uživatelské sezení, autentifikaci apod. Při použití popisných názvů funkcí v modelu není potřeba psát komentáře v kontroleru.

Skript modelu se zabývá datovým přístupem a může být podle toho uspořádán. Všechny parametry, které nezávisí na datové vrstvě (jako parametry požadavku) musí být uvedeny v kontroleru a nesmí být přímo přístupné z modelu. Funkce modelu mohou být snadno znovu použity jiným kontrolerem.

Rozdělení vrstev MVC

Principem MVC architektury je rozdělit kód podle jeho přirozenosti do tří vrstev. Kód datové logiky je vložen do modelu, prezentace do pohledu a aplikační logika do kontroleru.

Další přídavné návrhové vzory mohou kódování ještě více usnadnit. Model, pohled a kontroler mohou být ještě dále členěny.

Databázová abstrakce

Vrstva modelu může být rozdělena na vrstvu pro přístup k datům a vrstvu databázové abstrakce. Funkce pro přístup k datům nebudou u tohoto způsobu rozdělení používat příkazy, které jsou závislé na konkrétní databázi, ale budou volat funkce, které budou provádět samotné dotazy. Pokud později změníte váš databázový systém, bude potřeba aktualizovat pouze vrstvu databázové abstrakce.

Příklad vrstvy pro přístup k datům, která je specifická pro MySQL je ukázána ve Výpisu 2-6. Ve Výpisu 2-7 následuje ukázka vrstvy databázové abstrakce.

Výpis 2-6 - Databázově abstraktní část modelu

[php]
<?php

function open_connection($host, $user, $password)
{
  return mysql_connect($host, $user, $password);
}

function close_connection($link)
{
  mysql_close($link);
}

function query_database($query, $database, $link)
{
  mysql_select_db($database, $link);

  return mysql_query($query, $link);
}

function fetch_results($result)
{
  return mysql_fetch_array($result, MYSQL_ASSOC);
}

Výpis 2-7 - Část modulu pro přístup k datům

[php]
function getAllPosts()
{
  // Connecting to database
  $link = open_connection('localhost', 'myuser', 'mypassword');

  // Performing SQL query
  $result = query_database('SELECT date, title FROM post', 'blog_db', $link);

  // Filling up the array
  $posts = array();
  while ($row = fetch_results($result))
  {
     $posts[] = $row;
  }

  // Closing connection
  close_connection($link);

  return $posts;
}

?>

Můžete zkontrolovat, že ve vrstvě pro přístup k datům se nenachází žádná funkce, která by byla závislá na konkrétní databázi. Navíc funkce, které byly vytvořeny ve vrstvě databázové abstrakce mohou být znovu použity v mnoha jiných funkcích modelu, které budou potřebovat přistupovat do databáze.

NOTE Příklady ve Výpisech 2-6 a 2-7 ještě nejsou dostatečně uspokojivé a pořád zbývá udělat nějako práci, aby jsme dosáhli plné databázové abstrakce (abstrahovat SQL kód do databázově nezávislého sestavovatele, přesunout všechny funkce do třídy, atd.). Ale smyslem této knihy není naučit vás jak psát kód ručně. V Kapitole 8 uvidíte, že symfony umí velmi dobře udělat veškerou abstrakci.

Části pohledu

Vrstva pohledu může také mít přínos z rozdělení kódu. Webová stránka často obsahuje shodné prvky v celé aplikaci: hlavičky stránek, grafické rozložení, patička a globální navigaci. Mění se pouze vnitřní části stránek. To je důvod, proč je pohled rozdělen na rozložení a šablonu. Rozložení je obvykle globální pro celou aplikaci, nebo skupiny stránek. Šablona pouze dává tvar proměnným, které byly poskytnuty kontrolerem. Pro spolupráci těchto komponent bude potřeba nějaká logika, vrstvě této logiky pohledu zůstane název pohled. Podle těchto principů rozdělíme část pohledu z Výpisu 2-3 do třech oddělených částí (Výpisy 2-8, 2-9 a 2-10).

Výpis 2-8 - Část pohledu s šablonou, v mytemplate.php

[php]
<h1>List of Posts</h1>
<table>
<tr><th>Date</th><th>Title</th></tr>
<?php foreach ($posts as $post): ?>
  <tr>
    <td><?php echo $post['date'] ?></td>
    <td><?php echo $post['title'] ?></td>
  </tr>
<?php endforeach; ?>
</table>

Výpis 2-9 - Část logiky pohledu

[php]
<?php

$title = 'List of Posts';
$content = include('mytemplate.php');

?>

Výpis 2-10 - Část pohledu s rozložením

[php]
<html>
  <head>
    <title><?php echo $title ?></title>
  </head>
  <body>
    <?php echo $content ?>
  </body>
</html>

Akce a front kontroler

V předešlém příkladu nemá kontroler mnoho práce, ale v opravdové webové aplikaci je kontroler velmi vytížený. Podstatná část této práce je společná všem kontrolerům v aplikaci. Obecné úlohy zahrnují zpracování požadavků, ošetření bezpečnosti, nahrávání konfigurace aplikace a podobné úkoly. To je důvod, proč je kontroler často rozdělen na front kontroler, který je unikátní pro celou aplikaci a akce, které obsahují kód specifický pouze pro jednu danou stránku.

Jednou z velkých výhod front kontroleru je, že nabízí jedinečný vstupní bod pro celou aplikaci. Pokud se někdy v budoucnosti rozhodnete uzavřít přístup do aplikace, stačí pouze upravit skript front kontroleru. V aplikaci, která nemá front kontroler, by musel být upraven každý jednotlivý kontroler.

Objektová orientace

Všechny předcházející příklady používali procedurální programování. OOP vlastnosti moderních jazyků velmi usnadňují programování - objekt může zapouzdřit logiku, zdědit ji od jiného objektu a poskytuje jasnou konvenci pojmenování.

Implementace MVC architektury v jazyku, který není objektově orientovaný, přináší problémy se jmennými prostory a duplikací kódu a celkově je kód obtížně čitelný.

Objektová orientace umožňuje vývojáři pracovat s takovými věcmi jako je objekt pohledu, objekt kontroleru, třídy modelu a transformovat všechny funkce v předešlých příkladech do metod. To je nutná podmínka MVC architektur.

TIP

Pokud se chcete dozvědět víc o návrhových vzorech pro webové aplikace v objektově orientovaném kontextu, přečtěte si Patterns of Enterprise Application Architecture by Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0). Ukázky kódu ve Fowlerově knize jsou napsány v Javě nebo C#, ale jsou bez problémů čitelné pro PHP vývojáře.

Implementace MVC v symfony

Na chvíli se zastavme. Kolik komponent je potřeba pro jednu stránku s výpisem příspěvků weblogu? Jak je vidět na Obrázku 2-2, máme následující části:

  • Vrstva modelu
    • Databázová abstrakce
    • Přístup k datům
  • Vrstva pohledu
    • Pohled
    • Šablona
    • Rozložení
  • Vrstva kontroleru
    • Front kontroler
    • Akce

Sedm skriptů -- to je hodně souborů, které je potřeba otevřít a změnit pokaždé, když vytváříte novou stránku! Nicméně, symfony dělá věci jednoduše. Ačkoliv si symfony bere to nejlepší z MVC architektury, jsou tyto principy implementovány tak, aby vývoj aplikací byl rychlý a bezbolestný.

Především, kontroler a rozložení jsou společné pro všechny akce v aplikaci. Můžete mít mnoho kontrolerů a rozložení, ale budete potřebovat pouze jeden od každého. Front kontroler je čistá MVC logická komponenta a vy ji nikdy nebudete muset psát, protože symfony ji vygeneruje za vás.

Další dobrou zprávou je, že třídy z vrstvy modelu jsou také generovány automaticky podle vaší datové struktury. Toto je úkol knihovny Propel, která poskytuje kostru tříd a generuje kód. Pokud Propel nalezne integritní omezení cizím klíčem nebo datová pole, zpracovává je pomocí speciálních přídavných a transformačních metod. A databázová abstrakce je pro vás úplně neviditelná, protože spolupracuje s další komponentou, zvanou Creole. Takže pokud se najednou rozhodnete změnit databázi, nemusíte přepisovat ani jedinou řádku kódu. Pouze změníte jeden konfigurační parametr.

A poslední věc, logika pohledu může být jednoduše přeložena jako jednoduchý konfigurační soubor, není potřeba žádné programování.

Obrázek 2-2 - Symfony workflow

Symfony workflow

To znamená, že výše popsaný seznam příspěvků bude v symfony potřeba zpracovat pouze tři soubory (Výpisy 2-11, 2-12 a 2-13).

Výpis 2-11 - Akce list v myproject/apps/myapp/modules/weblog/actions/actions.class.php

[php]
<?php
class weblogActions extends sfActions
{
  public function executeList()
  {
    $this->posts = PostPeer::doSelect(new Criteria());
  }
}

?>

Výpis 2-12 - Šablona list, v myproject/apps/myapp/modules/weblog/templates/listSuccess.php

[php]
<h1>List of Posts</h1>
<table>
<tr><th>Date</th><th>Title</th></tr>
<?php foreach ($posts as $post): ?>
  <tr>
    <td><?php echo $post->getDate() ?></td>
    <td><?php echo $post->getTitle() ?></td>
  </tr>
<?php endforeach; ?>
</table>

Výpis 2-13 - Pohled list, v myproject/apps/myapp/modules/weblog/config/view.yml

listSuccess:
  metas: { title: List of Posts }

Navíc budeme ještě potřebovat definovat rozložení (Výpis 2-14), které ale může být mnohokrát znovu použito.

Výpis 2-14 - Rozložení, v myproject/apps/myapp/templates/layout.php

[php]
<html>
  <head>
    <?php echo include_title() ?>
  </head>
  <body>
    <?php echo $sf_data->getRaw('sf_content') ?>
  </body>
</html>

A to je opravdu všechno, co potřebujete. Toto je kód, který je potřeba pro zobrazení naprosto stejné stránky, jako produkuje dříve ukázaný špagetový kód ve Výpisu 2-1. Zbytek (to, že spolu všechny komponenty spolupracují) už je ošetřeno v symfony. Když spočítáte řádky, uvidíte, že vytvořit seznam příspěvků v MVC architektuře pomocí symfony nevyžaduje víc času nebo kódování, než napsání souboru se špagetovým kódem. Nicméně vám dává velkou výhodu, zejména čistou organizaci kódu, znovupoužitelnost, přizpůsobivost a taky je to zábavnější. A jako bonus získáte standardu odpovídající XHTML, možnost debugování, snadnou konfiguraci, databázovou abstrakci, elegantní URL směrování, četná prostředí a mnoho dalších vývojových nástrojů.

Třídy jádra symfony

Implementace MVC v symfony používá několik tříd, které budete v této knize potkávat docela často:

  • sfController je třída kontroleru. Dekóduje požadavky a předává je akcím.
  • sfRequest uchovává všechny prvky požadavku (parametry, cookies, hlavičky, atd.).
  • sfResponse obsahuje hlavičky a obsahy odpovědi. Je to objekt, který bude eventuálně transformován do HTML odpovědi a poslán uživateli.
  • Kontextový jedináček (singleton) (získaný pomocí sfContext::getInstance()) uchovává vazby na všechny objekty jádra a aktuální konfiguraci; je dostupný odevšad.

O těchto objektech se dozvíte víc v Kapitole 6.

Jak je vidět, všechny symfony třídy používají předponu sf, stejně jako proměnné jádra symfony v šablonách. Třídy jádra frameworku jsou tak snadno rozpoznatelné a také to umožńuje vyhnout se kolizím názvů ve vašich vlastních třídách a proměnných.

NOTE V symfony je použito několik kódovacích standardů, z nichž pro názvy tříd a proměnných je použit UpperCamelCase standard. Existují ale dvě výjimky: třídy jádra symfony začínají sf, tedy malým písmenem a proměnné nacházející se v šablonách používají syntaxi s podtržítkovým oddělovačem.

Organizace kódu

Teď, když znáte různé komponenty, ze kterých se skládá symfony aplikace, budete se asi podivovat jejich organizaci. Symfony organizuje kód do projektové struktury a zařazuje jednotlivé soubory projektu do standardní stromové struktury.

Struktura projektu: aplikace, moduly a akce

Projekt v symfony je množina služeb a operací, které jsou dostupné pod daným doménovým názvem a sdílejí stejný objektový model.

Uvnitř projektu jsou operace logicky seskupeny do aplikací. Aplikace může běžet nezávisle na ostatních aplikacích téhož projektu. Ve většině případů obsahuje projekt dvě aplikace: jednu pro frontend a jednu pro backend, přičemž obě sdílejí stejnou databázi. Ale také můžete mít projekt, který obsahuje spoustu dílčích stránek/sídel, z nichž každá je jinou, samostatnou aplikací. Je potřeba mít na paměti, že odkazy mezi aplikacemi musí být zapsány v absolutní podobě.

Každá aplikace je množinou jednoho nebo více modulů. Modul obvykle představuje stránku, nebo skupinu stránek s podobným účelem. Například můžete mít moduly home, articles, help, shoppingCart, account, atd.

Moduly mají k dispozici akce, které představují různé činnosti, které mohou být s modulem prováděny. Například modul shoppingCart může mít akce add, show a update. Všeobecně, akce může být popsána slovesem. Práce s akcemi je téměř stejná jako práce se stránkami v klasické webové aplikaci, ačkoliv dvě akce mohou ve výsledku vytvořit stejnou stránku (například přidání komentáře k nějakému příspěvku ve weblogu může znovu zobrazit příspěvek s novým komentářem).

TIP Pokud toto představuje pro začínající projekt příliš mnoho úrovní, je velice jednoduché seskupit všechny akce do jednoho modulu, takže struktura souborů může být jednoduchá. Když se aplikace stane komplexnější, je vhodné rozdělit akce do samostatných modulů. Jak bylo zmíněno v Kapitole 1, přepisování kódu pro zlepšení jeho struktury nebo čitelnosti (ale zachovávající jeho chování) se nazývá refaktoring, který lze uplatňovat často, pokud jsou dodržovány principy RAD.

Obrázek 2-3 zobrazuje ukázku organizace kódu pro projekt weblogu ve struktuře projekt/aplikace/modul/akce. Ale uvědomte si, že aktuální stromová struktura souborů projektu se bude lišit od uspořádání na obrázku.

Obrázek 2-3 - Příklad organizace kódu

Příklad organizace kódu

Stromová struktura souborů

Všechny webové projekty většinou sdílejí podobný typ obsahu, což může být:

  • Databáze, třeba MySQL nebo PostgreSQL
  • Statické soubory (HTML, obrázky, JavaScriptové soubory, stylopisy, atd.)
  • Soubory uploadované na sídlo uživateli a administrátory
  • PHP třídy a knihovny
  • Cizí knihovny (skripty třetích stran)
  • Dávkové soubory (skripty spouštěné z příkazové řádky nebo pomocí cron tabulky)
  • Logovací soubory (záznamy zapsané aplikací a/nebo serverem)
  • Konfigurační soubory

Symfony poskytuje standardní stromovou strukturu pro logickou organizaci tohoto obsahu, která je konzistentní s požadavky na architekturu (MVC vzor a seskupování projekt/aplikace/modul). Tato stromová struktura je automaticky vytvořena při inicializaci každého projektu, aplikace nebo modulu. Můžete si ji samozřejmě kompletně upravit, reorganizovat soubory a adresáře podle vašich potřeb nebo ji přizpůsobit požadavkům vašeho zákazníka.

Kořenová stromová struktura

Toto jsou adresáře, které se nacházejí v kořeni symfony projektu:

apps/
  frontend/
  backend/
batch/
cache/
config/
data/
  sql/
doc/
lib/
  model/
log/
plugins/
test/
  unit/
  functional/
web/
  css/
  images/
  js/
  uploads/

Tabulka 2-1 popisuje obsah těchto adresářů.

Tabulka 2-1 - Kořenové adresáře

Adresář | Popis ---------- | ------------ apps/ | Obsahuje jeden adresář pro každou aplikaci projektu (typicky frontend a backend pro správu frontendu a backendu). batch/ | Obsahuje PHP skripty volané z příkazové řádky nebo plánovačem, které spouští dávkové procesy. cache/ | Obsahuje cache verzi konfigurace a (pokud ji aktivujete) cache verzi akcí a šablon projektu. Cacheovací mechanizmus (detailně popsaný v Kapitole 12) používá tyto soubory pro urychlení odpovědi na webové požadavky. Každá aplikace zde bude mít vlastní podadresář obsahující preprocesované PHP a HTML soubory. config/ | Udržuje všeobecnou konfiguraci projektu. data/ | Zde můžete uchovávat datové soubory projektu, jako schéma databáze, SQL skript pro vytvoření tabulek, nebo dokonce i databázový soubor SQLite. doc/ | Uchovává dokumentaci projektu, která zahrnuje vaše vlastní dokumenty a dokumentaci generovanou pomocí PHPdoc. lib/ | Určený pro cizí třídy nebo knihovny. Sem můžete přidat kód, který je potřeba sdílet mezi vašemi aplikacemi. Podadresář model/ uchovává objektový model projektu (popsaný v Kapitole 8). log/ | Uchovává příslušné logovací soubory generované přímo symfony. Může také obsahovat logovací soubory webového serveru, databáze, nebo nějaké jiné části projektu. Symfony vytváří jeden logovací soubor pro každou aplikaci a pro každé prostředí (logovací soubory jsou probírány v Kapitole 16). plugins/ | Uchovává plug-iny instalované do aplikace (plug-iny jsou probírány v Kapitole 17). test/ | Obsahuje jednotkové a funkcionální testy napsané v PHP a kompatibilní s testovacím frameworkem symfony (probíráno v Kapitole 15). Symfony automaticky přidává během nastavování projektu určité kontrolní části s několika základnímy testy. web/ | Kořenový adresář pro webový server. Jediné soubory, které jsou přístupné z internetu, jsou umístěny v tomto adresáři.

Aplikační stromová struktura

Stromová struktura všech adresářů aplikací je stejná:

apps/
  [název aplikace]/
    config/
    i18n/
    lib/
    modules/
    templates/
      layout.php
      error.php
      error.txt

Tabulka 2-2 popisuje aplikační podadresáře.

Tabulka 2-2 - Aplikační podadresáře

Adresář | Popis ------------ | ----------- config/ | Obsahuje velkou množinu YAML konfiguračních souborů. Je to místo, kde je většina konfigurací aplikace a kde jsou také odděleny od výchozích parametrů samotného frameworku. V případě potřeby ale mohou být tyto výchozí parametry přepsány právě zde. O konfiguraci aplikací se dozvíte více v Kapitole 5. i18n/ | Obsahuje soubory pro internacionalizaci aplikace -- většinou soubory s překladem rozhraní (internacionalizaci se věnuje Kapitola 13). Pokud použijete pro internacionalizaci databázi, můžete tento adresář ignorovat. lib/ | Obsahuje třídy a knihovny, které jsou specifické pro aplikaci. modules/ | Uchovává všechny moduly, které obsahují vlastnosti/schopnosti aplikace. templates/ | Obsahuje všeobecné šablony aplikace -- ty, které jsou sdíleny všemi moduly. Jako výchozí je zde soubor layout.php, který slouží jako hlavní rozložení do něhož jsou vkládány šablony modulů.

NOTE U nové aplikace jsou adresáře i18n/, lib/ a modules/ prázdné.

V rámci projektu nemají třídy aplikace přístup k metodám a atributům jiných aplikací. Je potřeba vědět, že odkaz mezi dvěmi aplikacemi téhož projektu musí být v absolutní podobě. Toto omezení budete muset mít na paměti během inicializace, když se budete rozhodovat, jak rozdělit váš projekt na jednotlivé aplikace.

Modulová stromová struktura

Každá aplikace obsahuje jeden, nebo více modulů. Každý modul má svůj vlastní podadresář v adresáři modules. Jeho jméno se určuje během inicializace.

Toto je typická stromová struktura modulu:

apps/
  [název aplikace]/
    modules/
      [název modulu]/
          actions/
            actions.class.php
          config/
          lib/
          templates/
            indexSuccess.php
          validate/

Tabulka 2-3 popisuje modulové podadresáře.

Tabulka 2-3 - Modulové podadresáře

Adresář | Popis ------------ | ------------ actions/ | Obvykle obsahuje jeden soubor s třídou pojmenovaný actions.class.php, ve kterém můžete uchovávat všechny akce modulu. Můžete také uložit různé akce modulu do samostatných souborů. config/ | Může obsahovat upravené konfigurační soubory s lokálními parametry modulu. lib/ | Uchovává třídy a knihovny specifické pro daný model. templates/ | Obsahuje šablony, které odpovídají akcím modulu. Výchozí šablona, nazvaná indexSuccess.php, je vytvořena během inicializace modulu. validate/ | Je určen pro konfigurační soubory použité pro validaci formulářů (probíráno v Kapitole 10).

NOTE Adresáře config/, lib/ a validate/ jsou u nového modulu prázdné.

Webová stromová struktura

Pro adresář web, který obsahuje veřejně přístupné soubory, existuje několik málo omezení. Pár následujících jmenných konvencí bude poskytovat výchozí chování a užitečné zkratky v šablonách. Příklad adresářové struktury v adresáři web:

web/
  css/
  images/
  js/
  uploads/

Obvykle jsou statické soubory rozděleny do následujících adresářů (Tabulka 2-4).

Tabulka 2-4 - Typické webové podadresáře

Adresář | Popis ---------- | ----------- css/ | Obsahuje stylopisy s příponou .css. images/ | Obsahuje obrázky ve formátu.jpg, .png, nebo .gif. js/ | Obsahuje JavaScriptové soubory s příponou .js. uploads/ | Je určen pro soubory uploadované uživateli. Ačkoliv adresář většinou obsahuje obrázky, je oddělen od adresáře images, takže pokud dojde k synchronizaci vývojového a produkčního serveru, nijak to neovlivní uploadované soubory.

NOTE Ačkoliv je silně doporučeno dodržovat výchozí stromovou strukturu, je možné ji podle potřeb modifikovat, například pokud je potřeba provozovat projekt na serveru s odlišně definovanou stromovou strukturou a kódovacími konvencemi. O úpravě stromové struktury souborů pojednává Kapitola 19.

Společné nástroje

V symfony se opakovaně používá několik technik, které budete v této knize dosti často potkávat a také ve vašich projektech. Tyto zahrnují zásobníky parametrů, konstanty a automatické zavádění tříd.

Zásobníky parametrů

Mnoho tříd v symfony obsahuje zásobník parametrů. Je to vhodný způsob zapouzdření atributů pomocí transparentních getter a setter metod. Třída sfResponse například obsahuje zásobník parametrů, který můžete získat voláním metody getParameterHolder(). Každý zásobník parametrů uchovává data stejným způsobem, který je zobrazen ve Výpisu 2-15.

Výpis 2-15 - Použití zásobníku parametrů sfResponse

[php]
$response->getParameterHolder()->set('foo', 'bar');
echo $response->getParameterHolder()->get('foo');
 => 'bar'

Většina tříd používajících zásobník parametrů poskytuje proxy metody, které zkracují kód potřebný pro get/set operace. To je i případ objektu sfResonse, takže toho samého jako ve Výpisu 2-15 dosáhnete s kódem ve Výpisu 2-16.

Výpis 2-16 - Použití proxy metody zásobníku parametrů sfResponse

[php]
$response->setParameter('foo', 'bar');
echo $response->getParameter('foo');
 => 'bar'

Getter zásobníku parametrů přijímá druhý argument jako výchozí hodnotu. To dává k dispozici použitelný reverzní mechanizmus, který je mnohem stručnější než možnost s podmínkovým příkazem. Podívejte se na příklad ve Výpisu 2-17.

Výpis 2-17 - Použití atributu výchozí hodnoty u metody getter zásobníku

[php]
// The 'foobar' parameter is not defined, so the getter returns an empty value
echo $response->getParameter('foobar');
 => null

// A default value can be used by putting the getter in a condition
if ($response->hasParameter('foobar'))
{
  echo $response->getParameter('foobar');
}
else
{
  echo 'default';
}
 => default

// But it is much faster to use the second getter argument for that
echo $response->getParameter('foobar', 'default');
 => default

Zásobníky parametrů dokonce podporují jmenné prostory. Pokud specifikujete třetí argument u metod setter a getter, bude použit jako jmenný prostor a parametr bude definován pouze v uvnitř tohoto jmenného prostoru. Příklad je ve Výpisu 2-18.

Výpis 2-18 - Použití jmenného prostoru zásobníku parametrů sfResponse

[php]
$response->setParameter('foo', 'bar1');
$response->setParameter('foo', 'bar2', 'my/name/space');
echo $response->getParameter('foo');
 => 'bar1'
echo $response->getParameter('foo', null, 'my/name/space');
 => 'bar2'

Zásobníky parametrů můžete samozřejmě přidat do svých vlastních tříd a využít tak výhody jejich syntaktických možností. Výpis 2-19 zobrazuje jako definovat třídu se zásobníkem parametrů.

Výpis 2-19 - Přidání zásobníku parametrů do třídy

[php]
class MyClas
{
  protected $parameter_holder = null;

  public function initialize ($parameters = array())
  {
    $this->parameter_holder = new sfParameterHolder();
    $this->parameter_holder->add($parameters);
  }

  public function getParameterHolder()
  {
    return $this->parameter_holder;
  }
}

Konstanty

Překvapivě, v symfony najdete velmi málo konstant. Je to z toho důvodu, protože konstanty v PHP mají jeden veliký nedostatek: nemůžete, poté co byly definovány, změnit jejich hodnotu. Proto symfony používá vlastní konfigurační objekt nazvaný sfConfig, který konstanty nahrazuje. Poskytuje statické metody pro přístup k parametrům, které jsou přístupné odkudkoli. Výpis 2-20 demonstruje použití třídních metod sfConfig.

Výpis 2-20 - Použití třídních metod sfConfig namísto konstant

[php]
// Instead of PHP constants,
define('SF_FOO', 'bar');
echo SF_FOO;
// Symfony uses the sfConfig object
sfConfig::set('sf_foo', 'bar');
echo sfConfig::get('sf_foo');

Metody sfConfig podporují výchozí hodnoty a metodu sfConfig::set() lze volat vícekrát se stejným parametrem pro změnu jeho hodnoty. Metody `sfConfig' jsou detailněji probírány v Kapitole 5.

Automatické nahrávání tříd

Obecně, pokud v PHP použijete metodu třídy, nebo vytvoříte objekt, je nejprve potřeba inkludovat definici třídy.

[php]
include 'classes/MyClass.php';
$myObject = new MyClass();

U velkých projektů s mnoha třídami a hlubokou adresářovou strukturou, ale zabírá sledování všech souborů s třídami a cest k nim mnoho času. Symfony poskytuje funkci spl_autoload_register(), díky které není potřeba příkazy include používat a lze psát přímo:

[php]
$myObject = new MyClass();

Symfony se potom podívá po definici MyClass ve všech souborech s příponou php v jednom z lib/ adresářů projektu. Pokud je definice třídy nalezena, bude automaticky inkludována.

Takže pokud uchováváte své třídy v lib/ adresářích, nepotřebujete třídy inkludovat. To je důvod, proč symfony projekty obvykle neobsahují žádné příkazy include nebo require.

NOTE Pro zlepšení výkonu, symfony skenuje během prvního požadavku seznam adresářů (definovaný v interním konfiguračním souboru). Přitom zaregistruje všechny třídy, které tyto adresáře obsahují a uloží tyto údaje do PHP souboru jako asociativní pole. Proto není potřeba při dalších požadavcích znovu skenovat adresáře. A je to také důvod, proč je pokaždé, když je v projektu přidán nebo přesunut soubor se třídou, potřeba vyčistit cache příkazem symfony clear-cache (s výjimkou vývojového prostředí). Více o cache se můžete dozvědět v Kapitole 12 a o konfiguraci automatického nahrávání v Kapitole 19.

Shrnutí

Používání MVC frameworku vás nutí rozdělit a organizovat kód podle konvencí frameworku. Prezentační kód patří do pohledu, kód pro manipulaci s daty patří do modelu a na požadavku závislá manipulační logika patří do kontroleru. Z těchto důvodů je aplikace MVC frameworku zároveň velice užitečná a zároveň dosti omezující.

Symfony je MVC framework napsaný v PHP 5. Jeho struktura je navržena, aby bylo použito to nejlepší z MVC vzoru, ale zároveň aby bylo jednoduché na použití. Díky jeho univerzálnosti a konfigurovatelnosti je symfony vhodné pro všechny projekty webových aplikací.

Nyní byste měli rozumět základní teorii, na níž je symfony postaveno, takže jste téměř připraveni na vývoj své první aplikace. Ale ještě předtím budete potřebovat symfony nainstalovat a rozběhnout vývojový server.