wtorek, 3 kwietnia 2007

Zend_Controller_Router_Route i tworzenie nowych tras


Ostatnio na polskim forum Zend Framework spotkałem się z problemem obsługi przyjaznych adresów. Standardowo biblioteka ta obsługuje adresy w postaci:

http://nazwa_strony/nazwa_kontrolera/nazwa_akcji/parametr/wartość

Jednak strona miała zawierać treść wielojęzyczną. I choć Zend obsługuje możliwość odczytania informacji z przeglądarki to programista chciał sterować językiem poprzez umieszczenie kodu przed nazwą kontrolera, np.:

http://nazwa_strony/pl/nazwa_kontrolera/...

Postanowiłem zatem zajrzeć do dokumentacji i napisać niezbędny kod. Zaczniemy od struktury katalogów, którą zaczerpnąłem z jednego tutoriala:

  • application
    • controllers
      • IndexController.php
    • models
    • views
  • library
    • Zend
    • Zend.php
  • public
  • .htaccess
  • index.php

Plik .htaccess zawiera informacje sterujące dla modułu rewrite:

RewriteEngine on
RewriteRule .* index.php


Plik index.php stanowi tak zwany bootstrap dla ZF. W nim dokonujemy należy zainicjalizować wszystkie niezbędne do działania elementy środowiska. A więc do dzieła:

//Konfiguracja debugowania

define('_DEBUG',1);



if (defined('_DEBUG'))

if (_DEBUG == 1)

error_reporting(E_ALL|E_STRICT);



date_default_timezone_set('Europe/Warsaw');



//Konfigurujemy ścieżki bibliotek

set_include_path('.' . PATH_SEPARATOR

. './library' . PATH_SEPARATOR

. './application/models/' . PATH_SEPARATOR

. get_include_path() );



//Ładujemy jądro ZF

include('Zend.php');



try {

//Ładujemy niezbędne klasy

Zend::loadClass('Zend_View');

Zend::loadClass('Zend_Controller_Front');

Zend::loadClass('Zend_Controller_Router_Rewrite');



//Ustawiamy adres bazowy

$baseUrl = substr($_SERVER['PHP_SELF'], 0,

strpos($_SERVER['PHP_SELF'], '/index.php'));



//Konfiguracja klasy widoku
$view = new Zend_View();

$view->baseUrl = $baseUrl;

$view->setScriptPath('./application/views');

Zend::register('view',$view);



//Tutaj konfigurujemy naszą nową trasę

$route = new Zend_Controller_Router_Route(

':lang/:controller/:action',

//Zmienna określająca język znajduje się przed kontrolerem

array('lang'=>'pl', 'controller'=>'index',

'action'=>'index'), //Wartości domyślne

array('lang'=>'[a-z_]+')); //Warunek dla lang



//Utworzenie routera z naszą trasą

$router = new Zend_Controller_Router_Rewrite();

$router->removeDefaultRoutes();

$router->addRoute('user', $route);



//Inicjalizacja głównego kontrolera

$frontController = Zend_Controller_Front::getInstance();

$frontController->setRouter($router);

$frontController->setBaseUrl($baseUrl);

$frontController->setControllerDirectory(

'./application/controllers');

$frontController->throwExceptions(true);

$frontController->returnResponse(true);



//Inicjalizacja obiektu odpowiedzi

$response = $frontController->dispatch();

$response->renderExceptions(true);

$response->setHeader('Pragma', 'No-cache');

$response->setHeader('Cache-Control', 'no-cache');



//Wyświetlenie strony

echo $response;

} catch (Exception $exception) {

//Obsługa wyjątku

$message = 'Application setup exception: ';

$message.= $exception->getMessage();

if (defined('_DEBUG')) if (_DEBUG){

$message .= 'Trace: '.$exception->getTraceAsString();

}

die($message);

}

Nie pozostało zatem nic innego jak odczytać informacje o języku. Dokonamy tego w pliku IndexController.php:

class IndexController extends Zend_Controller_Action

{

function indexAction()

{

echo $this->_getParam('lang','pl');

echo " in IndexController::indexAction()";

}

}

Po przekopiowaniu plików na serwer dostaniemy informacje o języku i wywołanej metodzie

3 komentarze:

cyphelf pisze...

Myślę, że warto by było przykład lekko zmodyfikować, aby był w pełni przystosowany do wersji beta i później do 1.0.

Klasa Zend oznaczona jest teraz jako przestarzała, i została rozbita na kilka innych klas, więc w tym przykładzie dorze by było użyć klas Zend_Registry oraz Zend_Loader zamiast metod statycznych klasy Zend.

Live By Dream pisze...

Witam,
zaimplementowałem Twój sposób na wielojęzyczność w swojej aplikacji, z tą różnicą, że u siebie mam strukturę modularną katalogów. Mój problem polega na tym, że teraz nie jest obsługiwany ErrorController, tzn. nieważne jaki adres wpiszę (niepoprawny), zawsze wyświetlana jest domyślna strona, a nie strona z informacją o błędzie. Czy mógłbyś mi powiedzieć co muszę zmodyfikować? Ewentualnie gdzie mam szukać przyczyny? Pozdrawiam.

Smok pisze...

!UWAGA!
Artykuł całkowicie przestarzały. Proszę nie tracić czasu na jego czytanie.