Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Framework, kilka ciewawych(może nie?) sugestii
envp
post
Post #1





Grupa: Zarejestrowani
Postów: 359
Pomógł: 1
Dołączył: 16.04.2006
Skąd: Łódź

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


Witam, piszę sobie frameworka. Na razie jest dosyć 'mały' i niedopracowany. Wszystko oparte jest na MVC. No ale dobra do rzeczy. Przemyślałem kilka spraw i wymyśliłem kilka ciekawych rzeczy, a mianowicie:

1) Forwardowanie akcji.

Forwardowanie akcji, jest bardzo przydatną rzeczą w każdym frameworku, ale nie spotkałem się jeszcze z forwardowaniem na kilka akcji 'z góry', a myśle że to jest dośc przydatne, bo możemy poprzez jedną akcje zaplanować co i jak sie stanie. Wiadomo, że jeśli mamy akcje 'dodajNewsa' to rzeby zrobić 'dodajNewsaiPokaz' musimy tworzyć nową akcję, tak samo 'dodajiWyloguj' , a co bedzie jak zrobimy 'dodajWylogujPrzejdznaStroneGlowna' ? to jest tworzenie akcji, które już mamy(np. wyloguj) i dodawanie do nich jednej linijki (stare proceduralne kopiowanie kodu?). A jak mamy forwarodwanie na kilka akcji z 'góry' to jest super bo tworzymy sobie tylko 'Dodaj' 'Wyswietl' 'Wyloguj' 'PrzejdzNaStroneGlowna'. (Może przykład wyłuskany, ale nie umiem na szbyko wymyśleć innego). Ja rozwiązałem to sobie w taki sposób, że mam klase 'ActionCollectioner', która implementuje sobie Iterator :

  1. <?php
  2. class ActionCollectioner implements Iterator
  3. {
  4.  
  5. private $_aActions;
  6. private $_bValidIterationPointer = true;
  7.  
  8. public function __construct(){
  9. $this->_aActions = array();
  10. }
  11.  
  12. public function rewind()
  13. {
  14. reset($this->_aActions);
  15. }
  16.  
  17. public function current()
  18. {
  19. return current($this->_aActions);
  20. }
  21.  
  22. public function key()
  23. {
  24. return key($this->_aActions);
  25. }
  26.  
  27. public function next()
  28. {
  29. if(next($this->_aActions) === false)
  30. $this->_bValidIterationPointer = false;
  31. else
  32. $this->_bValidIterationPointer = true;
  33. }
  34.  
  35. public function valid()
  36. {
  37. return $this->_bValidIterationPointer;
  38. }
  39.  
  40. public function pushAct(DispatcherToken $oDispatcherToken)
  41. {
  42. if(!($oDispatcherToken instanceof DispatcherToken))
  43. {
  44. throw new ActionCollectionerException('Parameter You given to pushObj must be instance of DispatcherToken.');
  45. }
  46. array_push($this->_aActions, $oDispatcherToken);
  47. }
  48. }
  49. ?>


w Routerze umieściłem sobie pętlę foreach(), do której podaje mój ActionCollectioner:

  1. <?php
  2. class Router Implements IRouter
  3. {
  4.  
  5. private $_sURI = null;
  6. private $_aParams = null;
  7. private $_sCtrlName = null;
  8. private $_sActName = null;
  9. private $_oDispatcher = null;
  10. private $_oActionCollectioner = null;
  11.  
  12. public function __construct(Dispatcher $oDispatcher, ActionCollectioner $oActionCollectioner)
  13. {
  14. $this->_sURI = $this->_formatQuery();
  15. $this->_oDispatcher = $oDispatcher;
  16. $this->_oActionCollectioner = $oActionCollectioner;
  17. }
  18.  
  19. private function _formatQuery(){
  20. return substr($_SERVER['REQUEST_URI'],strlen($_SERVER['SCRIPT_NAME'])-9,strlen($_SERVER['REQUEST_URI']));
  21. }
  22.  
  23. public function route()
  24. {
  25.  
  26. if (strstr($this->_sURI, '?')) {
  27. $this->_sURI = substr($this->_sURI, 0, strpos($this->_sURI, '?'));
  28. }
  29. $this->_aParams = explode('/', trim($this->_sURI, '/'));
  30. $this->_sCtrlName = $this->_aParams[0];
  31. $this->_sActName = isset($this->_aParams[1]) ? $this->_aParams[1] : null;
  32.  
  33. if (!strlen($this->_sCtrlName))
  34. {
  35. $this->_sCtrlName = _DEFAULT_CTRL_NAME;
  36. $this->_sActName = _DEFAULT_ACT_NAME;
  37. }
  38.  
  39.  $aActParams = array();
  40.  for ($i=2; $i<sizeof($this->_aParams); $i=$i+2) {
  41.  $aActParams[$this->_aParams[$i]] = isset($this->_aParams[$i+1]) ? $this->_aParams[$i+1] : null;
  42.  }
  43.  
  44.  $oCurrentAction = new DispatcherToken($this->_sCtrlName, $this->_sActName, $aActParams);
  45.  
  46. //----------------------------------------------------------tutaj klade pierwsza akcje do mojego kontenera
  47.  
  48.  $this->_oActionCollectioner->pushAct($oCurrentAction); 
  49.  
  50.  foreach ($this->_oActionCollectioner as $iKey => $oActionToken)
  51.  {
  52.  $oCurrentAction = $oActionToken;
  53.  if (!$this->_oDispatcher->isDispatchable($oCurrentAction)) {
  54.  $oCurrentAction = new DispatcherToken('Error404', _DEFAULT_ACT_NAME, $aActParams);
  55.  }
  56.  
  57.  if (!$this->_oDispatcher->isDispatchable($oCurrentAction)) {
  58.  throw new RouterException('Request could not be mapped to a route and Error404 Controller has not been crea
    ted.'
    );
  59.  }
  60.  $this->_oDispatcher->executeAction($oCurrentAction);
  61.  
  62.  }
  63.  return $oCurrentAction;
  64.  }
  65.  
  66.  
  67. }
  68. ?>


Dispatcher odpala kontroller akcji, a w nim możemy skorzystać z metody rodzica pushNextAction, która odwołuje sie do FrontController'a (który jedyny we frameworku jest singletonem) trzymającego dostęp do ActionCollectioner:

  1. <?php
  2. class DoSmth extends Controller
  3. {
  4.  
  5.  
  6. public function _index(){
  7.  
  8.  
  9. $oView = $this->getView('DoSmth');
  10. $oModel = $this->getModel('DoSmth');
  11.  
  12. $oView->setAttribute('all',$oModel->showMeAll());
  13. $oView->setAttribute('imie', $this->imie);
  14.  
  15. $this->pushNextAction('SaveNews');
  16. $this->pushNextAction('Logout');
  17. $this->pushNextAction('Index','ShowNews', array('Param1'=>'costam'));
  18. return($oView);
  19. }
  20. ?>


oczywiście pokusiło mnie żeby sprawdzić, co się dzieje jeśli przekieruje akcje z widowkiem, na akcje z widokiem - i co wyświetla sie tylko pierwsza akcja z widowkiem - czemu - zastosowanie funkcji require_once() w systemie, który przetwarza widok (pokazuje tylko raz, a że mam Template i i subTemplate - czyli główny szablon www i 'srodkowa tresc' zasysa raz Main.php i już dalej nie). Dodam, że korzystam z szablonów php. Jedyne co pozostaje to stworzyć MAX_FORWARDS, aby akcje bez widoku sie nie zapętlały.

2) Kolejna sprawa - Model.
Zauważyłem, że w niektórych frameworkach Baze danych rejestruje się we FrontControllerze... Pyanie po co, to chyba gryzie się z ideologią MVC (może jest wygodne dla programisty, który tworzy aplikacje na tym frameworku, ale mało elastyczne). Ja postanowiłem problem rozwiązać w inny sposób, a mianowicie:

mam rodzica dla każdego modelu:

  1. <?php
  2. abstract class Model
  3. {
  4. protected $_oDataSource;
  5.  
  6. protected function setDataSource($sSourceClassName,array $aParameters=array(),$sPath = null)
  7. {
  8. if(!NyssSystem::getLibraryPath($sSourceClassName)){
  9. if(!NyssSystem::fileIsReadable($sPath))
  10. throw new ModelException('File '.$sPath.' is not readable');
  11. require_once($sSourceFile);
  12.  
  13. if(!class_exists($sSourceClassName))
  14. throw new ModelException('Can not create DataSource, class does not exist');
  15. $this->_oDataSource = new $sSourceClassName($aParameters);
  16. }
  17.  else $this->_oDataSource = new $sSourceClassName($aParameters);
  18. }
  19.  
  20. protected function getDataSourceParameters()
  21. {
  22.  require_once(_DIR_APPLICATION.'_configure.php');
  23.  return($aDataSourceParameters);
  24. }
  25.  
  26.  
  27.  
  28.  
  29.  
  30. }
  31.  
  32. }
  33. ?>


dodam iż funkcja setDataSource wygląda takowo iż używam magicznego __autoload() więc nie trzeba podawać ścieżki do DataSource, aby działało - wystarczy umieścić go w katalogu core, który na początku jest skanowany (proszę mi nie mówić, że spowalnia to aplikacje, bo czas wykonania różni sie o okolo 0.005 s, a jest bardzo wygodne) No dobra, ale do rzeczy teraz mam model :

  1. <?php
  2. class DoSmthModel extends Model
  3. {
  4.  
  5.  public function __construct()
  6.  {
  7.  $this->setDataSource('DatabaseMySQL',$this->getDataSourceParameters());
  8.  }
  9.  
  10.  public function showMeAll()
  11.  {
  12. $oMysql = $this->_oDataSource;
  13.  
  14. $oMysql->query('SELECT * from costam WHERE option_id=1');
  15.  
  16. return($oMysql->fetch());
  17.  }
  18.  
  19.  
  20. }
  21. ?>


i myśle, że to jest rozwiązanie optymalne, bo jak zeche korzystać z pliku, a nie z bazy to robie:
  1. <?php
  2. $this->setDataSource('FileReader',$this->getDataSourceParameters());
  3. ?>


No tak więc to by było na tyle, proszę o komentarze do moich pomysłów i z góry dziękuję za pomoc. Pozdrawiam... Kamil
Go to the top of the page
+Quote Post

Posty w temacie


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: 15.09.2025 - 03:27