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 :
<?php
class ActionCollectioner implements Iterator
{
private $_aActions;
private $_bValidIterationPointer = true;
public function __construct(){
$this->_aActions
= array(); }
{
}
{
}
{
return key($this->_aActions
); }
{
if(next($this->_aActions
) === false) $this->_bValidIterationPointer = false;
else
$this->_bValidIterationPointer = true;
}
public function valid()
{
return $this->_bValidIterationPointer;
}
public function pushAct(DispatcherToken $oDispatcherToken)
{
if(!($oDispatcherToken instanceof DispatcherToken))
{
throw new ActionCollectionerException('Parameter You given to pushObj must be instance of DispatcherToken.');
}
}
}
?>
w Routerze umieściłem sobie pętlę foreach(), do której podaje mój ActionCollectioner:
<?php
class Router Implements IRouter
{
private $_sURI = null;
private $_aParams = null;
private $_sCtrlName = null;
private $_sActName = null;
private $_oDispatcher = null;
private $_oActionCollectioner = null;
public function __construct(Dispatcher $oDispatcher, ActionCollectioner $oActionCollectioner)
{
$this->_sURI = $this->_formatQuery();
$this->_oDispatcher = $oDispatcher;
$this->_oActionCollectioner = $oActionCollectioner;
}
private function _formatQuery(){
return substr($_SERVER['REQUEST_URI'],strlen($_SERVER['SCRIPT_NAME'])-9
,strlen($_SERVER['REQUEST_URI'])); }
public function route()
{
if (strstr($this->_sURI
, '?')) { $this->_sURI
= substr($this->_sURI
, 0
, strpos($this->_sURI
, '?')); }
$this->_aParams
= explode('/', trim($this->_sURI
, '/')); $this->_sCtrlName = $this->_aParams[0];
$this->_sActName
= isset($this->_aParams
[1
]) ?
$this->_aParams
[1
] : null;
if (!strlen($this->_sCtrlName
)) {
$this->_sCtrlName = _DEFAULT_CTRL_NAME;
$this->_sActName = _DEFAULT_ACT_NAME;
}
for ($i=2; $i<sizeof($this->_aParams); $i=$i+2) {
$aActParams[$this->_aParams
[$i]] = isset($this->_aParams
[$i+1
]) ?
$this->_aParams
[$i+1
] : null; }
$oCurrentAction = new DispatcherToken($this->_sCtrlName, $this->_sActName, $aActParams);
//----------------------------------------------------------tutaj klade pierwsza akcje do mojego kontenera
$this->_oActionCollectioner->pushAct($oCurrentAction);
foreach ($this->_oActionCollectioner as $iKey => $oActionToken)
{
$oCurrentAction = $oActionToken;
if (!$this->_oDispatcher->isDispatchable($oCurrentAction)) {
$oCurrentAction = new DispatcherToken('Error404', _DEFAULT_ACT_NAME, $aActParams);
}
if (!$this->_oDispatcher->isDispatchable($oCurrentAction)) {
throw new RouterException('Request could not be mapped to a route and Error404 Controller has not been crea
ted.');
}
$this->_oDispatcher->executeAction($oCurrentAction);
}
return $oCurrentAction;
}
}
?>
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:
<?php
class DoSmth extends Controller
{
public function _index(){
$oView = $this->getView('DoSmth');
$oModel = $this->getModel('DoSmth');
$oView->setAttribute('all',$oModel->showMeAll());
$oView->setAttribute('imie', $this->imie);
$this->pushNextAction('SaveNews');
$this->pushNextAction('Logout');
$this->pushNextAction('Index','ShowNews', array('Param1'=>'costam')); return($oView);
}
?>
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:
<?php
abstract class Model
{
protected $_oDataSource;
protected
function setDataSource
($sSourceClassName,array $aParameters=array(),$sPath = null) {
if(!NyssSystem::getLibraryPath($sSourceClassName)){
if(!NyssSystem::fileIsReadable($sPath))
throw new ModelException('File '.$sPath.' is not readable');
require_once($sSourceFile);
if(!class_exists($sSourceClassName))
throw new ModelException('Can not create DataSource, class does not exist');
$this->_oDataSource = new $sSourceClassName($aParameters);
}
else $this->_oDataSource = new $sSourceClassName($aParameters);
}
protected function getDataSourceParameters()
{
require_once(_DIR_APPLICATION.'_configure.php');
return($aDataSourceParameters);
}
}
}
?>
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 :
<?php
class DoSmthModel extends Model
{
public function __construct()
{
$this->setDataSource('DatabaseMySQL',$this->getDataSourceParameters());
}
public function showMeAll()
{
$oMysql = $this->_oDataSource;
$oMysql->query('SELECT * from costam WHERE option_id=1');
return($oMysql->fetch());
}
}
?>
i myśle, że to jest rozwiązanie optymalne, bo jak zeche korzystać z pliku, a nie z bazy to robie:
<?php
$this->setDataSource('FileReader',$this->getDataSourceParameters());
?>
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