Witaj, Gościu O nas | Kontakt | Mapa
Wortal Forum PHPEdia.pl Planeta Kubek IRC Przetestuj się!

Frameworki dla PHP, czyli wydajne tworzenie aplikacji

Budujemy własny framework

Jak już zdążyliśmy zauważyć, wzorzec MVC daje nam solidne podstawy architektoniczne, w oparciu o które możemy zacząć konstruować własny framework. Ponieważ wytyczne samego MVC są dość ogólne, w kolejnych krokach przyjrzymy się dokładniej poszczególnym warstwom wypełniając je realnym, działającym kodem. Wszystkie zamieszczone przykłady zapisane są w PHP5.

Kontroler

Jeśli z programu na Listingu 4 wydzielimy warstwy modelu i widoku do osobnych plików, zostanie nam dość zgrabny skrypt, w którym otwieramy połączenie z bazą danych, pobieramy model i wybieramy widok. Nawet na podstawie tak prostego kontrolera można zaobserwować jego dwie ciekawe własności. Obsługuje on tylko jedną logiczną akcję (tu: pobranie listy newsów), ale zawiera również kod, który musi być wykonany dla każdej akcji. Na Listingu 4 jest to połączenie z bazą, ale z łatwością można wymienić inne przykłady: uwierzytelnianie, otwieranie sesji, logowanie zdarzeń itd. Wydzielmy więc powtarzalne fragmenty kodu do osobnej części kontrolera. Podział, który przed chwilą wykonaliśmy, jest bardzo często praktykowany przy budowaniu frameworka, a wspólny fragment kontrolera ma nawet specjalną nazwę: Front Controller.

Front Controller obsługuje wszystkie żądania przychodzące do aplikacji i realizuje operacje wspólne dla wszystkich akcji. W kolejnym kroku odnajduje on kontroler charakterystyczny dla danej akcji i przekazuje do niego sterowanie.

Strategie, według których odnajdywane i wykonywane są poszczególne kontrolery akcji, mogą być bardzo różne. Na początku zastosujmy najprostszą: każda akcja będzie zapisana w oddzielnym pliku o nazwie [nazwa_akcji].action.php. Użytkownik będzie decydował, którą z akcji wywołać, przekazując do Front Controllera parametr, np. http://[URL Front Controllera]? action=[nazwa_akcji].

Wynikiem działania pojedynczego kontrolera akcji musi być nazwa widoku oraz przygotowane obiekty modelu. Sformalizujmy te zwracane wartości opakowując je w klasę o nazwie ModelAndView.

Poznaliśmy sporo nowych pojęć, wróćmy więc do kodu PHP, aby zobaczyć jak to wszystko współgra w gotowej aplikacji. Listing 5 to definicja klasy ModelAndView. Kolejny kod programu umieszczony na Listingach 6 i 7 zawiera przebudowane klasy kontrolera akcji i Front Controllera.

Listing 4. Separacja warstwy modelu i kontrolera

<?php
// MODEL
class NewsModel{
    public function __construct($data_array){
        foreach($data_array as $k => $v){
            $this->$k = $v;
        }
    }

    public function isValid(){
        if ((int)$this->news_valid) {
            if (($this->news_validfrom == '0000-00-00 00:00:00')&&
            ($this->news_validto == '0000-00-00 00:00:00')) {
                return true;
            } else if (($this->news_validfrom == '0000-00-00 00:00:00')&&
            (time()<strtotime($this->news_validto))) {
                return true;
            } else if (($this->news_validto == '0000-00-00 00:00:00')&&
            (time()>strtotime($this->news_validfrom))) {
                return true;
            } else if ((time()>strtotime($this->news_validfrom))&&
            (time()<strtotime($this->news_validto))) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
}
class NewsModelDao {
    public function findAllNews(){
        $query = "SELECT * FROM my_news";
        $result = mysql_query($query)
            or die("Błąd zapytania : " . mysql_error());
        $result_arr = array();
        while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
            $result_arr[] = new NewsModel($line);
        }
        mysql_free_result($result);
        return $result_arr;
    }
}
// KONTROLER
// połączenie z DB
$link = mysql_connect("localhost", "root", "")
    or die("Nie mogę podłączyć się do DB : " . mysql_error());
mysql_select_db('newsdb') or die("Nie mogę wybrać DB!");
$news_dao = new NewsModelDao();
$result_arr = $news_dao->findAllNews();
// rozłączenie z DB
mysql_close($link);
// WIDOK
include('news_list_view.php');
?>

Oczywiście w aplikacji może znajdować się więcej niż jeden Front Controller. Rozwiązanie takie stosujemy wtedy, gdy mamy do wykonania różne zestawy operacji przed uruchomieniem właściwego kontrolera. Dobrym przykładem takiej sytuacji jest nasz moduł newsów z częścią administracyjną. Będziemy wtedy mieli dwa Front Controllery: jeden obsługujący prezentację i drugi - administrację z uwierzytelnianiem.

Widok

Zwróćmy uwagę, że kontroler włącza konkretny plik zawierający widok. Jest to akceptowalne rozwiązanie w przypadku, gdy mamy tylko jeden rodzaj prezentacji. Niestety, przy wielu różnych sposobach wyświetlania nie jest to najlepsze posunięcie: musielibyśmy w jednym pliku widoku zawrzeć informacje o wielu typach prezentacji.

Kolejny problem naszej warstwy widoku wiąże się z formą zapisu kodu HTML i informacji dynamicznej dla najpopularniejszego medium - przeglądarki WWW. Czy przedstawiony sposób zapisu nie przypomina nam czegoś? Tak, to po prostu szablon.

Rozwiążmy oba omówione problemy. Pierwszym krokiem będzie dodanie do rodzącego się frameworka systemu szablonów Smarty. Zmiana budowy kontrolera akcji i wprowadzenie klasy Model- AndView pozwoli nam uporządkować bałagan związany z przekazywaniem informacji o widoku.

Model

Również w warstwie modelu jest coś, co moglibyśmy udoskonalić. Najpierw jednak kilka słów o klasie NewsModelDao. Jej nazwa nie została wybrana przypadkowo, ponieważ skrót DAO pochodzi od kolejnego wzorca projektowego - ang. Data Access Object. Opisuje on sposób dostępu do trwałego źródła danych (najczęściej będzie to baza danych). Zgodnie ze wzorcem DAO cała logika dostępu do zewnętrznych danych konkretnego typu jest zamknięta w jednej klasie. Takie podejście daje nam kolosalne korzyści. Po pierwsze, dla obiektów korzystających z DAO zupełnie obojętne jest, skąd pochodzą dane. Pozwala to zmieniać miejsce przechowywania informacji bez naruszania pozostałych fragmentów kodu. Wyobraźmy sobie sytuację, w której poproszono nas by aplikacja, którą stworzyliśmy, pobierała od dzisiaj dane o użytkownikach nie z bazy danych, ale z webserwisu. Jeśli kod dostępu do danych użytkowników był rozrzucony w wielu skryptach, czeka nas wiele pracy polegającej na przepisywaniu i testowaniu całego rozwiązania. Przy wykorzystaniu DAO również musimy się trochę napracować, ale zadanie jest znacznie łatwiejsze do wykonania.

DAO jest jedyną częścią aplikacji, która zawiera kod związany z konkretną składnicą danych. Dzięki temu wszelkie zmiany związane z fizycznym medium są zamknięte w jednej klasie, a modyfikacja nazw tabel czy poszczególnych kolumn jest banalnie prosta do wprowadzenia. Dodatkowo możemy w DAO zamaskować różnice pomiędzy bazami danych korzystając z warstwy abstrakcji dostępu do bazy, np. AdoDB.

Listing 5. Klasa ModelAndView

<?php
class ModelAndView
{
    private $_model;
    private $_view;
    public function getModel()
    {
        return $this->_model;
    }
    public function setModel($model_arr)
    {
        $this->_model = $model_arr;
    }
    public function addToModel($arr_key, $model_value)
    {
        $this->_model[$arr_key] = $model_value;
    }
    public function setView($view)
    {
        $this->_view = $view;
    }
    public function getView()
    {
        return $this->_view;
    }
}
?>

Listing 6. Front Controller włączający kontroler akcji

<?php
require_once('ModelAndView.class.php');
$link = mysql_connect("localhost", "root", "")
    or die("Nie mogę połączyć się z DB : " . mysql_error());
mysql_select_db('newsdb') or die("Nie mogę wybrac DB!");
$action_to_run = $_GET['action'];
if ($action_to_run != '') {
    $action_file_name = $action_to_run.'.action.php';
    if (file_exists($action_file_name)) {
        require_once($action_file_name);
        $actionclassname = $action_to_run.'action';
        $actioncontroller = new $actionclassname();
        $mv = $actioncontroller->processRequest();
    } else {
        die("Brak akcji do uruchomienia!");
    }
} else {
    die("Brak parametru do odnalezienia akcji!");
}
mysql_close($link);
$result_arr = $mv->getModel();
include($mv->getView());
?>
Informacje na podobny temat:
Wasze opinie
Wszystkie opinie użytkowników: (11)
Adam
Czwartek 14 Styczeń 2010 6:22:02 pm - pp-layouts <a.lyskawa_at_gmail.com>

A już myślałem, że jestem szaleńcem rozwijając własny framework. A robię tak dlatego, że wychodzi mi zawsze szybciej napisać brakujący komponent X niż nauczyć się od podstaw nowego frameworka. Do tego jeszcze ta siła przyzwyczajeń. Byłbym chory gdybym miał na przykład mieszać php z html w jednym pliku, a np w ZF to norma.

Fajny art
Piątek 09 Styczeń 2009 10:04:20 am - uve

Fajny art, tylko nie rozumiem jednej rzeczy.

Co jest zawarte w klasie newsmodel.clsss.php ?

Pozdr.

pdf
Wtorek 06 Styczeń 2009 1:40:05 pm - yaotzin <yaotzin1_at_o2.pl>

PDF'a dajcież ...

Art
Piątek 08 Sierpień 2008 12:29:47 pm - Joachim Peters <edaroo_at_gmail.com>

Fajny art, na poziomie :)

Wersja do wydruku
Wtorek 30 Październik 2007 4:09:24 pm - reddy

A czy jest gdzies wersja do wydruku (np. PDF lub calosc na jednej stronie)? Wygodniej czytac z kartki :)

;)
Środa 15 Sierpień 2007 8:41:40 pm - carbolymer

Ciężki artykuł o ciężkim temacie. Listingi zbyt porozrzucane, czasem nie można odnaleźć klas o których jest mowa w tekście. Jest parę literówek w kodzie. Ogólnie jest dobrze.

Dobry artykul
Czwartek 04 Maj 2006 1:45:52 am - SzajbuS <szajbus_at_rambler.com.pl>

Listingi i rysunki troche zle umiejscowione w tekscie, co utrudnia czytanie, ale wartosc merytoryczna wysoka.

Brak druku do PDF
Środa 22 Luty 2006 9:27:25 pm - angel2953

Dlaczego jest brak możliwości pobrania tego artykułu jako pliku PDF ? Lub jeśli ów link istnieje (ja go jakoś nie potrafię zlokalizować) dlaczego jest tak słobo widoczny ?

prosty temat
Sobota 28 Styczeń 2006 6:00:51 pm - emp

po prostu zrob sobie swoje klasy i chierarchie klas i masz szkielety aplikacji i do tego bardzo modularne

Profesjonalizm
Niedziela 15 Styczeń 2006 12:22:17 pm - aztech <scrabblewroclaw_at_op.pl>

Cieszę się, że uwagi jakie zgłosiłem co do wyglądu listingów oraz ich podlinkowania zostały zauważone i szybko wprowadzone. To świadczy o profesjonalnym podejściu osób tworzacych ten wortal.
Brawo!

Brak danych :)
Piątek 13 Styczeń 2006 10:32:09 pm - ..:: pingu ::.. <pingu_at_interia.pl>

W PDF'ie ten artykuł wyglada duzo lepiej :P

Szkoda ze czasem trzeba przejsc na nastepna strone aby zobaczyc listing :(

Mentax.pl    NQ.pl- serwery z dodatkiem świętego spokoju...   
O nas | Kontakt | Mapa serwisu
Copyright (c) 2003-2017 php.pl    Wszystkie prawa zastrzeżone    Powered by eZ publish Content Management System eZ publish Content Management System