Witam wszystkich,
Ostatnio zacząłem czytać o obiektowym php5, MVC, frameworkach i postanowiłem zacząć pisać kod, który byłby dla mnie wygodny oraz co ważne - nadawał się do powtórnego wykorzystania.
Opiszę to co do tej pory zrobiłem. Proszę Was, znaczniej bardziej doświadczonych programistów, o uwagi na temat mojego podejścia.
Zaznacze, że swoją pracę oparłem do tej pory na artykule Frameworki z php.pl, framework CakePHP oraz o wypowiedzi forumowiczach w topikach MVC.
Charakterystyka ogólna:Drzewo projektuKod
|- actions/ (tu wrzucam kontrolery w postaci class.NazwaKontrolera.php)
|- conf/
|- models/ (tu będą modele, do tej pory nic tam nie mam)
|- lib/
| +-- core/ - tu są moje pliki wykorzystywane w całej aplikacji
| +-- class.Dispatcher.php
| +-- class.Controller.php
|- templates/ - szablony Smarty
|
|- index.php
Oczywiście nie jest to finalny widok drzewa projektu. Ale nie to jest ważne.
Jak działa mój framework?index.php uruchamia Dispatcher, który parsuje URL. Jeżeli następuje zgłoszenie index.php/Akcja1/Parametr1/Parametr2/, to dispatcher załącza kontroler Akcja1, a następnie kontroler tej akcji wywołuje na sobie (w zasadzie na potomku) metodę Parametr1 z parametrem Parametr2.
Przykład: strona.pl/index.php/Uzytkownik/Pokaz/1234. Dispatcher przekaże kontrolę do kontrolera Uzytkownik. Ten natomiast włączy metodę Pokaz(1234);
Generalnie wygląda to właśnie tak. Z tego co czytałem, to chyba całkiem logiczne rozwiązanie. Oczywiście mogę się mylić...
PlikiPlik index.php
<?php
require_once('conf/conf.Core.php');
require_once('lib/core/Logger/class.Logger.php'); // to nas nie interesuje - zwyklu silnik logowania
require_once('lib/core/class.Dispatcher.php');
try
{
Logger::register('file:///tmp/log.core.txt');
$objDispatcher = new Dispatcher();
$objDispatcher->handle();
}
catch (Exception $exception)
{
echo $exception->getMessage(); }
?>
Plik class.Dispatcher.php
<?php
require_once('lib/core/class.Controller.php');
require_once('Smarty.class.php');
class Dispatcher
{
private $_strUrlParameters; // zawiera parametry url, np: dla strona.pl/index/a/b/c/d zawiera a/b/c/d/
private $_arrUrlParameters; // tutaj parametry juz są w tablicy
public function __construct()
{
$strUrlParameters = $_SERVER['PATH_INFO'];
$this->_strUrlParameters
= substr($strUrlParameters, 1
); }
public function handle()
{
$this->_parsePath(); // zapusuje parametry url do tablicy
$strControllerName = $this->_getControllerName(); // zwroci pierwszy elementy w tablicy parametrow (indeks w tablicy oczywiscie 0)
//Następnie tworzy kontroler na podstawie nazwy akcji i go uruchamia
$strControllerFile = 'actions/class.'.$this->_getControllerName().'Controller.php';
{
require_once($strControllerFile);
$strControllerClasName = $this->_getControllerName().'Controller';
$objController = new $strControllerClasName($this->_getParametersForController());
$objController->run();
$objSmarty = new Smarty();
$objSmarty->tempalte_dir = 'templates';
$objSmarty->compile_dir = 'var';
$objSmarty->assign($objController->getModelData()); // kontroler powinien zwrocic dane dla Smarty.
$objSmarty->display($objController->getView());
}
else
{
throw new Exception('Core, dispatcher: Action '.$strActionToRun.' does not exist');
}
}
private function _parsePath() // rozbija parametry url na tablice
{
$arrParameters = explode('/', $this->_strUrlParameters
); if($arrParameters[count($arrParameters) - 1] == '')
$this->_arrUrlParameters = $arrParameters;
}
private function _getControllerName() // zwraca nazwe akcji ktora nalezy wykonac - tutaj to pierwsza pozycja w tablicy zawierajacej parametry url
{
$strControllerName = $this->_arrUrlParameters[0];
if(strlen($strControllerName)) return $strControllerName;
else
throw new Exception('Core, dispatcher: There is not action to run');
}
private function _getParametersForController()
{
$intNumOfPathParameters = count($this->_arrUrlParameters
); $arrPrametersForController = array();
for($i = 1; $i < $intNumOfPathParameters; $i++)
$arrPrametersForController[] = $this->_arrUrlParameters[$i];
return $arrPrametersForController;
}
}
?>
Plik class.Controller.php
<?php
require_once('Collection/class.Collection.php');
class Controller
{
private $_strControllerName = null; // nazwa kontrolera - wyorzystuje sie do wybrania widoku i modelu
private $_arrControllerParameters = array(); // parametry dla kontrolera. jezeli url wygladal nastepujaco: strona.pl/index.php/Uzytkownik/Pokaz/12345 to zawiera tablice [Pokaz][1234]
protected $_strPageName; // tytul strony (dla htmla)
private $_objModelsCollection; // kolekcja modeli, dziala jak tablica asocjacyjna - malo wazne
private $_strView; // widok - tutaj to nazwa szablonu smarty
private $_arrViewVars = array();
public function __construct($arrParameters = null)
{
if(!isset($this->_strControllerName
)) // pobiera nazwe swojej klasy - wykorzystuje sie to do wyboru widoku oraz modelu {
if(!preg_match('/(.*)Controller/i', get_class
($this), $arrResults)) {
die('Controller: Can not get my class name'); }
$this->_strControllerName = $arrResults[1];
}
if(count($arrParameters)) $this->_arrControllerParameters = $arrParameters;
$this->_objModelsCollection = new Collection();
$this->_objModelsCollection->addItem($this->_strControllerName.'Model');
$this->_strView = $this->_toLowerCase($this->_strControllerName).'.tpl';
}
public function getModelData() // zwraca tablice dla Smarty->assign()
{
if(count($this->_arrViewVars
)) return $this->_arrViewVars;
}
public function getView() // zwraca szablon dla smarty->display();
{
return $this->_strView;
}
public function run() // sedno kontrolera. Jezeli przekazano dodatkowy parametr w url, np: strona.pl/index.php/Uzytkownik/Pokaz to wywola sie funkcja Pokaz, jezeli nie wywola funckje domysla, ktora defi
niuje juz potomek tej klasy
{
if($this->_getMethodToRun())
{
if(is_callable
(array($this, $this->_getMethodToRun
()), $this->_getParameterForMethod
())) call_user_func_array
(array($this, $this->_getMethodToRun
()), $this->_getParameterForMethod
()); }
else
$this->runDefaultMethod();
}
protected function _setPageTitle($strTitle)
{
$this->_strPageTitle = $strTitle;
$this->_setVar('TITLE', $strTitle);
}
protected function _setVar($strVarName, $mixValue)
{
$this->_arrViewVars[$strVarName] = $mixValue;
}
private function _toLowerCase($strString)
{
}
private function _getMethodToRun() // sprawdza parametr url, czy ma wykonac jakas metode - patrz wyzej
{
if(isset($this->_arrControllerParameters
)) {
if(method_exists($this, $this->_arrControllerParameters[0]))
return($this->_arrControllerParameters[0]);
}
return false;
}
private function _getParameterForMethod() // zwraca tablice parametrow dla metody ktora nalezy wykonac. Jezeli url wygldal:
strona.pl/index.php/uzytkownik/pokaz/12345 to wykona metode pokaz kontrolera uzytkownik przekazujac do pokaz() 12345.
{
if(isset($this->_arrControllerParameters
)) {
if(count($this->_arrControllerParameters
) > 1
) {
$intNumOfParameters = count($this->_arrControllerParameters
); $arrPrametersForMethod = array();
for($i = 1; $i < $intNumOfParameters; $i++)
$arrPrametersForMethod[] = $this->_arrControllerParameters[$i];
return $arrPrametersForMethod;
}
}
}
}
?>
Plik class.HelloController.php - przykładowy kontroler dla akcji Hello
<?php
// To jest przykladowy kontroler. Jak widac mozna wywolac strone tak: strona.pl/index.php/Hello/Hi albo Hello/Bye. Mozna przekazac argument: Hello/Bye/Adrian przez co akcja porzegna Adriana.
class HelloController extends Controller
{
public function hi()
{
$this->_setPageTitle('Witamy Cię');
$this->_setVar('HEADER', 'Witaj, to działa!');
}
public function bye($strName)
{
$this->_setPageTitle('Pa pa pa');
$this->_setVar('HEADER', 'Pa pa '.$strName.', do następnego razu!');
}
public function runDefaultMethod()
{
$this->hi();
}
}
?>
Będę Wam ogromnie wdzięczny za uwagi. Pozdrawiam serdecznie,
Adrian.
Ten post edytował Prph 4.03.2006, 19:40:41