Clicky

Skocz do zawartości


Zdjęcie
- - - - -

[K2] Komponenty a'la Symfony - include_component()

33 odpowiedzi w tym temacie

  • Zaloguj się, aby dodać odpowiedź

#1 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 17 listopad 2008 - 17:26

Witam,
w Kohanie brakowało mi możliwości wczytywania komponentów czyli "podwidoków" posiadających własną logikę. W wyniku tego postanowiłem dopisać sobie takową funkcjonalność.

application/helpers/symfony.php
<?php
/**
* Helper zawierający metody rodem z Symfony ;)
*
* @package helpers
*/
class symfony {
/**
* Renderuje wskazany komponent.
*
* @param string $name Nazwa komponentu.
* @param string $action Wywoływana akcja.
* @param array $params Tablica przekazywanych parametrów.
*/
public static function include_component($name, $action, array $params = array()) {
$class = ucfirst($name).Component::CLASS_SUFFIX;

require_once(APPPATH.Component::COMPONENTS_DIRECTORY.'/'.$name.'.php');

$obj = new $class($name, $action, $params);
$obj->$action();
echo $obj->render();
}
}


application/libraries/Component.php
<?php
/**
* Klasa definiująca komponent.
*
* Komponent to "podwidok" posiadający własną logikę.
*
* @package libraries
*/
class Component {
/**
* Nazwa komponentu.
*
* @var string
*/
private $name;

/**
* Wywoływana akcja.
*
* @var string
*/
private $action;

/**
* Zbiór parametrów przekazywanych do komponentu.
*
* @var array
*/
private $params;

/**
* Obiekt widoku danego komponentu.
*
* @var View
*/
protected $view;

/**
* Tworzy nowy obiekt komponentu.
*
* @param string $name Nazwa komponentu.
* @param string $action Wywoływana akcja.
* @param array $params Tablica przekazywanych parametrów.
*/
public function __construct($name, $action, array $params = array()) {
$this->name = $name;
$this->action = $action;
$this->params = $params;

$this->view = new View($name.'/'.$action.self::VIEWS_SUFFIX);
}

/**
* Pobiera wartość parametru przekazanego do komponentu.
*
* W przypadku gdy wartość nie zostanie odnaleziona zwraca wartość domyślną ($default).
*
* @param string $param Nazwa parametru.
* @param mixed $default Wartość domyślna.
* @return mixed
*/
protected function getParam($param, $default = null) {
return isset($this->params[$param]) ? $this->params[$param] : $default;
}

/**
* Renderuje oraz zwraca szablon komponentu.
*
* @return string Szablon komponentu.
*/
public function render() {
return $this->view->render();
}

/**
* Nazwa podkatalogu w katalogu application, w którym zlokalizowane będą klasy komponentów.
*/
const COMPONENTS_DIRECTORY = 'components';

/**
* Suffix dołączany do nazwy komponentu w celu utworzenia nazwy klasy.
*
* Nazwa klasy komponentu składa się z jego nazwy rozpoczynającej się od wielkiej litery
* oraz od poniższego suffixu [nazwa_komponentu][SUFFIX], np.
* class Category_Component {}
*/
const CLASS_SUFFIX = '_Component';

/**
* Suffix dla pliku widoku komponentu.
*
* Widoki należy umieszczać w folderze application/views jako [nazwa_komponentu]/[akcja][SUFFIX],
* np. application/category/menu_component.php
*/
const VIEWS_SUFFIX = '_component';
}


Aby dodać komponent do widoku (w moim przypadku jest to application/views/template.php) należy:
application/components/user.php
class User_Component extends Component {
public function test() {
// przypisanie aktualnego czasu do widoku
$this->view->set('time', time());

// utworzenie modelu użytkownika
$mdlUser = new User_Model();
// pobranie danych z bazy na podstawie przekazanego parametru
$user = $mdlUser->get($this->getParam('userId'));
// przypisanie pobranych danych do widoku
$this->view->set('user', $user);
}
}


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


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


Proste, a zarazem funkcjonalne :) Myślę, że wszystko jest jasno opisane. Może komuś się przyda.

PS: Jeżeli temat umieściłem w złym dziale (może "Tutoriale"?) to prosiłbym o przeniesienie go w odpowiednie miejsce.
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#2 r4zick

r4zick

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 234 postów

Napisano 18 listopad 2008 - 19:09

A do czego się wykorzystuje komponenty?

#3 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 18 listopad 2008 - 19:38

Zastosowań jest masa. Przykładowo: możesz użyć komponentu w celu utworzenia menu w sklepie internetowym. Ja na razie zastosowałem go do wyświetlania panelu użytkownika. Jeżeli użytkownik nie jest zalogowany to wyświetlam formularz logowania, natomiast jeśli jest już zalogowany to wyświetlam info powitalne i link do wylogowania.

Generalnie zaleta komponentów jest taka, że możesz w nich bawić się sesjami, pobierać dane z bazy itd itd. Wszystko to zamykasz w jednej akcji klasy dziedziczącej po komponencie, a wszystko ładujesz prostą linijką symfony::include_component($nazwa, $akcja) bezpośrednio w widoku. Tyle.

Link do manuala komponentów w Symfony: http://www.symfony-p...ayer#Components

Działa to tak:
application/components/user.php
<?php
class User_Component extends Component {
public function panel() {
$session = Session::instance();

$isUserAuthenticated = $session->isUserAuthenticated();
$this->view->set('isUserAuthenticated', $isUserAuthenticated);

if ($isUserAuthenticated === true) {
$this->view->set('username', $session->getUserData('username'));
$this->view->set('isActive', $session->getUserData('is_active'));
}
}
}

W metodzie tej korzystam z kilku metod dodanych do klasy Session. Sprawdzają one stan zalogowania użytkownika ($session->isUserAuthenticated()) oraz pobierają dane o nim ($session->getUserData('username')). To tylko jako drobne wyjaśnienie.

application/views/user/panel_component.php
<?php if ($isUserAuthenticated === true): ?>
<p>Witaj <strong><?= html::anchor('user/profile', $username) ?></strong>! <?= html::anchor('authentication/logout', 'Wyloguj &raquo;') ?></p>
<?php if ($isActive == 'f'): ?>
<p><strong>Konto nieaktywowane!</strong></p>
<?php endif; ?>
<?php else: ?>
<?= form::open('authentication/login') ?>
<fieldset>
<ul>
<li>
<label for="header_authentication_username">Nazwa użytkownika:</label>
<?= form::input('authentication[username]', '', 'id="header_authentication_username"') ?>
</li>
<li>
<label for="header_authentication_password">Hasło dostępu:</label>
<?= form::password('authentication[password]', '', 'id="header_authentication_password"') ?>
</li>
<li>
<input type="submit" value="Zaloguj" />
</li>
</ul>
</fieldset>
<?= form::close() ?>
<?php endif; ?>


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


Jak dla mnie jest to zdecydowanie bardziej wygodne niż zabawa z nowymi metodami w kontrolerach (lub powtarzaniem kodu).
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#4 r4zick

r4zick

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 234 postów

Napisano 19 listopad 2008 - 12:16

Przydatne choć ja to robię inaczej i nie powtarzam kodu :P

#5 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 19 listopad 2008 - 12:51

Mógłbyś pokazać w jaki sposób to rozwiązujesz? Dla mnie jedynym sensownym rozwiązaniem byłoby dopisanie chronionej lub nawet prywatnej metody w danym kontrolerze, która przypisywałaby dane do danego obszaru. W każdej akcji należałoby wówczas wykonać $this->metoda() aby dokonać przypisania danych. Jak dla mnie jest to dość upierdliwe rozwiązanie, szczególnie przy elementach, które są na stałe na każdej podstronie. Wiem, że można takowe metody przypisać do głównego kontrolera i późniejsze kontrolery dziedziczyć po nim ale... wolę komponenty :)

Przedstaw proszę swoje rozwiązanie - możliwe, że czegoś nie wiem i da się uzyskać podobny efekt bez używania komponentów.
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#6 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 19 listopad 2008 - 14:30

do powtarzania tych samych rzeczy na każdej podstronie jest zwykle jakiś główny Site_Controller rozszerzający Template_Controller'a

#7 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 19 listopad 2008 - 14:39

do powtarzania tych samych rzeczy na każdej podstronie jest zwykle jakiś główny Site_Controller rozszerzający Template_Controller'a

Tak też mam :) Początkowo właśnie tam umieściłem kod tworzący panel z logowaniem/danymi użytkownika. W przypadku elementów występujących na każdej podstronie to rozwiązanie się sprawdza. Ale co w przypadku gdy chcemy powtarzać dany element w obrębie tylko jednego kontrolera? Oczywiście można dodawać warunki sprawdzające Router::$controller ale to i tak (moim zdaniem) wszystko komplikuje.
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#8 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 19 listopad 2008 - 15:01

Ale co w przypadku gdy chcemy powtarzać dany element w obrębie tylko jednego kontrolera?

korzystamy z konstruktora tego kontrolera

#9 r4zick

r4zick

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 234 postów

Napisano 19 listopad 2008 - 16:05

Mam 3 wersje template controllera.

#10 marrek13

marrek13

    Początkujący

  • Użytkownik
  • Pip
  • 43 postów

Napisano 21 listopad 2008 - 20:26

Moim zdaniem pomysł z komponentami wcale nie jest głupi. Można tak jak wyżej powiedzieć, że to samo da się zrobić za pomocą kontrolerów etcetera, ale takie coś przydaje się w momencie gdy często wykorzystujemy kod jednego skryptu do napisania następnego. Nie musimy wtedy wyciągać z kontrolerów co trzeba, tylko kopiujemy 2 pliki i gra gitara ;)

#11 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 21 listopad 2008 - 21:02

Również uważam, że jest to dość przydatna rzecz. Po ponad roku kodowania w Symfony mogę z całą odpowiedzialnością powiedzieć, że komponenty i partiale (prostsze komponenty, bez osobnej akcji) były przeze mnie bardzo często wykorzystywane. Jednak co kto lubi - nie każdy musi chcieć z nich korzystać. Ja zdecydowanie je polecam :)
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#12 jarek_bolo

jarek_bolo

    Początkujący

  • Użytkownik
  • Pip
  • 65 postów
  • Skąd:łódzkie

Napisano 27 listopad 2008 - 16:16

Do tej pory robiłem tak jak to opisał @mck, ale przyznam @Phpion, że ładnie portnołeś componenty z Symfony :)
Jam jest Polska, Ojczyzna Twoja, ziemia Ojców, z której wzrosłeś. Wszystko, czym jesteś, po Bogu - mnie zawdzięczasz!!

#13 crashu

crashu

    Początkujący

  • Użytkownik
  • Pip
  • 6 postów

Napisano 05 marzec 2009 - 23:54

a moze by tak  zwiększyc integracie w Kohane i:

system/core/Kohana.php (2.3.1) linjka 969:
		elseif ($suffix === 'Component')
{
$type = 'Component';
$file = strtolower(substr($class, 0, -10));
}


usage:
<?php echo new Test_Component('akcia', array('param' => 1)); ?>


#14 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 06 marzec 2009 - 00:02

tak ogólnie to grzebanie w system/* nie jest najszczęśliwszym pomysłem :)

#15 crashu

crashu

    Początkujący

  • Użytkownik
  • Pip
  • 6 postów

Napisano 06 marzec 2009 - 00:14

Od wtykania palcow w system nic zlego sie nam nie stanie, pozatym jesli ktos nie wie co robi zawsze moze zrobic backup pliku wprowadzic zmiany, sprawdzic czy działa, jesli tak to w czym problem ? Pozatym zmiana ktura wprowadziłem nie jest niczym specialnym , skopiowalem 5 linijek kodu i zmienilem 3 wartosci, niczego tym sposobem nie uszkodzimy, zreszta nigdzie nie widzialme ostrzeżenia "tutaj nosa nie wtykac"  :)

Dodam jeszcze iz moja ciekawosc NAKAZUJE mi zobaczyc co tam jest i czy mozna tam cos zmienic,  podpatrzec, ulepszyc ... itp. Z tego co mi wiadomo ideą wolnego oprogramowanie jest jego ulepszanie....

#16 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 06 marzec 2009 - 00:26

ja nie mówię, że nie, ale po każdej takiej zmianie wypadałoby przykleić na monitorze żółtą karteczkę, żeby przy aktualizacji źródła się nie zdziwić :)

#17 crashu

crashu

    Początkujący

  • Użytkownik
  • Pip
  • 6 postów

Napisano 06 marzec 2009 - 00:54

jesli komus odpowiada takie rozwiazanie moze skorzystac jesli nie, są inne motody aby osiagac cel, ja tylko pokazalem jak mozna zrobic to inaczej, "ładniej(?)"

#18 nrm

nrm

    webmastah

  • Admin
  • 1106 postów
  • Skąd:Katowice

Napisano 06 marzec 2009 - 01:23

Od wtykania palcow w system nic zlego sie nam nie stanie

upierdo*** ci palce...

#19 crashu

crashu

    Początkujący

  • Użytkownik
  • Pip
  • 6 postów

Napisano 06 marzec 2009 - 02:06

Od wtykania palcow w system nic zlego sie nam nie stanie

upierdo*** ci palce...


mod robiacy spam, nice, mam nadzieje ze to zart, bo jesli nie to bb

#20 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 06 marzec 2009 - 09:16

crashu:
Fajnie, że ptrafisz grzebać w plikach systemowych i że czujesz się w tym jak ryba w wodzie i że ogólnie jesteś wymiatacz. Jednak, tak jak pisał mck, takie podejście jest fe. W przypadku aktualizacji Kohany do nowszej wersji musisz przenieść wszystkie wprowadzone zmiany. Co do ulepszania kodu: jasne, ale jest do tego odpowiednie miejsce (application/libraries). Tam możesz rozszerzać pliki systemowe o własne funkcjonalności.

PS: Twoje rozwiązanie i tak nie zadziała. Musisz dodatkowo dodać metodę __toString() do klasy Component, która będzie go renderowała. Niby nic, a jednak o tym zapomniałeś.
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#21 thejw23

thejw23

    Senior Mastah

  • Webmastahy
  • PipPipPip
  • 824 postów

Napisano 06 marzec 2009 - 09:20

mck/normanos chcieli tylko powiedziec, ze z grzebania w systemie zazwyczaj nic dobrego nie wynika - przy kolejnych aktualizacjach bardzo latwo zapomniec co i gdzie sie zmienialo, a potem jest placz i zgrzytanie zebami :) mozesz robic co chcesz, mozesz zmienic nazwy klas, metod i helperow  na takie jak lubisz, mozesz wywalic polowe kodu uwazajac, ze jest zbedna - to juz jest Twoja sprawa. mozesz wszystko, tylko nie zawsze warto/powinno sie wszystko robic.  ja sie z normanosem zgadzam, w system lepiej nie grzebac, bo moze palce upier... :)  ja tam bardziej sobie cenie bezproblemowa aktualizacje, niz tego typu ulepszenia.

tak czy inaczej dzieki za podzielenie sie kodem, pomysl dobry, moze ktos skorzysta.



#22 Adam16

Adam16

    Początkujący

  • Użytkownik
  • Pip
  • 18 postów
  • Skąd:Niemcy

Napisano 06 marzec 2009 - 10:36


application/helpers/symfony.php

<?php
/**
* Helper zawierający metody rodem z Symfony ;)
*
* @package helpers
*/
class symfony {
/**
* Renderuje wskazany komponent.
*
* @param string $name Nazwa komponentu.
* @param string $action Wywoływana akcja.
* @param array $params Tablica przekazywanych parametrów.
*/
public static function include_component($name, $action, array $params = array()) {
$class = ucfirst($name).Component::CLASS_SUFFIX;

require_once(APPPATH.Component::COMPONENTS_DIRECTORY.'/'.$name.'.php');

$obj = new $class($name, $action, $params);
$obj->$action();
echo $obj->render();
}
}



Powinno byc raczej tak:


$class = ucfirst($name).Component::CLASS_SUFFIX.EXT;
require_once(APPPATH.Component::COMPONENTS_DIRECTORY.'/'.$class);

System komputerowy jest tylko na tyle bezpieczny i dobry
jak jego Administrator ktory go obsługuje.

Jak dobrze jednak ten Administrator swoje umiejetniosci
wykorzystac moze, jest juz zapisane w tym systemie.

#23 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 06 marzec 2009 - 11:44

Adam16:
Jest dobrze. Klasy komponentów to pliki nazwa.php, a nie Nazwa_Component.php
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#24 crashu

crashu

    Początkujący

  • Użytkownik
  • Pip
  • 6 postów

Napisano 06 marzec 2009 - 14:29

[...] ogólnie jesteś wymiatacz.

Nie mowilem ze jestem wymiatacz

PS: Twoje rozwiązanie i tak nie zadziała. Musisz dodatkowo dodać metodę __toString() do klasy Component, która będzie go renderowała. Niby nic, a jednak o tym zapomniałeś.

Pisałem to w nocy, na szybko, zaciekawil mnie ten temat i chcialem pokazac inną mozliwosc, ale skoro jestes tak czepliwy to prosze bardzo:

system/core/kohana.php:
elseif ($suffix === 'Component')
{
$type = 'components';
$file = strtolower(substr($class, 0, -10));
}


component.php
<?php

/**
* Klasa definiująca komponent.
*
* Komponent to "podwidok" posiadający własną logikę.
*
* @package libraries
*/
class Component
{
/**
* Nazwa komponentu.
*
* @var string
*/
private $name;
/**
* Wywoływana akcja.
*
* @var string
*/
private $action;

/**
* Zbiór parametrów przekazywanych do komponentu.
*
* @var array
*/
private $params;

/**
* Obiekt widoku danego komponentu.
*
* @var View
*/
protected $view;

/**
* Suffix dla pliku widoku komponentu.
*
* Widoki należy umieszczać w folderze application/views jako [nazwa_komponentu]/[akcja][SUFFIX],
* np. application/category/menu_component.php
*/
const VIEWS_SUFFIX = '_component';

/**
* Tworzy nowy obiekt komponentu.
*
* @param string $name Nazwa komponentu.
* @param string $action Wywoływana akcja.
* @param array $params Tablica przekazywanych parametrów.
*/
public function __construct($action, $params = array())
{
$this->name = get_class($this);
$this->action = $action;

$this->params = $params;
$this->view = new View(strtolower(substr($this->name, 0, -10).'/'.$action).self::VIEWS_SUFFIX);

$this->$action();
}

/**
* Pobiera wartość parametru przekazanego do komponentu.
*
* W przypadku gdy wartość nie zostanie odnaleziona zwraca wartość domyślną ($default).
*
* @param string $param Nazwa parametru.
* @param mixed $default Wartość domyślna.
* @return mixed
*/
protected function getParam($param, $default = null)
{
return isset($this->params[$param]) ? $this->params[$param] : $default;
}

public function __toString()
{
//lub: $this->view->render()
return $this->view->__toString();
}
}
?>


#25 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 06 marzec 2009 - 15:58

ale skoro jestes tak czepliwy to prosze bardzo

Dziękuję :)

PS: wciąż mieszasz w systemie - rób jak uważasz... Warto tak ryzykować tylko po to by wstawiać komponent poprzez:
<?php echo new Test_Component('akcja', array('param' => 1)); ?>

zamiast:
<?php symfony::include_component('test', 'akcja', array('param' => 1)) ?>

? Moim zdaniem nie warto no "ale to Twój tron" ;)
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana




Użytkownicy przeglądający ten temat: 0

0 użytkowników, 0 gości, 0 anonimowych