Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Kohana - komponenty a'la Symfony
Forum PHP.pl > Inne > Oceny
phpion
Witam,
korzystając z frameworka Kohana brakowało mi możliwości stosowania komponentów (często wykorzystywałem je przy pracy z Symfony). W związku z tym jakiś czas temu napisałem sobie rozszerzenie, które (moim zdaniem) nieźle spełnia funkcję komponentów w Kohana.

application/helpers/symfony.php
  1. <?php
  2. /**
  3.  * Helper zawierający metody rodem z Symfony ;)
  4.  *
  5.  * @package helpers
  6.  */
  7. class symfony {
  8.    /**
  9.      * Renderuje wskazany komponent.
  10.      *
  11.      * @param string $name Nazwa komponentu.
  12.      * @param string $action Wywoływana akcja.
  13.      * @param array $params Tablica przekazywanych parametrów.
  14.      */
  15.    public static function include_component($name, $action, array $params = array()) {
  16.        $class = ucfirst($name).Component::CLASS_SUFFIX;
  17.    
  18.        require_once(APPPATH.Component::COMPONENTS_DIRECTORY.'/'.$name.'.php');
  19.        
  20.        $obj = new $class($name, $action, $params);
  21.        $obj->$action();
  22.        echo $obj->render();
  23.    }
  24. }
  25. ?>


application/libraries/Component.php
  1. <?php
  2. /**
  3.  * Klasa definiująca komponent.
  4.  *
  5.  * Komponent to "podwidok" posiadający własną logikę.
  6.  *
  7.  * @package libraries
  8.  */
  9. class Component {
  10.    /**
  11.      * Nazwa komponentu.
  12.      *
  13.      * @var string
  14.      */
  15.    private $name;
  16.    
  17.    /**
  18.      * Wywoływana akcja.
  19.      *
  20.      * @var string
  21.      */
  22.    private $action;
  23.    
  24.    /**
  25.      * Zbiór parametrów przekazywanych do komponentu.
  26.      *
  27.      * @var array
  28.      */
  29.    private $params;
  30.    
  31.    /**
  32.      * Obiekt widoku danego komponentu.
  33.      *
  34.      * @var View
  35.      */
  36.    protected $view;
  37.    
  38.    /**
  39.      * Tworzy nowy obiekt komponentu.
  40.      *
  41.      * @param string $name Nazwa komponentu.
  42.      * @param string $action Wywoływana akcja.
  43.      * @param array $params Tablica przekazywanych parametrów.
  44.      */
  45.    public function __construct($name, $action, array $params = array()) {
  46.        $this->name = $name;
  47.        $this->action = $action;
  48.        $this->params = $params;
  49.        
  50.        $this->view = new View($name.'/'.$action.self::VIEWS_SUFFIX);
  51.    }
  52.    
  53.    /**
  54.      * Pobiera wartość parametru przekazanego do komponentu.
  55.      *
  56.      * W przypadku gdy wartość nie zostanie odnaleziona zwraca wartość domyślną ($default).
  57.      *
  58.      * @param string $param Nazwa parametru.
  59.      * @param mixed $default Wartość domyślna.
  60.      * @return mixed
  61.      */
  62.    protected function getParam($param, $default = null) {
  63.        return isset($this->params[$param]) ? $this->params[$param] : $default;
  64.    }
  65.    
  66.    /**
  67.      * Renderuje oraz zwraca szablon komponentu.
  68.      *
  69.      * @return string Szablon komponentu.
  70.      */
  71.    public function render() {
  72.        return $this->view->render();
  73.    }
  74.    
  75.    /**
  76.      * Nazwa podkatalogu w katalogu application, w którym zlokalizowane będą klasy komponentów.
  77.      */
  78.    const COMPONENTS_DIRECTORY = 'components';
  79.    
  80.    /**
  81.      * Suffix dołączany do nazwy komponentu w celu utworzenia nazwy klasy.
  82.      *
  83.      * Nazwa klasy komponentu składa się z jego nazwy rozpoczynającej się od wielkiej litery
  84.      * oraz od poniższego suffixu [nazwa_komponentu][SUFFIX], np.
  85.      * class Category_Component {}
  86.      */
  87.    const CLASS_SUFFIX = '_Component';
  88.    
  89.    /**
  90.      * Suffix dla pliku widoku komponentu.
  91.      *
  92.      * Widoki należy umieszczać w folderze application/views jako [nazwa_komponentu]/[akcja][SUFFIX],
  93.      * np. application/category/menu_component.php
  94.      */
  95.    const VIEWS_SUFFIX = '_component';
  96. }
  97. ?>


Aby dodać komponent do widoku (w moim przypadku jest to application/views/template.php) należy:
application/components/user.php
  1. <?php
  2. class User_Component extends Component {
  3.    public function test() {
  4.        // przypisanie aktualnego czasu do widoku
  5.        $this->view->set('time', time());
  6.        
  7.        // utworzenie modelu użytkownika
  8.        $mdlUser = new User_Model();
  9.        // pobranie danych z bazy na podstawie przekazanego parametru
  10.        $user = $mdlUser->get($this->getParam('userId'));
  11.        // przypisanie pobranych danych do widoku
  12.        $this->view->set('user', $user);
  13.    }
  14. }
  15. ?>


application/views/user/test_component.php
  1. <p>Oto przykładowy komponent.</p>
  2. <p>Czas: <?= $time ?>.</p>
  3. <p>User: <?= $user['username'] ?></p>


application/views/template.php
  1. <?php symfony::include_component('user', 'test', array('userId' => 1)) ?>


Bardziej życiowy przykład zastosowania: wyświetlanie panelu użytkownika. Jeżeli użytkownik nie jest zalogowany to wyświetlany jest formularz logowania, natomiast jeśli jest już zalogowany to wyświetlane jest info powitalne i link do wylogowania.

application/components/user.php
  1. <?php
  2. class User_Component extends Component {    
  3.    public function panel() {
  4.        $session = Session::instance();
  5.        
  6.        $isUserAuthenticated = $session->isUserAuthenticated();
  7.        $this->view->set('isUserAuthenticated', $isUserAuthenticated);
  8.        
  9.        if ($isUserAuthenticated === true) {
  10.            $this->view->set('username', $session->getUserData('username'));
  11.            $this->view->set('isActive', $session->getUserData('is_active'));
  12.        }
  13.    }
  14. }
  15. ?>


application/views/user/panel_component.php
  1. <?php if ($isUserAuthenticated === true): ?>
  2. <p>Witaj <strong><?= html::anchor('user/profile', $username) ?></strong>! <?= html::anchor('authentication/logout', 'Wyloguj &raquo;') ?></p>
  3.    <?php if ($isActive == 'f'): ?>
  4.    <p><strong>Konto nieaktywowane!</strong></p>
  5.    <?php endif; ?>
  6. <?php else: ?>
  7. <?= form::open('authentication/login') ?>
  8.    <fieldset>    
  9.        <ul>
  10.            <li>
  11.                <label for="header_authentication_username">Nazwa użytkownika:</label>
  12.                <?= form::input('authentication[username]', '', 'id="header_authentication_username"') ?>
  13.            </li>
  14.            <li>
  15.                <label for="header_authentication_password">Hasło dostępu:</label>
  16.                <?= form::password('authentication[password]', '', 'id="header_authentication_password"') ?>
  17.            </li>
  18.            <li>
  19.                <input type="submit" value="Zaloguj" />
  20.            </li>
  21.        </ul>
  22.    </fieldset>
  23. <?= form::close() ?>
  24. <?php endif; ?>


Wczytanie komponentu w application/views/template.php:
  1. <?php symfony::include_component('user', 'panel') ?>


Prosiłbym o opinie oraz ewentualne uwagi czy sugestie.

pion
Speedy
Mógłbyś ogólnie przybliżyć, w czym mają pomagać i generalnie do czego mają służyć te komponenty? Wyświetlanie formularza lub informacji można spokojnie zrealizować we frameworku bez użycia żadnych komponentów. Nie korzystałem dotychczas z Symfony, dlatego nie jestem w tym zorientowany i chciałbym się dowiedzieć, dlaczego uważasz takie rozwiązanie za dobre.
marcio
Bo wczytyjesz modul gdzie i kiedy chcesz a on reszte robi za ciebie
phpion
Cytat(Speedy @ 1.12.2008, 19:48:11 ) *
Mógłbyś ogólnie przybliżyć, w czym mają pomagać i generalnie do czego mają służyć te komponenty?

Jest tak, jak pisze ~marcio:

Cytat(marcio @ 1.12.2008, 19:51:47 ) *
Bo wczytyjesz modul gdzie i kiedy chcesz a on reszte robi za ciebie

Przykład z panelem użytkownika może nie był najlepszy. Pomyśl sobie jednak, że masz np. sklep internetowy i na każdej podstronie chcesz wyświetlać menu kategorii (pobierane z bazy danych). Możesz oczywiście pisać odpowiednie metody do kontrolera nadrzędnego (i tak to jest realizowane w Kohana), które zrobią to za Ciebie. Jednak w momencie gdy takowych elementów będziesz miał więcej (np. box zawierający produkty w promocji, polecane czy też najchętniej kupowane) dodawanie nowych metod do kontrolera będzie upierdliwe. Poza tym: nie możesz takiego elementu wykorzystać w innym miejscu (np. pod listą produktów z danej kategorii). Skorzystanie z komponentu ogranicza się to wpisu symfony::include_component() w miejscu, w którym mają zostać wyświetlone dane.

Więcej informacji o komponentach znajdziesz tutaj:
http://www.symfony-project.org/book/1_2/07...ayer#Components
marcio
  1. <?php
  2. function add_modules($module) {
  3.    
  4. IF(file_exists('./system/modules/'.$module)) {    
  5.    
  6.    include('./system/modules/'.$module);
  7.   }
  8. return($zawartosc);
  9. }
  10.  
  11.  
  12. function draw_site($tpl = './theme/new/styl/normal/tpl1.tpl', $self) {
  13.  
  14. $layoutObiect = new layout($tpl);
  15.  
  16. $sql = mysql_query('select * from settings where dzial = "'.$self.'" limit 1');
  17. $sql1 = mysql_query('select * from modules where module_dzial = "'.$self.'"');
  18.  
  19. $tab = mysql_fetch_assoc($sql);
  20.  
  21. foreach($tab as $key => $val) $layoutObiect -> addVar($key, $val);
  22.  
  23. while($re = mysql_fetch_assoc($sql1))
  24. $layoutObiect -> addVar($re['module_place'], render_window($re['header'], add_modules($re['module_name'])));
  25.  
  26. $output .= $layoutObiect -> showCode();
  27.  
  28. return $output;
  29. }
  30. ?>

Np u mnie tak wyglada ladowanie wszystkich modulow dla danej podstrony we wlasciwe miejsce tongue.gif oczywiscie mozna tez ladowac moduly gdy wystapi jakis $_GET za pomoca metody load_modules($module); ktora prawie niczym sie nie rozni od add_modules() oprocz tego ze zwraca zmienne z glownym kodem moduly.

Ogolnie moze i przyklad z modulem panela uzytkownika nie jest w pelni zrozumialy bo jak sam chcialem zrozumiec jak uzywac moduly kumpel tez mi zrobil taki przyklad i nic nie zrozumialem, jednak wedlug mnie ja moglbym to tak wytlumaczyc:

Zalozmy ze masz strone index.php(Strona glowna) ktora jest napisania za pomoca div'ow a do kazdego div'a mozesz zaladowac poszczegolny modul i wtedy na stronie kontrolujesz jakie maja byc moduly i gdzie one maja byc, oczywiscie dajac tez mozliwosc ladowania kilka modulow do tego samego div'a.

Ogolnie kod @phpion jest fajny tongue.gif tylko ze ja nie uzywam Kohana ani OOP dlatego tez napisalem wlasne metody tongue.gif
phpion
@marcio:
Za bardzo nie czaję w jakim celu wkleiłeś swój kod. Przyznam również, że nie do końca mogę się połapać o co Ci chodzi smile.gif

Swoją drogą:
moduł != komponent
marcio
Ja na komponent mowie modul zreszta to chyba synonimy w pewnym sensie przynajmniej dla mnie w zyciu codziennym, a kod podalem zeby @Speedy mogl bardziej zrozumiec po co je uzywac
phpion
Cytat(marcio @ 1.12.2008, 21:58:36 ) *
Ja na komponent mowie modul zreszta to chyba synonimy

W takim razie nieco się rozmijamy z ideą komponentów. W Symfony (z którego zaczerpnąłem pomysł) jest to zupełnie coś innego niż to, co opisujesz. Komponent to nie moduł.
Cysiaczek
Koncepcja partiali jest chyba znana programistom Kohanej. Komponent to partial z wydzieloną logiką.
Speedy
Dzięki za linki. Rzeczywiście, poczytałem i jest to fajna sprawa. Mogę sobie wykorzystać Twój kod w Kohanie? snitch.gif
phpion
Cytat(Speedy @ 2.12.2008, 02:32:02 ) *
Mogę sobie wykorzystać Twój kod w Kohanie? snitch.gif

Oczywiście, nie ma problemu.
ziqzaq
Witam.
Nie jest to przypadkiem to samo/podobne podejście co hmvc in kohana tylko tam wykorzystuje się poprostu kontrolery?
nrm
kosmiczne pre-3.0 własnie opiera się na HMVC.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.