End a Request with a Zend Framework 2 Controller Plugin

By default, Zend Framework 2 (ZF2) controller plugins cannot force the request to end. Typically, the controller action calls plugin methods and then does what it wishes with the returned value. However, there are some circumstances (such as user authentication), where you may want to end the request if certain conditions are met in the controller plugin.

For example:
Say you want to return the currently authenticated user using a controller plugin, and if there is no authenticated user, return a 401 status code. When your controller calls the plugin, you would have to check the return value every time and have boilerplate code to set the status code in the response and return the response from your controller action.

There is a better way:
Instead of having to check in your controller, wouldn’t it be better if you could just have the Plugin do the work: set the status code and return the response to the client?

This class makes that possible. By emitting MvcEvent:EVENT_FINISH, it triggers the listeners to send the response to the client. By immediately exiting the application and ending the request, we ensure that MvcEvent:EVENT_FINISH is emitted only once.

/**
 * Plugins interiting from this superclass will be able to terminate the request by calling sendResponse()
 *
 * Class RequestTerminationPlugin
 * @package Application\Controller\Plugin
 */
abstract class SendResponsePlugin extends AbstractPlugin
{
 
    /**
     * @var MvcEvent
     */
    private $event;
 
 
    /**
     * Sends the response and terminates.
     * @param ResponseInterface $response
     */
    protected function sendResponse(ResponseInterface $response)
    {
        $e = $this->getEvent();
        $e->setResponse($response);
 
        $e->getApplication()->getEventManager()->trigger(MvcEvent::EVENT_FINISH, $e);
        exit();
    }
 
 
    /**
     * Get the event
     *
     * @return MvcEvent
     * @throws DomainException if unable to find event
     */
    protected function getEvent()
    {
        if ($this->event) {
            return $this->event;
        }
 
        $controller = $this->getController();
        if (!$controller instanceof InjectApplicationEventInterface) {
            throw new DomainException(get_class($this) . ' requires a controller that implements InjectApplicationEventInterface');
        }
 
        $event = $controller->getEvent();
        if (!$event instanceof MvcEvent) {
            $params = $event->getParams();
            $event  = new MvcEvent();
            $event->setParams($params);
        }
        $this->event = $event;
 
        return $this->event;
    }
 
}

, , , ,

No Comments

GitLab 5+ on Ubuntu 12.04 LTS

GitLab is a neat GitHub clone that can be installed on your own servers. I wanted to setup mine running in a virtualized Ubuntu 12.04LTS environment.

These instructions are for Ubuntu 12.04.2 AMD64 and GitLab 5-3-stable

Basic Instructions are here:
https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md

Deviations from Official Instructions

Ruby

Rather than downloading and compiling ruby 1.9.3, I installed it from the repo:

sudo apt-get install ruby1.9.3

However, I still installed the Bundler Gem.

MySQL

I went with MySQL over PostgreSQL simply because it integrates into my existing tools better.

sudo apt-get install mysql-server mysql-client libmysqlclient-dev

I use MySQL Workbench to configure my server instances. Command line instructions can be found in the GitLab Docs.

Notice in the “Install Gems” step, you have to use the First option for MySQL:

sudo -u git -H bundle install --deployment --without development test postgres

, , , , ,

No Comments

Getting started with AbstractRestfulController

Zend Framework 2 introduced a new controller abstract class: AbstractRestfulController (more docs here). This is used to create restful services (which will communicate with javascript in the browser, for example).

Controllers implementing AbstractRestfulController, can expose normal actions in addition to the REST methods. Following the Zend convention, these the name of these methods must end in “Action”.

Example Rest Controller, with only the getList() method populated.

class TestRestController extends AbstractRestfulController
{
    public function indexAction()
    {
        return new ViewModel();
    }
 
    /**
     * Return list of resources
     *
     * @return mixed
     */
    public function getList()
    {
        return new JsonModel(array(
            array('name' => 'test'),
            array('name' => 'second')
        ));
    }
 
    /**
     * Return single resource
     *
     * @param  mixed $id
     * @return mixed
     */
    public function get($id)
    {
        //TODO: Implement Method
    }
 
    /**
     * Create a new resource
     *
     * @param  mixed $data
     * @return mixed
     */
    public function create($data)
    {
        //TODO: Implement Method
    }
 
    /**
     * Update an existing resource
     *
     * @param  mixed $id
     * @param  mixed $data
     * @return mixed
     */
    public function update($id, $data)
    {
        //TODO: Implement Method
    }
 
    /**
     * Delete an existing resource
     *
     * @param  mixed $id
     * @return mixed
     */
    public function delete($id)
    {
        //TODO: Implement Method
    }
}

I found the dispatch logic for AbstractRestfulController a little confusing.
If there is an available “action” value on the request object, the controller attempts to find the corresponding action method. If there is no action value, then it dispatches to the REST methods. This essentially means that we will have to setup custom routes to dispatch to AbstractRestfulControllers as the “action” value will typically have a default value of “index” if we are following the traditional route configuration.

If you are getting 404 Not Found errors, when you are expecting the REST methods to be executing, this is probably the problem.

Example route configuration (In module.config.php):

return array(
    'controllers' => array(
        'invokables' => array(
            'Application\Controller\TestRest' => 'Application\Controller\TestRestController',
        ),
    ),
 
    'router' => array(
        'routes' => array(
            'rest' => array(
                'type'    => 'Literal',
                'options' => array(
                    'route'    => '/rest',
                    'defaults' => array(
                        '__NAMESPACE__' => 'Application\Controller',
                    ),
                ),
                'may_terminate' => true,
                'child_routes' => array(
                    'default' => array(
                        'type'    => 'Segment',
                        'options' => array(
                            'route'    => '/:controller[/:id][/]',
                            'constraints' => array(
                                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                            ),
                            'defaults' => array(
                            ),
                        ),
                    ),
                ),
            ),
        ),
    ),

To get the controller to just render the JSON in the JsonModel returned by the getList method, we have to add a view manager strategy to the config:

return array(
    'view_manager' => array(
        'template_path_stack' => array(
            __DIR__ . '/../view',
        ),
        'strategies' => array(
            'ViewJsonStrategy',
        ),
    ),
);

, ,

4 Comments

Composer and Git on Windows

I’ve been having some problems downloading packages using Composer. It seems GitHub is having some hickups and it’s returning errors such as:

[Composer\Downloader\TransportException]                                     
  The "http://nodeload.github.com/symfony/Yaml/zipball/v2.1.3" file could not be downloaded (HTTP/1.1 404 Not Found)    

As a workaround you can use the

--prefer-source

flag to tell Composer to download the source code rather than using a bundled package. However, this means that you must have Git on your path, otherwise composer won’t be able to find it.

When I installed git, I chose the option to use the git shell, and as a result it didn’t put it on my path. I could put the cmd folder in the git installation location on the path, but instead of polluting my path, I decided to modify the composer.bat file to set the path to git.

@ECHO OFF
 
rem Include GIT on the path
SET PATH=%PATH%;C:\Program Files (x86)\Git\cmd
 
SET composerScript=composer.phar
php "%~dp0%composerScript%" %*

On Windows 7, if you used the composer installer, composer.bat should be in C:\ProgramData\Composer\bin. Make sure you change the path to git to reflect your environment.

3 Comments

Hijacker Camper Jack ORing Rebuild Parts List

Over the weekend we were rebuilding the Hijacker Camper Jacks on our camper. Since Hijacker has gotten out of the camper jack business, the rebuild kits are tough to find. We were in NAPA (Canada) and managed to size replacement o-rings that seem to do the trick. The product codes for the replacement o-rings are:

NAPA Part Number Hijacker Part # Description
DYN-54112 HJ-111 STATIC O-RINGS 1/2″ ID
DYN-54012 HJ-112 CHECK VALVE / PAC END O-RING 7/16″ ID
DYN-54008 HJ-114 RELEASE VALVE O-RING 3/16″ ID
DYN-54011 HJ-121 PLUNGER O-RING 5/16″ ID

Refer to the illustrations and tables in the following PDF for more information:
Hijacker Camper Jack Manual

, , ,

21 Comments