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 (1 - 8)
Prph
post
Post #2





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

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


Witam,

Ad 2.

IMHO, model nie powinien byc dziedziczony. Na pewno nie z klasy Model.
Dlatego, ze 2 modele moga tak znaczaco sie roznic, ze nie ma mniejmniejszego sensu. I co wazne - model wie skad powibiera dane. Wie ze jest to baza danych mysql na serwerze tym i tym. Taka ideologia mvc.

Oczywiscie robic w kazdym modelu nowy obiekt bazy danych, wczytywanie konfiguracji dla polaczenia z baza itp jest bardzo niewygodne. Mozna zrobic dla ulatwienia Model_MySQL i z niego dziedziczyc.

Adrian.
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%)
-----


  1. <?php
  2. $this->setDataSource('DatabaseMySQL',$this->getDataSourceParameters());
  3. ?>


mój model wie skąd czytać...
Go to the top of the page
+Quote Post
NuLL
post
Post #4





Grupa: Zarejestrowani
Postów: 2 262
Pomógł: 21
Dołączył: 3.05.2004
Skąd: Sopot, Krakow, W-wa

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


Cytat
Mozna zrobic dla ulatwienia Model_MySQL i z niego dziedziczyc.

I co questionmark.gif Bedzie przepisywal wszystkie modele kiedy bedzie chcial jechac na Postgresie questionmark.gif snitch.gif laugh.gif


--------------------
Javascript, Coffeescript, Node.js, Mongo, CouchDb, chmury, workery & inne bajery - zycie jest zbyt krotkie aby miec nudna prace :)
Go to the top of the page
+Quote Post
Cysiaczek
post
Post #5





Grupa: Moderatorzy
Postów: 4 465
Pomógł: 137
Dołączył: 26.03.2004
Skąd: Gorzów Wlkp.




Popieram NuLL'a - zrób większą abstrakcję do źródeł danych.

Pozdrawiam


--------------------
To think for yourself you must question authority and
learn how to put yourself in a state of vulnerable, open-mindedness;
chaotic, confused, vulnerability, to inform yourself.
Think for yourself. Question authority.
Go to the top of the page
+Quote Post
mariuszn3
post
Post #6





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
Prph
post
Post #7





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

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


Cytat(NuLL @ 28.08.2006, 23:39:55 ) *
I co questionmark.gif Bedzie przepisywal wszystkie modele kiedy bedzie chcial jechac na Postgresie questionmark.gif snitch.gif laugh.gif


Kto jak kto, ale Ty chyba wiesz, ze SQL postgre i SQL MySQL jednak sie roznia...
Wiec jak napisze Model ktory korzysta z mysql, a pozniej musi zmienic baze, to najpierw zmieni zapytania :]

Adrian.
Go to the top of the page
+Quote Post
envp
post
Post #8





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
splatch
post
Post #9





Grupa: Zarejestrowani
Postów: 487
Pomógł: 7
Dołączył: 7.01.2004
Skąd: Warszawa

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


Modele proponuję załatwić przez interfejsy + dao.

Tzn.
Interfejsy Author, AuthorDAO.
Metody Author - setName, getName, setId, getId, save
Metody AuthorDAO - getAuthorByName, getAuthorById, getAll

Do tego klasy implementujące ten interfejs:
SQLAuthorDAO oraz SQLAuthor z implementacją opartą na PDO.

Tworzenie modeli możesz załatwić w kontrolerze. W ten sposób, możesz dodać model obsługiwany przez inną technologię (np dane z XML a nie z bazy).


--------------------
Łukasz Dywicki
Independent Java and open source software consultant.
Blog - Java, OSGi, integracja oprogramowania..
Go to the top of the page
+Quote Post

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

 



RSS Aktualny czas: 20.08.2025 - 22:35