Redirecting in Slim Middleware

I recently ran into a problem with calling redirect() in a Slim framework middleware class, so I thought I’d better document the solution so that I remember in future!

The authentication middleware looks roughly like this:

class Authentication extends \Slim\Middleware
{
    public function call()
    {
        if (!$this->isLoggedIn()) {
            $app = \Slim\Slim::getInstance();
            $app->redirect($app->urlFor('login'));
        }

        $this->next->call();
    }

    // other methods...
}

The problem is that you can’t call $app->redirect() in Middleware as redirect() is designed to only run in application route callbacks and Middleware should only act on the request and response objects.

This is because the app’s redirect() method calls through to stop() which throws a Stop exception which is intended to be caught by the app’s call() method. However, if this exception is thrown in middleware, then it isn’t caught by call() and the redirect doesn’t work. What’s weird is that it works on some (most?) web servers but not all.

The correct way to redirect in middleware, use the Response‘s redirect() method instead like this:

class Authentication extends \Slim\Middleware
{
    public function call()
    {
        if (!$this->isLoggedIn()) {
            $app = \Slim\Slim::getInstance();
            return $app->response()->redirect($app->urlFor('login'));
        }

        $this->next->call();
    }

    // other methods...
}

Integrating ZF2 forms into Slim

Let’s say that you want to use Zend Framework 2′s Form component outside of ZF2 itself. In this case, a Slim application.

It turns out that Composer makes this quite easy, though there’s quite a lot of code involved, so this is a long article.

Start with a really simple Slim Application.

index.php:

require 'vendor/autoload.php';
$app = new \Slim\Slim();

$app->map('/', function () use ($app) {
    $app->render('home.php', array(
        'form' => $form
    ));
})->via('GET', 'POST');

$app->run();

templates/home.php:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
</head>

<body role="document">
  <div class="container">
    <h1 class="content-subhead">Using ZF2 Forms with Slim</h1>
  </div>
</body>
</html>

and of course, composer.json:

{
    "require": {
        "slim/slim": "2.*",
    }
}

Given this starting point, we can now add Zend\Form.

Firstly, we update composer.json:

{
    "require": {
        "slim/slim": "2.*",
        "zendframework/zend-form": "2.3.*",
        "zendframework/zend-servicemanager": "2.3.*",
        "zendframework/zend-i18n": "2.3.*",
        "zendframework/zend-view": "2.3.*",
        "zendframework/zend-escaper": "2.3.*"
    },
    "autoload": {
        "psr-4": {
            "RKA\\" : "RKA"
        }
    }
}

I’ve also set up the RKA namespace as we’ll have to create some classes ourselves.

These are minimum set of components for it all to work. If you do your own rendering, then you don’t need zend-view or zend-escaper. You’ll then only need zend-i18n for some validators and filters.

When you run composer update, you’ll see that the following ZF2 components are installed for you:

  • Zend\StdLib
  • Zend\Validator
  • Zend\Filter
  • Zend\InputFilter
  • Zend\Form
  • Zend\Loader
  • Zend\EventManager
  • Zend\View
  • Zend\I18n
  • Zend\ServiceManager
  • Zend\Escaper

Other than EventManger which is required by View, this doesn’t seem an unreasonable list to me.

As, we’ll probably want to override the default validation messages and add our own validators & filters, it’s worth spending the time setting up our own instance of Zend\ServiceManager and using that to instantiate the form for us.

Configuring the service manager with the relevant plugin managers is usually done by Zend\Mvc & Zend\ModuleManager, so we’ll simplify and create a single class called ServiceManagerConfigurator. This is the most complicated part of the entire thing and looks like this:

RKA\ServiceManagerConfigurator:

namespace RKA;

use Zend\ServiceManager\Config as ServiceConfig;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class ServiceManagerConfigurator
{
    // List of plugin managers to register (key name => class name)
    public $pluginManagers = [
        'FilterManager'      => 'Zend\Filter\FilterPluginManager',
        'FormElementManager' => 'Zend\Form\FormElementManager',
        'InputFilterManager' => 'Zend\InputFilter\InputFilterPluginManager',
        'ValidatorManager'   => 'Zend\Validator\ValidatorPluginManager',
        'ViewHelperManager'  => 'Zend\View\HelperPluginManager',
    ];
    
    // Keys to look for in the config array (config key name => sm key name)
    public $configKeys = [
        'validators'      => 'ValidatorManager',
        'filters'         => 'FilterManager',
        'form_elements'   => 'FormElementManager',
        'input_filters'   => 'InputFilterManager',
        'view_helpers'    => 'ViewHelperManager',
    ];

    // Main method that gives us back a configured ServiceManager
    public function createServiceManager(array $config)
    {
        // create ServiceManager
        $serviceManager = new ServiceManager();

        // set an initializer for ServiceLocatorAwareInterface
        $serviceManager->addInitializer(
            function ($instance, ServiceLocatorInterface $serviceLocator) {
                if ($instance instanceof ServiceLocatorAwareInterface) {
                    $instance->setServiceLocator($serviceLocator);
                }
            }
        );
        // add $serviceManger to the config keys so we can configure it
        $this->configKeys = ['service_manager' => $serviceManager] 
                            + $this->configKeys;

        // add the pluginManagers to the ServiceManager
        foreach ($this->pluginManagers as $key => $className) {
            $serviceManager->setInvokableClass($key, $className);
        }

        // add Zend\Form's view helpers to the ViewHelperManager
        $viewHelperManager = $serviceManager->get('ViewHelperManager');
        $vhConfig = new \Zend\Form\View\HelperConfig;
        $vhConfig->configureServiceManager($viewHelperManager);

        // apply configuration
        $this->applyConfig($serviceManager, $config);
        return $serviceManager;
    }

    // Helper method to apply config to the service manager and all plugins
    public function applyConfig($serviceManager, $config)
    {
        foreach ($this->configKeys as $keyName => $thisManager) {

            $smConfig = array();
            if (isset($config[$keyName]) && is_array($config[$keyName])) {
                $smConfig = $config[$keyName];
            }
            
            // Get this service manager from the main service manager if it
            // isn't an instance already
            if (!$thisManager instanceof ServiceManager) {
                $thisManager = $serviceManager->get($thisManager);
            }

            // Apply the config to this service manager
            $serviceConfig = new ServiceConfig($smConfig);
            $serviceConfig->configureServiceManager($thisManager);
        }
    }
}

I’ve commented the code so that hopefully, it’s fairly easy to follow.

The key method is createServiceManager which will instantiate a ServiceManager object, add the plugin managers and other bits and bobs before calling the helper method applyConfig which will do the custom configuration.

To use it, we update our index.php:

index.php:

$app = new \Slim\Slim();

$config = [
    'validators' => array(
        'invokables' => array(
            'email-address' => 'RKA\Validator\EmailAddress',
            'string-length' => 'RKA\Validator\StringLength',
            // etc.
        ),
    ),
    'form_elements' => array(
        'invokables' => array(
            'RKA\ExampleForm'  => 'RKA\ExampleForm',
        ),
    ),

];

$smConfigurator = new RKA\ServiceManagerConfigurator();
$app->serviceManager = $smConfigurator->createServiceManager($config);
$app->view(new RKA\View());

// continue with $app->map() calls

We firstly set up the config that we want. In this case, I want to add my custom validators and then I add the form we want to use. Obviously, if we had custom filters, form elements or view helpers we could also add those too. Also, although I’m using invokables, you could also use factories if any of the classes you were adding had dependencies that needed adding.

The form is defined as any other Zend\Form is. In this case, I created a separate class called RKA\ExampleForm, but we could equally have used the factory creation.

RKA\ExampleForm:

namespace RKA;

use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;

class ExampleForm extends Form implements InputFilterProviderInterface
{
    public function init()
    {
        $this->add([
            'name' => 'email',
            'options' => [
                'label' => 'Email address',
            ],
            'attributes' => [
                'id'       => 'email',
                'class'    => 'form-control',
                'required' => 'required',
            ],
        ]);

        $this->add([
            'name' => 'submit',
            'type' => 'button',
            'options' => [
                'label' => 'Go!',
            ],
            'attributes' => [
                'class' => 'btn btn-default',
            ],
        ]);
    }

    public function getInputFilterSpecification()
    {
        return [
            'email' => [
                'required' => true,
                'filters'  => [
                    ['name' => 'StringTrim'],
                    ['name' => 'StripTags'],
                ],
                'validators' => [
                    ['name' => 'EmailAddress'],
                ],
            ],
        ];
    }
}

Nothing complicated is going on here. We add two elements to the form and then define some validation for the email element.

To use the form, we update our handler for ‘/’:

$app->map('/', function () use ($app) {
    $formElementManager = $app->serviceManager->get('FormElementManager');
    $form = $formElementManager->get("RKA\ExampleForm");

    if ($app->request->isPost()) {
        $data = $app->request->post();
        $form->setData($data);
        $isValid = $form->isValid();
        if ($form->isValid()) {
            echo "Success!";
            exit;
        }
    }

    $app->render('home.php', array(
        'form' => $form
    ));
})->via('GET', 'POST');

We grab the $formElementManager from the service manager and then grab our example form form there. If the request is a POST, then we set the posted data to the form and test for validity. On success, we would probably redirect. Finally we render our view template, passing the form to it.

We render the form within the view template using Zend\Form’s formRow view helpers to render the label, element and errors and label in one go for us, though we could have used the formLabel, formElement and formElementErrors view helpers separately:

templates/home.php:

    <!-- ... -->
    <h1 class="content-subhead">Using ZF2 Forms with Slim</h1>
      
      <form method="POST" role="form">
          <div class="form-group">
              <?= $this->formRow($form->get('email')) ?>
          </div>
          <?= $this->formElement($form->get('submit')) ?>
      </form>

    <!-- ... -->        
 

Finally, we have to extends Slim\View to integrate ZF2′s view helper system with it. This requires implementing the Zend\View\Renderer\RendererInterface and also writing a __call() method:

Rka\View:

namespace RKA;

use Slim\Slim;
use Zend\View\Renderer\RendererInterface;

class View extends \Slim\View implements RendererInterface
{
    protected $viewHelpers;
    protected $helperCache;

    public function __construct()
    {
        parent::__construct();

        $app = Slim::getInstance();
        $sm = $app->serviceManager;
        $this->viewHelpers = $sm->get('ViewHelperManager');
    }

    public function plugin($name, array $options = null)
    {
        $helper = $this->viewHelpers->get($name, $options);
        $helper->setView($this);
        return $helper;
    }

    public function __call($method, $argv)
    {
        if (!isset($this->helperCache[$method])) {
            $this->helperCache[$method] = $this->plugin($method);
        }
        if (is_callable($this->helperCache[$method])) {
            return call_user_func_array($this->helperCache[$method], $argv);
        }
        return $this->helperCache[$method];

    }

    // Required by RendererInterface
    public function render($template, $data = null)
    {
        return parent::render($template, $data);
    }

    public function getEngine()
    {
        return $this;
    }
    
    public function setResolver(\Zend\View\Resolver\ResolverInterface $resolver)
    {
        return $this;
    }
}

One undocumented feature of the formElement view helper is that it looks for a method called plugin in the View class, so I created one for it!

The final result looks like:

Slim zendform

That’s it. The code that’s shown here is on GitHub in the slim-zendform project, so you can download it and play around yourself.

Globally overriding validation messages for ZF2 forms

One thing that I always do when creating a Zend Framework 2 form is override the validation messages for a number of validators – EmailAddress in particular.

I recently decided that I should probably sort this one out once and be done with it. Turns out that it’s quite easy assuming that you use the FormElementManger to instantiate your forms.

All that I need to do is create my own validator classes that extend the Zend Framework ones and just set new message templates. This is what EmailAddress looks like:

namespace RKA\Validator;

use Zend\Validator\EmailAddress as BaseEmailAddress;

class EmailAddress extends BaseEmailAddress
{
    protected $messageTemplates = array(
        self::INVALID            => "Invalid type given. String expected",
        self::INVALID_FORMAT     => "Invalid email address",
        self::INVALID_HOSTNAME   => "Invalid email address",
        self::INVALID_MX_RECORD  => "Invalid email address",
        self::INVALID_SEGMENT    => "Invalid email address",
        self::DOT_ATOM           => "Invalid email address",
        self::QUOTED_STRING      => "Invalid email address",
        self::INVALID_LOCAL_PART => "Invalid email address",
        self::LENGTH_EXCEEDED    => "Email address is too long",
    );
}

To ensure that the ValidatorPluginManager uses the new validator in place of the default one, we override in module.config.php:

    'validators' => [
        'invokables' => [
            'email-address' => 'RKA\Validator\EmailAddress',
            'string-length' => 'RKA\Validator\StringLength',
            // etc.
        ],
    ],

Now, whenever you create a form with input filter that uses FormAbstractServiceFactory or via a config array with the Form\Factory as set up in my last post, then the new validator is picked up (assuming you use the short name).

If you create your forms via a class, then you should use the FormElementManager like this.

Firstly, create your form:

namespace RKA\Form;

use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;

class ExampleForm extends Form implements InputFilterProviderInterface
{
    public function init()
    {
        $this->add([
            'name' => 'email',
            'type' => 'text',
            'options' => [
                'label' => 'Email address',
            ],
            'attributes' => [
                'class'    => 'form-control',
                'required' => 'required',
            ],
        ]);

        $this->add([
            'name' => 'submit',
            'type' => 'button',
            'options' => [
                'label' => 'Go!',
            ],
            'attributes' => [
                'class' => 'btn btn-default',
            ],
        ]);
    }

    public function getInputFilterSpecification()
    {
        return [
            'email' => [
                'required' => true,
                'filters'  => [
                    ['name' => 'StringTrim'],
                    ['name' => 'StripTags'],
                ],
                'validators' => [
                    ['name' => 'EmailAddress'],
                ],
            ],
        ];
    }
}

Note that in getInputFilterSpecification we use the service manager key names for each validator name. The ones that are shipped with ZF2 are listed in the ValidatorPluginManager.

Now register it with the FormElementManager in module.config.php:

    'form_elements' => [
        'invokables' => [
            'RKA\ExampleForm'  => 'RKA\Form\ExampleForm',
        ],
    ],

You can then instantiate it in your controller via the main service locator:

    // in my controller
    public function getExampleForm()
    {
        $formManager = $this->getServiceLocator()->get('FormElementManager');
        return $formManager->get('RKA\ExampleForm');
    }

In addition to forms, you can also register your own fieldsets and elements under the ‘form_elements’ key and then use them within your forms.

Creating a ZF2 form from config

I have a requirement to create a Zend\Form from a dynamically created array which means that I can’t use the FormAbstractServiceFactory and so will use Zend\Form\Factory directly.

If you need to override any form elements, validators or add new ones, then you’ll need the correct plugin managers for the factory. The way to set this up is like this:

$factory = new Factory();
$formElements = $this->serviceLocator->get('FormElementManager');
$factory->setFormElementManager($formElements);
$inputFilters = $this->serviceLocator->get('InputFilterManager');
$factory->getInputFilterFactory()->setInputFilterManager($inputFilters); 

Your $factory is now configured and so you can create a form like this:

$formConfig = [
    'elements' => [
        [
            'spec' => [
                'name' => 'name',
                'options' => [
                    'label' => 'Your name',
                ],
                'attributes' => [
                    'type' => 'text',
                    'class' => 'form-control',
                    'required' => 'required',
                ],
            ],
        ],
        [
            'spec' => [
                'name' => 'email',
                'options' => [
                    'label' => 'Your email address',
                ],
                'attributes' => [
                    'type' => 'text',
                    'class' => 'form-control',
                    'required' => 'required',
                ],
            ],
        ],
    ],
    'input_filter' => [
        'name' => [
            'name'       => 'name',
            'required'   => true,
            'validators' => [
                [
                    'name' => 'not_empty',
                ],
                [
                    'name' => 'string_length',
                    'options' => [
                        'max' => 30,
                    ],
                ],
            ],
        ],
        'email' => [
            'name'       => 'email',
            'required'   => true,
            'validators' => [
                [
                    'name' => 'not_empty',
                ],
                [
                    'name' => 'email_address',
                ],
            ],
        ],
    ],
];

$form = $factory->createForm($formSpec);

View status of all Vagrant environments

I’ve just upgraded to Vagrant version 1.6, and vagrant global-status is possibly my favourite new feature.

This command lists all currently up Vagrant environments wherever they may be on your computer:

$ vagrant global-status

id       name    provider   state   directory                                         
--------------------------------------------------------------------------------------
dbc7770  joindin virtualbox running /Users/rob/www/thirdparty/joindin-vm              
0683c7a  default virtualbox running /Users/rob/www/thirdparty/joindin-zs7 
 
The above shows information about all known Vagrant environments
on this machine. This data is cached and may not be completely
up-to-date. To interact with any of the machines, you can go to
that directory and run Vagrant, or you can use the ID directly
with Vagrant commands from any directory. For example:
"vagrant destroy 1a2b3c4d"

As you can see by the helpful information message, you can then pass the id to any of the usual Vagrant commands in order to work with that Vagrant install rather than changing directory first.

I tend to use this to halt VMs that I’ve left running by accident! i.e.

$ vagrant halt 0683c7a

All in all, a very useful feature!

Prefixing every key in a hash ref in Perl

I needed to prepend some text to every element in a Perl hash ref, so I came up with:

$hashref->{"prefix_$_"} = delete($hashref->{$_}) foreach (keys %$hashref);

which prefixes each key of $hashref with “prefix_”.

After talking it over with Cliff, he was concerned with modifying the list in place while simultaneously iterating over it and suggested this solution:

%$hashref = map { +"prefix_$_" => $hashref->{$_} } keys %$hashref;

One interesting thing about this solution is the requirement for a unary “+” in map in order to help Perl work out whether we are using map BLOCK LIST or map EXPR, LIST as in this case it guesses wrong without it. from the documentation:

{ starts both hash references and blocks, so map { ... could be either the start of map BLOCK LIST or map EXPR, LIST. Because Perl doesn’t look ahead for the closing } it has to take a guess at which it’s dealing with based on what it finds just after the {. Usually it gets it right, but if it doesn’t it won’t realize something is wrong until it gets to the } and encounters the missing (or unexpected) comma. The syntax error will be reported close to the }, but you’ll need to change something near the { such as using a unary + to give Perl some help

Of course, it’s knowing the quirks like this that makes you comfortable in a given language, in the same way that good JavaScript developers know about 53 bit integers.

Z-Ray for Zend Server 7

I see that Zend Server 7 has now been released.

I’ve been running the beta for all my development work for a while now and the main reason is the new Z-Ray feature. Z-Ray is a bar that is injected into the bottom of your page showing lots of useful information.

This is what it looks like in its closed state when run on my development version of joind.in:

Z ray1

At a glance, I can see that this page’s performance is acceptable, there’s a notice that I need to look at and that 11 database queries were executed.

Continue reading

Privilege

If ever there was a word to make someone defensive, it’s privilege.

You are brought face to face with the fact that someone else doesn’t have the same experiences in life as you and that their experiences somehow make their life harder than yours.

I am one of the most privileged people I know. I am a well-educated European white man. I was raised in a loving, stable home. I have a loving, stable relationship and two children. I am doing well financially, working in a job I love. The list goes on and on and on…

I understand intellectually that not everyone has this good a run in life. But I feel defensive when someone mentions privilege. “But it’s not my fault!”, I want to whine.

I have friends who are treated as inferior by strangers. I have friends who are not listened to at work because they aren’t a white man. I have friends who have been sexually assaulted. I have known this for years and I used to shrug it off as “It’s just the way the world is, but not all men are like that.”.

This is not acceptable.

I’ve started paying more attention. I want to be part of the solution, not part of the problem. I will not blithely ignore that the rest of the population have to deal, day-in and day-out, with problems that I cannot ever fathom.

I’m reading articles and watching talks on the subject. I’m listening carefully to what my wife and friends have to say. How else can I learn?

I now know what the Bechdel Test is and I’ve noticed the lack of female protagonists in new games coming out of E3. I was shocked and depressed by what I read on #yesAllWomen.

I will change my behaviour and the way I talk. I will call out others too.

I will fail regularly in my attitude, in what I say and in what I do. I need my friends to point this out and, when they do, I will not whine.

Missing mime-info database for use with File::MimeInfo

A requirement I have on a current project means that I need to determine the mime type of a file I load from disk.

One way to do this is to use the File::MimeInfo::Magic CPAN module like this:

use File::MimeInfo::Magic;
my $mime_type = mimetype($path_to_file);

However, on OS X, an error was raised:

WARNING: You don’t seem to have a mime-info database. The
shared-mime-info package is available from http://freedesktop.org/ .

The easiest way to solve this is via Homebrew:

$ brew install shared-mime-info
$ update-mime-database /usr/local/share/mime

Speaking at DPC & OSCON

Two conferences are coming up that I’m speaking at:

I'm speaking at DPC 2014

The Dutch PHP Conference takes place in Amsterdam and this year is between June 26th and 28. I’m giving a tutorial with Matthew Weier O’Phinney on Apigility which will provide you with a full day’s teaching on creating web APIs with Apigility. I’m also giving a talk called Creating Models discussing the options available when creating the model layer of a typical MVC PHP application.

DPC is a fantastic conference full of great content and people and if you can get to Amsterdam at the end of June, it’s well worth your time to attend.

I'm speaking at OSCON 2014

The following month, I’m coming to the US to speak at OSCON which runs from the 20th to 24th July in Portland. OSCON is a massive conference that covers the entire spectrum of Open Source and I’m excited to be presenting Creating Models in the PHP track. There’s a lot on the schedule and I expect to learn a lot and meet lots of people from communities that I haven’t interacted with much before. I’ve never been to Portland before, so it’ll be interesting to see what the city has to offer too.

If you attend either of these conferences, please come and say hello!