Freaky thought! But would it ever be needed ?Originally Posted by Ezku
| SitePoint Sponsor |
Freaky thought! But would it ever be needed ?Originally Posted by Ezku





Just include it as a procedural snippet at the bottom of the file which you put the Request class in. It will only ever be run once, because if you try to include the file twice, you will get "Request class already defined" errors.Originally Posted by kyberfabrikken
YANGI doesn't seem to be a priority in this threadOriginally Posted by kyberfabrikken
Douglas
Hello World




Suddenly, my sarcasm-scanner activated, emitting a faint *blip*.Originally Posted by kyberfabrikken
![]()
I just had the idea - wouldn't it make sense to put the errorlogger in the Response-object ? In that case, we don't need the Context-object.Originally Posted by kyberfabrikken
(Well, actually I was reading the wact sources, and they do this.)
Actually I weren't. I can't think of a situation where you would need that option. Except maybe that we could use it to apply some lazy-loading.Originally Posted by Ezku




There's certain logic to that. Trash the Context for now, I don't think we want to introduce it needlessly.Originally Posted by kyberfabrikken
I have to admit I haven't thought it through. Could be about how you think of dispatching to an ApplicationController.I can't think of a situation where you would need that option.
Considering lazy loading; WACT had this nice idea of triggering events to invoke Delegates that wrap an object. Something along the lines of this:Except maybe that we could use it to apply some lazy-loading.The trick is that if you pass the Delegate a Handle object, the actual class can be lazy-loaded nicely upon triggering the event. Don't know if this is cool or YAGNI, but I couldn't resist when you brought it up.PHP Code:/**
* Calls a method on an object upon invocation
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 12, 2005
*/
class Delegate implements IDelegate
{
protected $subordinate = NULL;
protected $method = NULL;
public function __construct($subordinate, $method)
{
$this->subordinate = $subordinate;
$this->method = $method;
}
public function invoke($args = NULL)
{
$callback = array($this->subordinate, $this->method);
return call_user_func_array($callback, (array) $args);
}
}
class EventHandler
{
/**
* @var array 2-dimensional IDelegate map
*/
protected $listeners = array();
/**
* Register listener for event
* @param object IDelegate
*/
public function register($event, IDelegate $delegate)
{
$this->listeners[$event][] = $delegate;
}
/**
* Trigger event listeners
* @param string event
*/
public function trigger($event)
{
if (isset($this->listeners[$event]) && is_array($this->listeners[$event]))
{
foreach($this->listeners[$event] as $delegate)
{
$delegate->invoke();
}
}
}
}
![]()

I think we should rename the Input Controller to something more meaningful then...perhaps InputSanitizer?Originally Posted by Ezku




I believe I've already expressed my wish to rename the InputController. Sanitizer won't quite do, but I'd be glad to have further suggestions!Originally Posted by Overunner
I think it's both cool and YAGNI. Form a FormController, the overhead of creating a few Handlers, that aren't going to execute is dimminishingly small. I actually think it would add up to introducing a lazy-load mechanism. I believe we came to the same conclusion about RequestMappers in the frontcontroller package.Originally Posted by Ezku
I agree that it should be renamed. It's the only class named Controller, which doesn't implement IHandler. I'm not keen on InputSanitizer. Perhaps InputProcessor ?Originally Posted by Ezku




That's a good suggestion.Originally Posted by kyberfabrikken
Regarding Context: wouldn't it be a nice place to store Session objects and the like? I was about to start stuffing Session, Cookie etc. to the Request when I realized that Context would probably be where they really belong. Context could also be used as a messaging service between layers (along the lines of $context->data->set('errors', $logger->getMessages());). It would prevent cluttering both Request and Response. Is this A Bad Idea (TM)?
I recieved a PM from tharos, but since I think it's relevant to the discussion, I'll reply here.
That's a good idea. There were a brief suggestion by me and ezku to create a factory-class which would do something like this. We just haven't come to that yet.Originally Posted by tharos
I reckon we could rely on the ConfigReader classes from the skeleton-thread.
Basically, you would want to substitute the ServerPage("page/formdone.php") with an Action that handles the submit. It could be along the lines of :Originally Posted by tharos
PHP Code:class MySubmitHandler
{
var $redirect = "?page=afterform"; // or whatever
function execute(&$request, &$response) {
$model =& new Model();
$model->import($request);
$response->setRedirect($this->redirect);
}
}
class MyForm extends FormController
{
function MyForm() {
parent::FormController(
new ServerPage("page/forminit.php"), // handler to handle state=init
new ServerPage("page/forminvalid.php"), // handler to handle state=invalid
new MySubmitHandler() // handler to handle state=valid
);
// rules to be met in order to become valid
$this->addRule(new Rule_Required("foo"));
$this->addRule(new Rule_Email("foo"));
}
}
Sorry. I stick with php4. But some of the classes have been converted from Ezku's posts, which were php5. I'm sure that once we get things a bit more consolidated, somebody will port it.Originally Posted by tharos
Yes and no. I'm a bit afraid of the context-object as I mentioned earlier. Session stuff definately doesn't belong in the request object IMHO. I like to see session as sort of persistence and thus clearly belonging to the Model-layer. Cookies might belong in the Request-object - I'm not sure about that.Originally Posted by Ezku
Yes, but I think this is where we get very close to MagicContainer. I'd rather have that Controllers use the Model-layer to communicate with each-other if they need to.Originally Posted by Ezku
I won't rule out a Context as a ServiceLocator alltogether, but I'd rather wait to implement it when we actually need it. And I don't think we do quite yet.
flowcontroller0.4.zip
Here's a minor update to the code, which removes the context-object again, and places the errorLogger in the respose-object.
I also renamed InputController to InputProcessor as agreed.
I have updated tests and added a test for DataSpace. Still need to port the tests for rules (if we decide to stay with the Logger ...)
Lastly I added magic-fix back to the Request code in the way that DougBTX suggested (copy&paste from WACT)
About the naming. Since InputController have been renamed to InputProcessor, maybe we should rename FlowController to InputController ? Would that make sense ?



This is less a reply to kyberfabrikken, who's probably seen WACT stuff before, if only by way of explanations in Selkirk's posts. Newer readers may have a greater interest.Originally Posted by kyberfabrikken
With WACT, it gets better than that. The handlers inside delegates need not be instantiated objects, but so-called 'Handles'. If the particular Delegate wrapping that Handle is invoked, the Handle is instantiated as the handler object.
I'm in awe of Selkirk for creating this most elegant mechanism!
Zealotry is contingent upon 100 posts and addiction 200?




The Context could be implemented in a more strict manner, providing getters and setters for pre-defined specific objects (Request, Response, Messages, User, Session, etc), not just any key/value pair. In that case, a MagicContainer would not be a bad place to start; let it eat everything and later on, when things clear up (what can and what can't be in it), one could (and should) refactor it to a more strict context class.Originally Posted by kyberfabrikken




I wouldn't object (no pun intended) to that. The fact is we do have quite a load of objects to be passed around in the Handlers. They can't all go in Request/Response.Originally Posted by dbevfat
auricle: My thoughts exactly. As for my relating code above, I was just guessing based on the description at WACT. It's probably quite different in reality.
They could go into the request, they do in rails. The logic of such an approach depends on how you want to define the term "request"; the narrow definition would include only what's in the POST, GET and the URI itself, a broader definition would include Cookies, Sessions, etc. A possiblity would be to rename the object to something more inclusive, like Context, and within it place the Request, Cookies, Sessions, etc.. passing it around in the handlers.Originally Posted by Ezku




Wouldn't that effectively transform Request into a less organized Context?Originally Posted by 33degrees
Isn't that exactly what we were talking about? Or do you mean passing around Context and Response, as opposed to just Context? What's the point in that?A possiblity would be to rename the object to something more inclusive, like Context, and within it place the Request, Cookies, Sessions, etc.. passing it around in the handlers.
I'm starting to believe we really need a Context container that collects data together and encapsulates common data used throughout the system (Encapsulate Context, Allan Kelly).
There's some sort of logic in Context=>input and Response=>output.Originally Posted by Ezku
The thing which I don't like about having a Context-object is that it makes it harder for newcomers to understand the codebase. The benefits of such a container lies in the scalability of the system, but it's at the price of simplicity. Depending on the system you are building with it this may be good or bad.




How about an InputContext with an OutputContext? InputContext with, say, Request and Session and OutputContext with Response, Logger and whatnot. If you browsed the linked article, there's talk about separating the Context object into bits like this. I think it'd be pretty logical, but does that pose the same problem with understandability? I'd concern that pretty minuscule however. Does it radically differ from having the necessary stuff embedded in Request/Response?Originally Posted by kyberfabrikken
Yes, exactly.Originally Posted by kyberfabrikken
To be honest, I don't think that's much of an issue, considering there are other parts of the codebase that are much more complex. It seems to me that the main goal so far has been flexibility, rather than simplicity...Originally Posted by kyberfabrikken




Does anyone like this idea? I'd like to try it.Originally Posted by Ezku
Context, I understand, is already generally agreed on? Assuming I refactor my code to Context+Response, where do Logger or the error messages go?
Last edited by Ezku; Jul 14, 2005 at 17:03.
That could work, and it would provide a place for logging and errors, as you mention.Originally Posted by Ezku
Originally Posted by Ezku
Now we're just changing the names aren't we ? I mean ... Context implies a global span, which would include both input and output. If we are having seperate objects for in/out, why not keep the names Request/Response ?Originally Posted by 33degrees
I'd want to have either one Context object or a Request + a Response.
Since they are output, I'd say in the Response.Originally Posted by Ezku




Alright, how about if the current Request and Response would be stored at $request->http and $response->http respectively? There's a nice logic and it allows for a clean context object.Originally Posted by kyberfabrikken
Off Topic:
I should really learn to think before posting![]()
Why the sudden loss in interest?![]()
Last edited by Ezku; Jul 15, 2005 at 07:12.




Here's some code.PHP Code:/**
* Context containing Request-related objects
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 15, 2005
*/
class Request
{
/**
* @var object HttpRequest
*/
protected $http = NULL;
/**
* @var object FILES DataSpace
*/
protected $files = NULL;
/**
* @var object COOKIE DataSpace
*/
protected $cookie = NULL;
/**
* @var object SERVER DataSpace
*/
protected $server = NULL;
public function __construct()
{
$this->http = new HttpRequest;
$this->files = new DataSpace($_FILES);
$this->cookie = new DataSpace($_COOKIE);
$this->server = new DataSpace($_SERVER);
}
public function & __get($name)
{
return isset($this->$name) ? $this->$name : NULL;
}
}
PHP Code:/**
* HTTP request data: GET and POST
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 15, 2005
*/
class HttpRequest extends DataSpace
{
/**
* Request method is GET
*/
const METHOD_GET = 'GET';
/**
* Request method is POST
*/
const METHOD_POST = 'POST';
/**
* @var int Request method
*/
protected $method = NULL;
/**
* @var object GET DataSpace
*/
public $GET = NULL;
/**
* @var object POST DataSpace
*/
public $POST = NULL;
/**
* Request constructor
* @param int request method, optional
*/
public function __construct()
{
$this->method = (strcasecmp($_SERVER['REQUEST_METHOD'], 'POST') == 0) ? self::METHOD_POST : self::METHOD_GET;
$this->data = $_REQUEST;
$this->GET = new DataSpace($_GET);
$this->POST = new DataSpace($_POST);
}
public function getMethod()
{
return $this->method;
}
public function isPost()
{
return (self::METHOD_POST == $this->method);
}
/**
* Cleans arrays ruined by MagicQuotes=On.
*/
static public function fixMagicQuotes($aList, $aIsTopLevel = true)
{
$gpcList = array();
$isMagic = self::$magic;
foreach ($aList as $key => $value)
{
if (is_array($value))
{
$decodedKey = ($isMagic && !$aIsTopLevel)?stripslashes($key):$key;
$decodedValue = self::fixMagicQuotes($value, false);
}
else
{
$decodedKey = stripslashes($key);
$decodedValue = ($isMagic)?stripslashes($value):$value;
}
$gpcList[$decodedKey] = $decodedValue;
}
return $gpcList;
}
static public $magic = NULL;
}
/**
* Fix magicquotes
*/
if (HttpRequest::$magic = get_magic_quotes_gpc())
{
$_REQUEST = HttpRequest::fixMagicQuotes($_REQUEST);
$_POST = HttpRequest::fixMagicQuotes($_POST);
$_GET = HttpRequest::fixMagicQuotes($_GET);
$_COOKIE = HttpRequest::fixMagicQuotes($_COOKIE);
}
PHP Code:/**
* Context containing Response-related objects
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 15, 2005
*/
class Response
{
/**
* @var object HttpResponse
*/
protected $http = NULL;
/**
* @var object LogManager
*/
protected $logs = NULL;
public function __construct()
{
$this->http = new HttpResponse;
$this->logs = new LogManager;
}
public function & __get($name)
{
return isset($this->$name) ? $this->$name : NULL;
}
}
PHP Code:/**
* HTTP response data: headers, status, redirection, content.
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 15, 2005
*/
class HttpResponse
{
protected $headers = array();
protected $redirect = NULL;
protected $status = NULL;
protected $content = NULL;
public function setHeader($key, $value=NULL) { $this->headers[$key] = $value; }
public function getHeaders() { return $this->headers; }
public function setRedirect($url) { $this->redirect = $url; }
public function getRedirect() { return $this->redirect; }
public function setStatus($status) { $this->status = $status; }
public function getStatus() { return $this->status; }
public function setContent($content) { $this->content = $content; }
public function getContent() { return $this->content; }
public function out()
{
if($this->redirect)
{
header('Location: '.$this->redirect);
die;
}
else
{
if ($this->status)
{
header('HTTP/1.1 '.$this->status);
}
foreach ($this->headers as $key => $value)
{
header($key.': '.rawurlencode($value));
}
echo $this->content;
}
}
}
Changed Request to HttpRequest and put it in a new Request-context, the same for Response. Created a LogManager as a place to store Loggers, put it in Response.PHP Code:/**
* A container for Loggers.
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 15, 2005
*/
class LogManager
{
/**
* @var array ILogger storage
*/
protected $logs = array();
/**
* Set Logger by a name.
* @param string Logger name
* @param object ILogger
*/
public function __set($key, ILogger $logger)
{
$this->logs[$key] = $logger;
}
/**
* Get Logger. If one doesn't exist, a basic Logger will be created by the given name and returned.
* @param string Logger name
*/
public function & __get($key)
{
if(!isset($this->logs[$key]))
{
$this->logs[$key] = new Logger;
}
return $this->logs[$key];
}
}
I need your thoughts!
While I can't really conjure up rational arguments, I'm still not keen on changing the signature of IHandler->execute()
Regarding you latest post, I think the LogManager may be overkill. Why would we need multiple logs ?
If we are going to pass all sort of stuff (such as $_FILES, $_SERVER and LogManager) around, I'd prefer a single ServiceLocator (Context) rather than split it into two. For example, the Loggers are output to some scripts, but input to others, which makes them odd to put in the right spot. (Though Response is possible better than Request)
Maybe we could give it a rest and bring it back up in a while ?
I'd be much more interested in peeking into a form-factory class as the one tharos was calling for. For a start, I suppose that we could just extend the FormController class ?
Bookmarks