Mar 31 2008

Zend Framework: Routování subdomén

Tag: PHP,SEO,Zend FrameworkJens @ 00:00

Routování v Zend Frameworku (ZF) není nic zvláště složitého. Stačí pouze lehce nahlédnout do dokumentance a začít používat defaultní routovaní případně si nastavit nějaká jiná vlastní pravidla.

Problém ale nastává v případě, že chcete do routování zahrnout subdomény. Na to ZF není přímo (zatím? — v době psaní tohoto článku je stable verze 1.5) vybaven a je tedy třeba použít kousek „vlastního kódu“.

Výchozí routovaní ZF

Předpokládejme že prezentace bude umístěna na domena.cz, výchozí routování v ZF je nastaveno takto:

domena.cz/controller/action/*

což odpovídá pravidlu

$route = new Zend_Controller_Router_Route(
  '/:controller/:action/*',
  array(
    'controller' => 'index',
    'action' => 'index'
  )
);

Je tedy vidět, že pouze jednoduchou úpravou pravidel nelze subdomény zapojit do procesu routování.

Vlastní routovaní

Pojďme si tedy nejdříve popsat jednoduchý příklad struktury prezentace, na které budeme routování subdomén v ZF ukazovat. Mějme tedy doménu domena.cz. Na této doméně provozujeme například blog, který je rozdělen do několika kategorií, ty budou tvořit názvy subdomén. Jednotlivé příspěvky — články jsou pak zařazeny v těchto kategoriích (pro jednoduchost předpokládejme že jeden článek patří vždy jen do jedné kategorie). Jako základní subdoménu blogu si zvolíme www, na které budou umístěny základní informace, kontakty a podobné statické stránky. Struktura URL prezentace by tedy mohla vypadat nějak takto:

www.domena.cz/... - základní index, kontakty, ...
<kategorie-url>.domena.cz/ - konkrétní kategorie blogu, zobrazuje seznam článků v dané kategorii
<kategorie-url>.domena.cz/<clanek-url> - konkrétní článek konkrétní kategorie blogu

Pro toto řešení si vytvoříme dvě kolekce rout. První bude routovat základní subdoménu a její akce a druhá bude routovat kategorie a články. Předpokládejme že máme zajištěno že http://domena.cz se bude přesměrovávat na naši základní subdoménu http://www.domena.cz. Obě kolekce budou zapsány pro jednoduchost do bootstrap souboru (bootstrap.php).

Nejdříve je však třeba zjistit aktuální název subdomény, podle kterého se rozhodneme jakou kolekci použít.

Získání názvu domény a subdomény

// rozseknuti nazvu serveru
$domains = explode('.', $_SERVER["HTTP_HOST"]);

// aktualni subdomena
$subdomain = $domains[0];

Nyní si definujeme první kolekci rout pro základní index www.

První kolekce rout:

// zakladni www router
$www_router = new Zend_Controller_Router_Rewrite();
// zruseni defaultniho routovani
$www_router->removeDefaultRoutes();

// vlastni defaultni routa
$route = new Zend_Controller_Router_Route(
  '/*',
  array('controller' => 'index', 'action' => 'index')
);
$www_router->addRoute('default', $route);

// kontakt -- staticka stranka indexu
$route = new Zend_Controller_Router_Route(
  '/contact/*',
  array('controller' => 'index', 'action' => 'contact')
);
$www_router->addRoute('index_contact', $route);

// o nas -- staticka stranka indexu
$route = new Zend_Controller_Router_Route(
  '/about/*',
  array('controller' => 'index', 'action' => 'about')
);
$www_router->addRoute('index_about', $route);

Druhá kolekce rout pro subdoménové kategoriie:

// subdomenovy router -- kategorie
$sub_router = new Zend_Controller_Router_Rewrite();
$sub_router->removeDefaultRoutes();
// defaultni subdomenovy router
$route = new Zend_Controller_Router_Route(
  '/*',
  array(
    'controller' => 'category',
    'action' => 'index',
    'category_url' => $subdomain,
  )
);
$sub_router->addRoute('category_index', $route);

// konkretni clanek v kategorii
$route = new Zend_Controller_Router_Route(
  '/:article_url/*',
  array(
    'controller' => 'article',
    'action' => 'index',
    'category_url' => $subdomain,
  )
);
$sub_router->addRoute('article_index', $route);

A nakonec je třeba se rozhodnout, podle aktuální subdomény, kterou z kolekcí rout nastavíme jako primární a kterou jako alternativní. Pro uložení alternativní routy použijeme Zend_Registry.

Nastavení primární a alternativní kolekce rout

// rozhodnuti, ktera z rout je primarni dle subdomeny indexu
if ( 'www' === $subdomain )
{
  $front->setRouter($www_router);  // defaultni router -- index
  Zend_Registry::set('alt_router', $sub_router); // alternativni router -- subdomeny
}
else
{
  $front->setRouter($sub_router); // defaultni router -- subdomeny
  Zend_Registry::set('alt_router', $www_router);  // alternativni router -- index
}

Vlastní View a View-Helpery

Jelikož na odkazy, které budeme generovat do šablon, nelze přímo použít přibalený Zend_View_Helper_Url a musíme si tedy definovat vlastní URL helper a helpery pro generovaní indexových a subdoménových odkazů. Proto si hned v bootstrapu zavedeme i vlastni view do kterého si předáme parametry (doména a subdoména) již v bootstrapu a v helperech k ním budeme pouze přistupovat.

// vlastni view
$view = new Zend_View;
$view->setScriptPath(array('../application/views/scripts', '.'));
$view->setHelperPath('../application/views/helpers', 'Jens_View_Helper');

// ulozeni subdomeny a domeny do view
$view->server = new stdClass();
$view->server->subdomain = $subdomain;
$view->server->domain = $domains[1].'.'.$domains[2];

Zend_Registry::set('view', $view);

Pro generovaní URL si upravíme přiložený Zend_View_Helper_Url, nazveme si ho Jens_View_Helper_JensUrl. Ten bude fungovat tak, že v případě že neexistuje routa se jménem předaným argumentem $name, zkusíme z registru natáhnout a alternativní sadu rout a budeme hledat routu $name tam.

Dále si definujeme vlastní helpery pro generovaní odkazů základního indexu www: Jens_View_Helper_wwwUrl, pro generování odkazů na kategorie: Jens_View_Helper_CategoryUrl a pro generování odkazu na daný článék dané kategorie: Jens_View_Helper_ArticleUrl. Jednotlivé helpery zde nebudu dále popisovat, najdete je v přiloženém archivu ukázkové aplikace.

Ukázková aplikace

Součástí ukázkové aplikace jsou všechny výše popsané programové jednotky a další tři kontrolery a šablony pro zobrazování výstupu těchto kontrolerů. Celá aplikace má klasickou zendovskou strukturu:

domena.cz/
  application/
    controllers/
    views/
      helpers/
      scripts/
  library/
  public/

Pro správné fungování musíte do adresáře library nahrát Zenda. V příkladu se používají subdomény www, php a zend, proto pokud používáte okna, musíte do host přidat něco takového:

127.0.0.1 www.domena.cz php.domena.cz zend.domena.cz

Samozřejmou nutností je správná konfigurace Apache pro virtuální doménu domena.cz a krásné URL s povoleným mod_rewrite:

ServerName www.domena.cz
ServerAlias domena.cz *.domena.cz

DocumentRoot /var/www/domena.cz/public
<Directory /var/www/domena.cz/public/>
  Options FollowSymLinks
  AllowOverride All
</Directory>

Aplikace ke stažení: příklad routování subdomén v Zend Frameworku

Použité verze aplikací:

Zend Framework 1.5
PHP Version 5.2.5-3
Apache/2.2.8
OS: Debian (Lenny) 2.6.22-3-686

Jeden komentář k článku “Zend Framework: Routování subdomén”

  1. Jens napsal:

    Jen upozorňuji pro případné zájemce, že tento příklad routování už není v aktuálním Zend Frameworku (cca od verze 1.7) relevantní, neboť byla zavedena třída Zend_Controller_Router_Route_Hostname a ZF tedy už přímo podporuje routování domén a subdomén, více viz článek: Zend Framework: Hostname routing – routování domén a subdomén.