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
 
Start new topic
Odpowiedzi
mariuszn3
post
Post #2





Grupa: Zarejestrowani
Postów: 352
Pomógł: 0
Dołączył: 22.01.2006

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


Za poprzednikami.. zapytania do bazy danych powinieneś przynajmniej wydzielić do osobnej klasy.
Poza tym tak jakoś niechlujnie to opisałeś masa błędów stylistycznych, literówek, anglojęzycznych wstawek (kiedy istnieją polskie odpowiedniki).. nie wiem może dla wielu jest to trendi dżezi.. ale na pewno to ogranicza czytelność i trudniej jest się połapać w tym co chcesz przekazać.. wszystko zależy od tego jaki był cel tej publikacji.
Jedna drobna rzecz.. jaki ma cel taki kod:
Kod
public function pushAct(DispatcherToken $oDispatcherToken)
  {
    if(!($oDispatcherToken instanceof DispatcherToken))
    {
      throw new ActionCollectionerException('Parameter You given to pushObj must be instance of DispatcherToken.');
    }
    array_push($this->_aActions, $oDispatcherToken);
  }

Przecież jeśli $oDispatcherToken nie będzie instancją DispatcherToken php na wstępie wywali Ci fatalny błąd. W żadnym wypadku wyjątek nie zostanie wyrzucony.
Go to the top of the page
+Quote Post
envp
post
Post #3





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

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


Cytat(mariuszn3 @ 29.08.2006, 11:39:00 ) *
Za poprzednikami.. zapytania do bazy danych powinieneś przynajmniej wydzielić do osobnej klasy.
Poza tym tak jakoś niechlujnie to opisałeś masa błędów stylistycznych, literówek, anglojęzycznych wstawek (kiedy istnieją polskie odpowiedniki).. nie wiem może dla wielu jest to trendi dżezi.. ale na pewno to ogranicza czytelność i trudniej jest się połapać w tym co chcesz przekazać.. wszystko zależy od tego jaki był cel tej publikacji.
Jedna drobna rzecz.. jaki ma cel taki kod...


ok ten fragment kodu jest zbędny.

A co do opisu - pisane na szybko - to nie miał być artykuł.

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: 13.10.2025 - 01:39