Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Zalążek frameworka z MVC, Proszę, zweryfikujcie moje podejście
Prph
post
Post #1





Grupa: Zarejestrowani
Postów: 338
Pomógł: 2
Dołączył: 4.03.2006
Skąd: Łódź

Ostrzeżenie: (0%)
-----


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 projektu

Kod
|- 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ć...

Pliki
  1. Plik index.php
  2. <?php
  3. require_once('conf/conf.Core.php');
  4. require_once('lib/core/Logger/class.Logger.php'); // to nas nie interesuje - zwyklu silnik logowania
  5. require_once('lib/core/class.Dispatcher.php');
  6.  
  7. try
  8. {
  9. Logger::register('file:///tmp/log.core.txt');
  10.  
  11. $objDispatcher = new Dispatcher();
  12. $objDispatcher->handle();
  13. }
  14. catch (Exception $exception)
  15. {
  16. echo $exception->getMessage();
  17. }
  18.  
  19. ?>



  1.  Plik class.Dispatcher.php
  2.  
  3. <?php
  4.  
  5. require_once('lib/core/class.Controller.php');
  6. require_once('Smarty.class.php');
  7.  
  8. class Dispatcher
  9. {
  10.  
  11. private $_strUrlParameters; // zawiera parametry url, np: dla strona.pl/index/a/b/c/d zawiera a/b/c/d/
  12. private $_arrUrlParameters; // tutaj parametry juz są w tablicy 
  13.  
  14. public function __construct()
  15. {
  16. $strUrlParameters = $_SERVER['PATH_INFO'];
  17. $this->_strUrlParameters = substr($strUrlParameters, 1);
  18. }
  19.  
  20. public function handle()
  21. {
  22. $this->_parsePath(); // zapusuje parametry url do tablicy
  23.  
  24. $strControllerName = $this->_getControllerName(); // zwroci pierwszy elementy w tablicy parametrow (indeks w tablicy oczywiscie 0)
  25. //Następnie tworzy kontroler na podstawie nazwy akcji i go uruchamia
  26. $strControllerFile = 'actions/class.'.$this->_getControllerName().'Controller.php'; 
  27. if(file_exists($strControllerFile))
  28. {
  29. require_once($strControllerFile);
  30. $strControllerClasName = $this->_getControllerName().'Controller';
  31. $objController = new $strControllerClasName($this->_getParametersForController());
  32. $objController->run();
  33.  
  34. $objSmarty = new Smarty();
  35. $objSmarty->tempalte_dir = 'templates';
  36. $objSmarty->compile_dir = 'var';
  37.  
  38. $objSmarty->assign($objController->getModelData()); // kontroler powinien zwrocic dane dla Smarty.
  39. $objSmarty->display($objController->getView());
  40. }
  41. else
  42. {
  43. throw new Exception('Core, dispatcher: Action '.$strActionToRun.' does not exist');
  44. }
  45. }
  46.  
  47. private function _parsePath() // rozbija parametry url na tablice
  48. {
  49.  $arrParameters = explode('/', $this->_strUrlParameters);
  50.  if($arrParameters[count($arrParameters) - 1] == '')
  51.  array_pop($arrParameters);
  52.  
  53.  $this->_arrUrlParameters = $arrParameters;
  54. }
  55.  
  56. private function _getControllerName() // zwraca nazwe akcji ktora nalezy wykonac - tutaj to pierwsza pozycja w tablicy zawierajacej parametry url
  57. {
  58. $strControllerName = $this->_arrUrlParameters[0];
  59.  
  60. if(strlen($strControllerName))
  61. return $strControllerName;
  62. else
  63. throw new Exception('Core, dispatcher: There is not action to run');
  64. }
  65.  
  66. private function _getParametersForController()
  67. {
  68. $intNumOfPathParameters = count($this->_arrUrlParameters);
  69. $arrPrametersForController = array();
  70.  
  71. for($i = 1; $i < $intNumOfPathParameters; $i++)
  72. $arrPrametersForController[] = $this->_arrUrlParameters[$i];
  73.  
  74. return $arrPrametersForController;
  75. }
  76. }
  77.  
  78. ?>


  1. Plik class.Controller.php
  2. <?php
  3.  
  4. require_once('Collection/class.Collection.php');
  5.  
  6. class Controller
  7. {
  8. private $_strControllerName = null; // nazwa kontrolera - wyorzystuje sie do wybrania widoku i modelu
  9. private $_arrControllerParameters = array(); // parametry dla kontrolera. jezeli url wygladal nastepujaco: strona.pl/index.php/Uzytkownik/Pokaz/12345 to zawiera tablice [Pokaz][1234]
  10.  
  11. protected $_strPageName; // tytul strony (dla htmla)
  12.  
  13. private $_objModelsCollection; // kolekcja modeli, dziala jak tablica asocjacyjna - malo wazne
  14. private $_strView; // widok - tutaj to nazwa szablonu smarty
  15.  
  16. private $_arrViewVars = array();
  17.  
  18. public function __construct($arrParameters = null)
  19. {
  20. if(!isset($this->_strControllerName)) // pobiera nazwe swojej klasy - wykorzystuje sie to do wyboru widoku oraz modelu
  21. {
  22. $arrResults = array();
  23.  
  24. if(!preg_match('/(.*)Controller/i', get_class($this), $arrResults))
  25. {
  26. die('Controller: Can not get my class name');
  27. }
  28.  
  29. $this->_strControllerName = $arrResults[1];
  30. }
  31.  
  32. if(count($arrParameters))
  33. $this->_arrControllerParameters = $arrParameters;
  34.  
  35. $this->_objModelsCollection = new Collection();
  36.  
  37. $this->_objModelsCollection->addItem($this->_strControllerName.'Model');
  38. $this->_strView = $this->_toLowerCase($this->_strControllerName).'.tpl';
  39. }
  40.  
  41. public function getModelData() // zwraca tablice dla Smarty->assign()
  42. {
  43. if(count($this->_arrViewVars))
  44. return $this->_arrViewVars;
  45. }
  46.  
  47. public function getView() // zwraca szablon dla smarty->display();
  48. {
  49. return $this->_strView;
  50. }
  51.  
  52. 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
  53. {
  54. if($this->_getMethodToRun())
  55. {
  56. if(is_callable(array($this, $this->_getMethodToRun()), $this->_getParameterForMethod()))
  57. call_user_func_array(array($this, $this->_getMethodToRun()), $this->_getParameterForMethod());
  58. }
  59. else
  60. $this->runDefaultMethod();
  61. }
  62.  
  63. protected function _setPageTitle($strTitle)
  64. {
  65. $this->_strPageTitle = $strTitle;
  66. $this->_setVar('TITLE', $strTitle);
  67. }
  68.  
  69. protected function _setVar($strVarName, $mixValue)
  70. {
  71. $this->_arrViewVars[$strVarName] = $mixValue;
  72. }
  73.  
  74. private function _toLowerCase($strString)
  75. {
  76. return strtolower(substr($strString, 0, 1)).substr($strString, 1);
  77. }
  78.  
  79. private function _getMethodToRun() // sprawdza parametr url, czy ma wykonac jakas metode - patrz wyzej
  80. {
  81. if(isset($this->_arrControllerParameters))
  82. {
  83. if(method_exists($this, $this->_arrControllerParameters[0]))
  84. return($this->_arrControllerParameters[0]);
  85. }
  86. return false;
  87. }
  88.  
  89. 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.
  90. {
  91. if(isset($this->_arrControllerParameters))
  92. {
  93. if(count($this->_arrControllerParameters) > 1)
  94. {
  95. $intNumOfParameters = count($this->_arrControllerParameters);
  96. $arrPrametersForMethod = array();
  97.  
  98. for($i = 1; $i < $intNumOfParameters; $i++)
  99. $arrPrametersForMethod[] = $this->_arrControllerParameters[$i];
  100.  
  101. return $arrPrametersForMethod;
  102. }
  103. }
  104. }
  105. }
  106.  
  107. ?>


  1. Plik class.HelloController.php - przykładowy kontroler dla akcji Hello
  2. <?php
  3.  
  4. // 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.
  5.  
  6. class HelloController extends Controller
  7. {
  8. public function hi()
  9. {
  10. $this->_setPageTitle('Witamy Cię');
  11. $this->_setVar('HEADER', 'Witaj, to działa!');
  12. }
  13.  
  14. public function bye($strName)
  15. {
  16. $this->_setPageTitle('Pa pa pa');
  17. $this->_setVar('HEADER', 'Pa pa '.$strName.', do następnego razu!');
  18. }
  19.  
  20. public function runDefaultMethod()
  21. {
  22. $this->hi();
  23. }
  24. }
  25.  
  26. ?>


Będę Wam ogromnie wdzięczny za uwagi. Pozdrawiam serdecznie,
Adrian.

Ten post edytował Prph 4.03.2006, 19:40:41
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
matid
post
Post #2





Grupa: Zarejestrowani
Postów: 362
Pomógł: 0
Dołączył: 18.02.2004
Skąd: Knurów

Ostrzeżenie: (0%)
-----


U mnie to wygląda tak:

index.php:
W tym pliku tworzone są obiekty HttpRequest i HttpResponse (ktore następnie dodaje do kontenera HttpContext dla ułatwienia). Następnie tworzony jest obiekt FrontController i wywoływana jest jego metoda processRequest( iHttpRequest $Request, iHttpResponse $Response);
Oczywiście wszystkie metody tutaj zawarte można umieścić w obiekcie ApplicationBootstrap, albo czymś podobnym.

FrontController.class.php:
Metoda processRequest tworzy obiekt RequestHelper (patrz niżej). Po pobraniu od RequestHelpera polecenia, FrontController wywołuje metodę processCommand( iCommand $Command). Metoda ta tworzy nowy obiekt FilterManager. A następnie rejestruje w nim kolejne filtry, jednym z nich jest ExecutionFilter, który przyjmuje jako parametr polecenia do wykonania.

RequestHelper.class.php:
Klasa ta udostępnia metodę getCommand. Tworzony jest obiekt CommandFactory i RequestDispatcher. Wywoływana jest metoda CommandFactory->createCommand, która przyjmuje zwracane przez RequestDispatcher nazwę modułu i nazwę polecenia.

ExecutionFilter.class.php:
Klasa ta jest wykonywana przez FilterManager. Wywołuję na poleceniu (Command) metodę execute(), następnie tworzy obiekt ViewFactory, który na podstawie danych dostarczonych przez obiekt Command tworzy nowy widok. Operacje zawarte w obiekcie widoku są wykonywane, następnie dane zwrócone przez widok przekazywane są obiektowy HttpResponse.

Sama przykładowe polecenie wygląda tak:
  1. <?php
  2.  
  3. class IndexCommand extends BaseCommand
  4. {
  5. public function execute()
  6. {
  7. $Title = new String( 'Blank Index Page' );
  8. $Body = new String( 'Lorem ipsum <span class="red">dolor</span> sit amet, consectetuer adipiscing elit. Praesent in eros egestas velit congu
    e elementum. Morbi varius ante non nibh. Mauris urna ipsum, ultricies vitae, inte
    rdum egestas, molestie ac, mauris. Maecenas fermentum mollis arcu. Integer alique
    t nulla et velit. Suspendisse nibh urna, egestas faucibus, ullamcorper sit amet, 
    volutpat id, nibh. Ut arcu lorem, dignissim et, auctor et, suscipit sed, sapien. 
    Praesent sollicitudin, mauris in auctor adipiscing, diam orci ullamcorper turpis,
     non gravida augue mi vitae ante. Cras accumsan risus eget est. Maecenas iaculis,
     ligula at consequat adipiscing, ante urna eleifend velit, non tincidunt lacus ma
    uris at nulla. Nulla semper dictum felis. Fusce feugiat. Sed consequat mauris ut 
    libero gravida adipiscing. Aliquam et eros non tellus auctor euismod. Maecenas ti
    ncidunt massa nec dolor. Suspendisse potenti. Suspendisse tincidunt, tortor in po
    suere tempor, risus sapien pellentesque massa, eget ultrices ante nibh a eros. Et
    iam quis risus a turpis viverra mattis. Mauris a wisi.'
     );
  9. $Message = new Message( $Title, $Body );
  10.  
  11. $this->addModel( new String( 'Message' ), $Message );
  12.  
  13. $this->setViewHandle( new ViewHandle( new String( 'MessageView' ) ) );
  14. }
  15. }
  16.  
  17. ?>


A widok MessageView tak:
  1. <?php
  2.  
  3. class MessageView extends XHTMLView
  4. {
  5. public function execute()
  6. {
  7. $XML = new MessageXMLHelper( $this->getModel( new String( 'Message' ) ) );
  8.  
  9. $XSL = new DOMDocument;
  10. $XSL->load( OF_TEMPLATE_DIR . 'Message.xsl' );
  11.  
  12. $XSLTProcessor = new XSLTProcessor;
  13. $XSLTProcessor->importStylesheet( $XSL );
  14.  
  15. $XHTML = $XSLTProcessor->transformToDoc( $XML->execute() );
  16. $XHTML->formatOutput = true;
  17.  
  18. $this->addDocument( $XHTML );
  19. }
  20. }
  21.  
  22. ?>


Nie jest to może najprostsze rozwiązanie, ale myślę, że jest poprawne w duchu MVC.

Ten post edytował matid 5.03.2006, 10:52:21
Go to the top of the page
+Quote Post

Posty w temacie
- Prph   Zalążek frameworka z MVC   4.03.2006, 16:02:14
- - sf   Brak komentarzy, miales jakis pomysl, ale nie kazd...   4.03.2006, 18:07:56
- - matid   Cytat(sf @ 2006-03-04 18:07:56)Pozatym nie ba...   4.03.2006, 18:56:02
- - Prph   Diękują za uwagi. Co do die() - faktycznie nie p...   4.03.2006, 19:52:05
- - Fipaj   Ten pomysł z Dispatcherem mi się nie podoba. Czem...   4.03.2006, 19:58:25
- - Prph   Ale przeciez w praktyce to tak działa Ale chyba ...   4.03.2006, 20:26:36
- - matid   We wzorcu MVC kontroler to część aplikacji odpowie...   4.03.2006, 20:51:50
- - Ociu   Ja sobie podzieliłem to tak: Kodframework - Web ...   5.03.2006, 09:12:40
- - Prph   Teraz raz jeszcze przeczytalem Wprowadzenie do MVC...   5.03.2006, 10:14:11
- - hwao   W ogole brak Ci widoku w tym frameworku. Glupio j...   5.03.2006, 10:24:42
- - matid   U mnie to wygląda tak: index.php: W tym pliku two...   5.03.2006, 10:51:08
- - Prph   Witam Widzę, że niechętnie podchodzicie do mojej...   5.03.2006, 16:47:05
- - Ociu   Widze, że czekasz aż ktoś rzuci kodem.[PHP] pobier...   7.03.2006, 14:59:34
- - Prph   Przejrzałem kod Phienda, poczytałem dokumentacje, ...   9.03.2006, 23:24:05
- - hwao   czemu u Ciebie akcja wlacza Model i Widok? Pr...   10.03.2006, 06:48:18
- - Prph   Yyyyy? A to co ma włączać model i widok? Ludzie cz...   10.03.2006, 07:54:17
- - sf   Hyh, w ostatnim php Solutions jest fajnie napisane...   10.03.2006, 09:03:36
- - mike_mech   Cytat(Prph @ 2006-03-10 07:54:17)Yyyyy? A to ...   10.03.2006, 09:09:42
- - Martio   Cytat(mike_mech @ 2006-03-10 10:09:42)Hyh, w ...   10.03.2006, 12:28:05
- - hawk   Żaden nie trzymał się zasad wzorca MVC? Bo to zale...   10.03.2006, 14:51:59
- - Martio   CytatI dlaczego to, że jakiś framework nie trzyma ...   10.03.2006, 15:40:32
- - Vengeance   Akcja to po prostu część kontrolera. Ponieważ kont...   10.03.2006, 15:57:25
- - Martio   Dobra, ale jak obiektowo w takim bądź razie zakodo...   10.03.2006, 20:41:56
- - DeyV   W takim momencie okazuje, się, że wydzielenie z ko...   10.03.2006, 22:34:27
- - Prph   No proszę... Najpierw ktoś mówi, że akcja nie ster...   11.03.2006, 00:51:03
- - DeyV   Pamiętaj o jednej rzeczy. MVC nie mówi, jak ma b...   11.03.2006, 01:57:31
- - Prph   No dobrze, a teraz juz troche idac w przyszlosc......   11.03.2006, 10:42:13
- - eMartio   Zerknijcie na to. Czeskie, ale myślę, że dobre roz...   11.03.2006, 13:14:35
- - Martio   Chciałbym jeszcze powrócić do akcji. Powiedzmy, że...   11.03.2006, 14:04:49
- - aleksander   [PHP] pobierz, plaintext <?phpclass Kontroler...   11.03.2006, 14:39:03
- - Prph   Ha! A to całkiem ciekawe rozwiązanie. A jeszc...   11.03.2006, 18:01:49
- - hwao   zalezy jakie to dane... konfiguracja aplikacji de...   11.03.2006, 18:34:17
- - Prph   Cytat(hwao @ 2006-03-11 17:34:17)konfiguracja...   11.03.2006, 20:07:57
- - hwao   Cytat(Prph @ 2006-03-11 20:07:57)Cytat(hwao ...   11.03.2006, 21:11:28
- - hawk   Cytat(Martio @ 2006-03-11 14:04:49)[PHP] pobi...   11.03.2006, 22:46:08
- - eMartio   Postanowiłem odejść od wzorca MVC, realizując apli...   12.03.2006, 10:42:33
- - Ociu   Ja podzieliłem sobie kontroler na FrontController ...   12.03.2006, 11:35:35
- - eMartio   Analizując wszystkie wątki o MVC na tym forum zgłu...   13.03.2006, 14:17:03
- - Vengeance   "Czy możecie zrobić malutkie podsumowanie...   13.03.2006, 15:38:35
- - hawk   Cytat(Vengeance @ 2006-03-13 15:38:35)MVC mów...   13.03.2006, 16:27:47
- - aleksander   @eMartio: http://php.pl/wortal/artykuly/php/archit...   13.03.2006, 16:44:31
- - eMartio   Cytat(aleksander @ 2006-03-13 15:44:31)@eMart...   13.03.2006, 21:15:27
- - Prph   Przeczytajcie na końcu!. Jak rozwiąć Widok? W...   17.03.2006, 07:56:14


Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 26.11.2025 - 04:29