Posts by Tag "ezcComponents"

Subscribe to posts of this tag

REST and Ajax Aware controllers in ezcMvcTools

There are essentially two major different ways to implement a restful application using a web framework. You either implement a router that routes to different controller actions based on the HTTP method used on a requested resource. This is the fancy way, which sadly is not always so practical because many browsers do not support sending more than GET and POST requests. The other way would be to define suburls of a resource such as /user/1/delete for the resource /user/1 and take GET a a request for deleting and POST for the confirmation of the delete.

ezcMvcTools HTTP Request Parser and routing mechanisms currently offer no real help to decide on this issues, but its easy to extend this missing functionality. What we first add are simple checks of the current http request method. We extend ezcMvcHttpRequestParser which will return a derived ezcMvcRequest object that implements 7 new methods: isPost(), isGet(), isDelete(), isPut(), isXmlHttpRequest(), isMethod() and getMethod(). These methods can now be easily used on the request object to determine which action will be undertaken:

class myMvcRequest extends ezcMvcRequest{  public function isPost()  {    return $this->isMethod("POST");  }  public function isGet()  {    return $this->isMethod("GET");  }  public function isPut()  {    return $this->isMethod("PUT");  }  public function isDelete()  {    return $this->isMethod("DELETE");  }  public function isXmlHttpRequest()  {    if(isset($this->raw['HTTP_X_REQUESTED_WITH'])      && strtolower($this->raw['HTTP_X_REQUESTED_WITH']) == "xmlhttprequest") {      return true;    }    return false;  }  public function getMethod()  {    if(isset($this->raw['REQUEST_METHOD']))      return strtolower($this->raw['REQUEST_METHOD']);    }    return false;  }  public function isMethod($method)  {    if(isset($this->raw['REQUEST_METHOD']) &&       $this->getMethod() == strtolower($method)) {      return true;    }    return false;  }}class myMvcHttpRequestParser extends ezcMvcHttpRequestParser{  /**   * Uses the data from the superglobals.   *   * @return ezcMvcRequest   */  public function createRequest()  {    $this->request = new myMvcRequest;    $this->processStandardHeaders();    $this->processAcceptHeaders();    $this->processUserAgentHeaders();    $this->processFiles();    $this->processAuthVars();    $this->request->raw = &$_SERVER;    return $this->request;  }}

This helps us to implement simple decision mechanisms in a single controller action that takes both POST and GET requests. From the point separation of concerns this is not a good design decision. We need routes that can point to different controller actions based on their request method, so that two requests GET /user/1/delete and POST /user/1/delete lead to different methods, for example userController::doDeleteDialog and userController::doDelete. We will simply extend the ezcMvcRailsRoute to support decision based on http request methods:

class myMvcRestRoute extends ezcMvcRailsRoute{  protected $method;  public function __construct( $method, $pattern, $controllerClassName, $action = null, array $defaultValues = array() )  {    $this->method = $method;    parent::__construct($pattern, $controllerClassName, $action, $defaultValues);  }  public function matches( ezcMvcRequest $request )  {    if(strtolower($this->method) == strtolower($request->raw['REQUEST_METHOD'])) {      return parent::matches($request);    }    return null;  }}

This very simple extension is independent of the advanced request parser given above, so you could use it separatly. In the light of our delete user example, you would use the new router in the following way:

class myRouter extends ezcMvcRouter{  public function createRoutes()  {    return array(      new myMvcRestRoute( 'GET', '/users/:id/delete', 'UserController', 'deleteDialog' ),      new myMvcRestRoute( 'POST', '/users/:id/delete', 'UserController', 'delete' ),    );  }}

We have now simple rest route support in our ezcMvcTools application.

Overwrite ezcMvcController - A bit more rapid

ezComponents gets Mvc in its 2008.2 version. I have played around a bit with the alpha version, since I am currently searching for a good framework for a high performance application. My first benchmarks on ezcMvc just say: wh000pie! Alot faster as compared to the Zend Framework.

Still ezcMvc is VERY loosly coupled and you have to write lots of lines to get where ZF gets you with less (more magic involved). As you can see from the tutorial on the ezcMvcTools component it is currently a bit unwieldily to work with ezcMvcController since you have to create and return result objects everywhere. This is very nice since it abstracts from the actual response type (could be www, mail, cli, anything).

I have created a very little extension of the ezcMvcController class that hopefully serves you quite some time. You can append variables to the ezcMvcResult object by calling the magic __get and __set on the controller. Plus it offers a method to use the ezcMvcInternalRedirect instead of the result. See for yourself:


class myController extends ezcMvcController
{
    protected $result;
 
    public function createResult()
    {
        $actionMethod = $this->createActionMethodName();
 
        if ( method_exists( $this, $actionMethod ) ) {
            $status = $this->$actionMethod();
            if($status != 0) {
                $this->getResult()->status = $status;
            }
            return $this->getResult();
        } else {
            throw new ezcMvcActionNotFoundException( $this->action );
        }
    }
 
    protected function _redirect($uri)
    {
        $request = clone $this->request;
        $request->uri = $uri;
        $this->result = new ezcMvcInternalRedirect($request);
    }
 
    public function __get($name)
    {
        if(isset($this->getResult()->variables[$name])) {
            return $this->getResult()->variables[$name];
        }
        return null;
    }
 
    public function __set($name, $value)
    {
        $this->getResult()->variables[$name] = $value;
    }
 
    public function __isset($name)
    {
        return isset($this->getResult()->variables[$name]);
    }
 
    protected function getResult()
    {
        if($this->result === null) {
            $this->result = new ezcMvcResult();
        }
        return $this->result;
    }
}

You can now use a controller in the following way:

class dashboardController extends myController
{
    public function doIndex()
    {
        $this->cookie = "Cookie!"; // Proxy to $ezcMvcResult->variables['cookie']
    }
 
    public function doRedirect()
    {
        $this->_redirect("/");
    }
}

Very nice! The next thing I have to extend in ezcMvc is automagical matching of controller and action names to view output names with a special View Handler that takes care of this. This saves another bunch of work you have to cope with in the current standard setup.