Symfony2 components overview: Validator

In the first five posts of this series we have been talking about key components for any PHP framework from the point of view of their internals, such as HttpFoundation to abstract the HTTP protocol, HttpKernel to convert a Request into a Response, Routing to map requests to controllers, EventDispatcher to add reusability and extensibility, and Config to load and validate configuration values. This time we’ll delve deeper in the user space to describe a component that is for specific apps rather than just for frameworks. Today’s topic will be the Validator component.

It is not always easy to know what and how to validate a given input

The problem

Every single application that accepts data from a source must implement some sort of validation. It does not matter that your data comes from users or from an online API, you always run the risk your data might be tainted.

We all know the catastrophic consequences we can face if we don’t filter input data, from inconsistency in our database to security disasters caused by SQL injections, Cross-Site Scripting (XSS) or Cross-Site Request Forgery (CSRF), to name just a few. Even though the Validator component responsibilities fall under the first set of problems – to keep data consistency -, any non-filtered input data can trigger security issues.

Any application must validate input data. Some of this validations like emails, urls or ISBNs are so common that is a waste of time to code them again, as probably someone else has already made it before. The Validator component provides an extensive list of validations and a way to use them easily.

Architecture

The component it is based on the JSR-303 specification and each validation is composed of one or more constraints, which are validated against a validator. For example, in your database, your employees table must have only email addresses from your company, so you can use the default email constraint to check that the given address is valid and a second constraint that checks the domain. With the Validator component, this is done in two parts:

  • Constraints
    A constraint describes the rule. It is just a PHP object that makes an assertive statement, such as “the email must be valid”.
  • Validators
    Validators implement the validation logic. In the email example, the validator class will use filter_var($email, FILTER_VALIDATE_EMAIL) to check if the email is valid.

Simple example

<?php 

use Symfony\Component\Validator\Validation; 
use Symfony\Component\Validator\Constraints\Range; 

include_once __DIR__. '/vendor/autoload.php'; 

$validator = Validation::createValidator(); 
$constraint = new Range(array(
    'min' => 1,
    'max' => 10
));

$violations = $validator->validateValue(15, $constraint);

The $violations variable will have a ConstraintViolationList object with one ConstraintViolation object for each violation. If there are no violations, the list will be empty, but it is important to remember that for consistency, we will always get a ConstraintViolationList object, not null, false or 0.

In the last example, the $violations variable will contain one violation:

class Symfony\Component\Validator\ConstraintViolationList#10 (1) {
  private $violations =>
  array(1) {
    [0] =>
    class Symfony\Component\Validator\ConstraintViolation#13 (8) {
      private $message =>
      string(32) "This value should be 10 or less."
      private $messageTemplate =>
      string(41) "This value should be {{ limit }} or less."
      private $messageParameters =>
      array(2) {
        ...
      }
      private $messagePluralization =>
      NULL
      private $root =>
      int(11)
      private $propertyPath =>
      string(0) ""
      private $invalidValue =>
      int(11)
      private $code =>
      NULL
    }
  }
}

The ConstraintViolationList class implements Traversable, Countable and ArrayAccess interfaces. That means that we can work with the object like it was an array:

var_dump(count($violations));
var_dump(empty($violations));

foreach ($violations as $violation) {
    var_dump($violation->getMessage());
}
int(1)
bool(false)
string(32) "This value should be 10 or less."

Built-in validations

The component is shipped with the most commonly-needed constraints. Basic constraints to check that an email is valid – even checking host and MX records if needed -, the length of a string, number ranges, list of choices and many more are available out of the box.

Internationalization

We will talk more about the Translation component in future posts, but for now you must know that any object implementing the TranslatorInterface interface can be injected into the validator. The trans method of the object will be called to get the translation. Let’s see an example:

<?php 

use Symfony\Component\Validator\Validation; 
use Symfony\Component\Validator\Constraints\Range; 
use Symfony\Component\Translation\Loader\XliffFileLoader; 
use Symfony\Component\Translation\Translator; 

include_once __DIR__. '/vendor/autoload.php'; 

$translator = new Translator('es_ES'); 
$translator->addLoader('xliff', new XliffFileLoader());
$translator->addResource('xliff', __DIR__ . '/vendor/symfony/validator/Symfony/Component/Validator/Resources/translations/validators.es.xlf', 'es');

$validator = Validation::createValidatorBuilder()
    ->setTranslator($translator)
    ->getValidator();

$rangeConstraint = new Range(array(
    'min' => 1,
    'max' => 10
));

$violations = $validator->validateValue(11, $rangeConstraint);

var_dump($violations[0]->getMessage());

In this example, we want to show error messages in Spanish. To do so, we create the translator object and configure it to use the default XLIFF translation files provided by the component. Obviously, for simplicity, this is a dirty way to reference the file and, based on your application, you should find a better way to do it without relying on a Composer folder called vendor or that the autoload method is going to be PSR-0. Finally, we inject the translator and use the validator as usual. We get as the output the error message in Spanish:

string(35) "Este valor debería ser 10 o menos."

Validating objects

Most of the times, you will need to validate full objects instead of single values before persisting it in the database. How does the validator know what rules apply to each property? We need to create a mapping that links class properties with sets of constraints. It can be done using YAML, XML, annotations or PHP, in our example we will do it using YAML:

RaulFraile\Foo:
    properties:
        email:
            - NotBlank: ~
            - Email: ~
        age:
            - Range:
                min: 18

Once we have the mapping we need to tell the validator what kind of mapping we are using and where to find it:

<?php 

use Symfony\Component\Validator\Validation; 
use Symfony\Component\Validator\Constraints\Range; 
use RaulFraile\Foo; 

include_once __DIR__. '/vendor/autoload.php'; 

$obj = new Foo(); $obj->setEmail('raul@servergrove');
$obj->setAge(17);

$validator = Validation::createValidatorBuilder()
    ->addYamlMapping(__DIR__ . '/src/RaulFraile/validation/Foo.yml')
    ->getValidator();

$violations = $validator->validate($obj);

var_dump($violations);

Finally, we call the validate method – not validateValue – and get the list of violations as usual. In this case, the email is not correct and the age is less than the minimum allowed:

class Symfony\Component\Validator\ConstraintViolationList#11 (1) {
  private $violations =>
  array(2) {
    [0] =>
    class Symfony\Component\Validator\ConstraintViolation#25 (8) {
      private $message =>
      string(40) "This value is not a valid email address."
      private $messageTemplate =>
      string(40) "This value is not a valid email address."
      private $messageParameters =>
      array(1) {
        ...
      }
      private $messagePluralization =>
      NULL
      private $root =>
      class RaulFraile\Foo#2 (2) {
        ...
      }
      private $propertyPath =>
      string(5) "email"
      private $invalidValue =>
      string(16) "raul@servergrove"
      private $code =>
      NULL
    }
    [1] =>
    class Symfony\Component\Validator\ConstraintViolation#29 (8) {
      private $message =>
      string(32) "This value should be 18 or more."
      private $messageTemplate =>
      string(41) "This value should be {{ limit }} or more."
      private $messageParameters =>
      array(2) {
        ...
      }
      private $messagePluralization =>
      NULL
      private $root =>
      class RaulFraile\Foo#2 (2) {
        ...
      }
      private $propertyPath =>
      string(3) "age"
      private $invalidValue =>
      int(17)
      private $code =>
      NULL
    }
  }
}

Custom validations

The list of built-in constraints is huge and keeps growing, but if you need custom validations, it’s as easy as creating the corresponding classes for the constraint and the validation logic. For example, let’s create a simple validation to check that a programming language starts with ‘p’, or is in a fixed list of allowed languages – I know it is weird, but it’s just an example :) -.

First, we create the constraint, which defines the error message and the list of available programming languages:

<?php

namespace RaulFraile\Constraints;

use Symfony\Component\Validator\Constraint;

class ProgrammingLanguage extends Constraint
{
    public $message = 'The string "%string%" is not an accepted programming language';
    public $languages = array('php', 'javascript');
}

Then, the validation logic:

<!?php 

namespace RaulFraile\Constraints; 

use Symfony\Component\Validator\Constraint; 
use Symfony\Component\Validator\ConstraintValidator; 

class ProgrammingLanguageValidator extends ConstraintValidator {
    
    public function validate($value, Constraint $constraint) 
    {
        if (!(!empty($value) && $value[0] == 'p') && !in_array($value, $constraint->languages)) {
            $this->context->addViolation(
                $constraint->message,
                array('%string%' => $value)
            );
        }
    }
}

That’s it! If it is not an accepted programming language, we add a new violation with the error message, which will be appended to the list.

If we follow the convention and the validator class has the same name as the constraint class appending “Validator” at the end, it will automatically work. In our previous example, we add a lang property to the Foo class and include the constraint in the class validation definition:

RaulFraile\Foo:
    properties:
        ...
        lang:
            - RaulFraile\Constraints\ProgrammingLanguage: ~

Voila! Our example will work if the lang property is not valid:

<?php

$obj = new Foo(); 
$obj->setEmail('raul@servergrove.com');
$obj->setAge(18);
$obj->setLang('perlang');

$violations = $validator->validate($obj);

Will output:

class Symfony\Component\Validator\ConstraintViolationList#11 (1) {
  private $violations =>
  array(1) {
    [0] =>
    class Symfony\Component\Validator\ConstraintViolation#33 (8) {
      private $message =>
      string(59) "The string "erlang" is not an accepted programming language"
      private $messageTemplate =>
      string(61) "The string "%string%" is not an accepted programming language"
      private $messageParameters =>
      array(1) {
        ...
      }
      private $messagePluralization =>
      NULL
      private $root =>
      class RaulFraile\Foo#2 (3) {
        ...
      }
      private $propertyPath =>
      string(4) "lang"
      private $invalidValue =>
      string(6) "erlang"
      private $code =>
      NULL
    }
  }
}

Who is using it

More info

Photo: Jack Spades – Security Features of the US Twenty Dollar Bill

March 03 / 2014

Symfony2 components overview: Config

After a few weeks, we continue with the Symfony2 components series. This time we are going to be talking about the Config component, which helps you to load and validate configuration values, regardless of their source.

The Nazi’s Enigma Machine had 158,962,555,217,826,360,000 different configurations to cypher messages

Let’s imagine we want to create a blog generator system, which will take a few configuration parameters such as title, description, number of posts shown in the main page, social media icons, and whether the blog will have a RSS channel or not. With that in mind, we could create a YAML configuration file like this:

blog:
    title: My blog
    description: This is just a test blog
    rss: true
    posts_main_page: 2
    social:
        twitter:
            url: http://twitter.com/raulfraile
            icon: twitter.png
        sensiolabs_connect:
            url: https://connect.sensiolabs.com/profile/raulfraile
            icon: sensiolabs_connect.png

Now, we would need to parse the file, check that the required fields are present, set a default value for optional fields and perform by-field validations, such as the rss field must be a boolean or posts_main_page an integer between 1 and 10. In addition, we need to do it every time the script runs, unless we use any sort of caching system. It gets even more trickier if we want to support additional formats like INI, XML or JSON.

To avoid all this we use the config component, so you don’t have to code all of this yourself. It is simple, well tested, and flexible enough to cover the needs of any project.

Architecture

The component is divided in two main parts:

  • Definition of the configuration values hierarchy

    The component permits to define the format of the configuration resource, which basically can be anything, from a simple INI file to a something more esoteric like protocol-specific configuration messages. Using the TreeBuilder builder we can define the types of the values, make them required/optional and set a default value.
  • Locate, load and process configuration resources

    Once the configuration resource has been defined, must be located, loaded and processed to check that the values comply with the defined format. At the end, the component will give us a plain array with the validated values or an exception if there is an error.

Example

Let’s go back to our example. We wanted to create a highly configurable blog generator system, so it’s time to define the configuration values. For that, we use a TreeBuilder instance, which provides an easy DSL for that.

<?php

namespace RaulFraile\Config;

use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;

class Configuration implements ConfigurationInterface
{
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('blog');

        $rootNode
            ->children()
                ->scalarNode('title')
                    ->isRequired()
                ->end()
                ->scalarNode('description')
                    ->defaultValue('')
                ->end()
                ->booleanNode('rss')
                    ->defaultValue(false)
                ->end()
                ->integerNode('posts_main_page')
                    ->min(1)
                    ->max(10)
                    ->defaultValue(5)
                ->end()
                ->arrayNode('social')
                    ->prototype('array')
                        ->children()
                            ->scalarNode('url')->end()
                            ->scalarNode('icon')->end()
                        ->end()
                    ->end()
                ->end()
            ->end()
        ;

        return $treeBuilder;
    }
}

Whoa! Don’t worry too much if it is the first time you see this kind of code in PHP, DSLs always look a bit weird in PHP. What we are doing here is to define a root node, called “blog”, and the format of all the configuration values – nodes -. We expect a scalar value for the “title” and is required, “description” is optional and will be empty if not present, “rss” must be a boolean – true/false – and will be false by default while “posts_main_page” must be an integer between 1 and 10, with 5 by default.

Ok, we have the definition, let’s load and process it. As the configuration resource can be anything, we need to define how to convert that resource into a plain array, that will be validated and processed later using our definition. There must be one class for each format, so if we allow YAML and XML files, we would need to create two classes. In our example we’ll use only YAML for simplicity:

<?php

namespace RaulFraile\Config;

use Symfony\Component\Config\Loader\FileLoader;
use Symfony\Component\Yaml\Yaml;

class YamlConfigLoader extends FileLoader
{
    public function load($resource, $type = null)
    {
        $configValues = Yaml::parse($resource);

        return $configValues;
    }

    public function supports($resource, $type = null)
    {
        return is_string($resource) && 'yml' === pathinfo(
            $resource,
            PATHINFO_EXTENSION
        );
    }
}

As you see, is very simple. The supports method is used by the LoaderResolver to know wether the resource can be load with that specific loader. The load method just converts the YAML file into an array using the Yaml component.

Finally, we make use of the definition and the loader to process the configuration values:

<?php

use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\Config\Loader\DelegatingLoader;
use Symfony\Component\Config\Definition\Processor;
use RaulFraile\Config\YamlConfigLoader;
use RaulFraile\Config\Configuration;

include_once __DIR__. '/vendor/autoload.php';

// directories of config files
$directories = array(__DIR__.'/config');
$locator = new FileLocator($directories);

// convert the config file into an array
$loader = new YamlConfigLoader($locator);
$configValues = $loader->load($locator->locate('config.yml'));

// process the array using the defined configuration
$processor = new Processor();
$configuration = new Configuration();
try {
    $processedConfiguration = $processor->processConfiguration(
        $configuration,
        $configValues
    );

    // configuration validated
    var_dump($processedConfiguration);
} catch (Exception $e) {
    // validation error
    echo $e->getMessage() . PHP_EOL;
}

Let’s see what this code is doing. First, we define an array of directories where the configuration files could be, and using the FileLocator object look for the config.yml file in those folders. Then, we create the YamlConfigLoader object, which returns an array with the configuration values. Eventually, the array with the raw values is processed using our definition.

The output of this script shows the processed array:

array(5) {
  'title' =>
  string(7) "My blog"
  'description' =>
  string(24) "This is just a test blog"
  'rss' =>
  bool(true)
  'posts_main_page' =>
  int(2)
  'social' =>
  array(2) {
    'twitter' =>
    array(2) {
      'url' =>
      string(29) "http://twitter.com/raulfraile"
      'icon' =>
      string(11) "twitter.png"
    }
    'sensiolabs_connect' =>
    array(2) {
      'url' =>
      string(49) "https://connect.sensiolabs.com/profile/raulfraile"
      'icon' =>
      string(22) "sensiolabs_connect.png"
    }
  }
}

If we change the config.yml and remove the “rss” and “posts_main_page” fields, we will get the default values:

array(5) {
  ...
  'rss' =>
  bool(false)
  'posts_main_page' =>
  int(5)

Caching

If the configuration is complex, having to parse and process the configuration resources in every request can be a time-consuming task. The config component makes caching extremely easy by looking at the “last modified” timestamp of the resources.

To enable caching in our example we only need a few more lines:

<?php

use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Definition\Processor;
use RaulFraile\Config\YamlConfigLoader;
use RaulFraile\Config\Configuration;

include_once __DIR__. '/vendor/autoload.php';

$cachePath = __DIR__.'/cache/config.php';
$configFile = 'config.yml';

// the second argument is to enable/disable debugging
$cache = new ConfigCache($cachePath, true);

if (!$cache->isFresh()) {
    // directories of config files
    $directories = array(__DIR__.'/config');
    $locator = new FileLocator($directories);

    // convert the config file into an array
    $loader = new YamlConfigLoader($locator);
    $configFilePath = $locator->locate($configFile);
    $configValues = $loader->load($configFilePath);
    $resource = new FileResource($configFilePath);

    // process the array using the defined configuration
    $processor = new Processor();
    $configuration = new Configuration();
    try {
        $processedConfiguration = $processor->processConfiguration(
            $configuration,
            $configValues
        );

        // serialize the config array and save it
        $cache->write(serialize($processedConfiguration), array($resource));
    } catch (Exception $e) {
        // validation error
        echo $e->getMessage() . PHP_EOL;
    }

}

The instance of the ConfigCache class checks if the cache file exists and then compares the last modification timestamp to detect if the cache is fresh or not. Notice that when we write the cache file, we are saving the list of resources too to be able to compare them in next requests.

Multiple loaders

Allowing different formats is as easy as adding a new loader that supports the new format. In our example, if we wanted to support XML configuration files, we would add the loader and use the resolver:

<?php

namespace RaulFraile\Config;

use Symfony\Component\Config\Loader\FileLoader;

class XmlConfigLoader extends FileLoader
{
    public function load($resource, $type = null)
    {
        // parse xml

        return $configValues;
    }

    public function supports($resource, $type = null)
    {
        return is_string($resource) && 'xml' === pathinfo(
            $resource,
            PATHINFO_EXTENSION
        );
    }
}
$loaderResolver = new LoaderResolver(array(
    new YamlConfigLoader($locator),
    new XmlConfigLoader($locator)
));
$delegatingLoader = new DelegatingLoader($loaderResolver);
$configValues = $delegatingLoader->load($locator->locate('config.xml'));

Generate reference configuration

The component provides a couple of dumpers to generate reference configuration to add to your documentation.

<?php
...
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;

$dumper = new YamlReferenceDumper();
echo $dumper->dump($configuration);

Will print out:

blog:
    title:                ~ # Required
    description:          ''
    rss:                  false
    posts_main_page:      5
    social:
        url:                  ~
        icon:                 ~

Advantages

You may be thinking that this is too much work and you would do the same with a couple of functions. Well, this is usually the “cost” of having a good OOP design. On the other hand, using this component gives you lots of advantages:

  • The component is well tested (~80% of code coverage) and actively maintained.
  • Allowing new formats is really easy. Just add a new loader that transforms the resource into a plain array. The same definition will be used for any format. In general, to extend any part of the component – node types/validators, loaders, dumpers… – just have to implement the required interface.
  • Caching works out of the box, with different settings for dev and prod environments.
  • Built-in validators.
  • Generates reference configuration.

More info

Photo: Elliot Brown

February 21 / 2014

Summary of SunshinePHP 2014

Last weekend took place the second edition of SunshinePHP and was fantastic, we could not have hoped for a better PHP conference, and we did not even have to travel. For those of you that don’t know, SunshinePHP is hosted by the South Florida PHP User Group, our home base. The event was organised by the tireless Adam Culp, with the help of Pablo Godel, Adrian Cardenas, Diana Espino, and Melissa Billias who became the elephpant model. It was a world class PHP conference and needless to say, we are very proud of it.

hug

The speaker list read like a who’s who of the PHP world and they all brought something new to the conference. Beth Tucker Long, Ryan Weaver, Anthony Ferrara, Keith Casey, Brandon Savage, Michelangelo Van Dam, Evan Coury, Lukas Kahwe Smith, John Coggeshall, Anthony Ferrara, Josh Broton, Chris Hartjes, Ilia Alshanetsky, Paul Jones, Davey Shafik, Jordan Kasper, Jonathan Klein, Jeremy Lindblom, Rowan Merewood, Jeff Carouth, Elizabeth Naramore, Ben Ramsey, Chris Tankersley, Derick Rethans, Alvaro Videla, Jeremy Mikola, Thijs Feryn, Eli White, Ricard Clau and Beau Simensen. So yeah, who would not want to come to the sunny Miami in February to see these people speak? The quality of the talks were top-notch.

Keynotes

But it gets better, the conference had 4 keynotes. Mark Brown and Cal Evans were in charge of opening and closing the conference, while Rasmus Lerdorf, Larry Garfield and Matthew Weier O’Phinney dove into more technical stuff talking about PHP, open source and APIs.

It was great to hear Rasmus’ keynote, where he started giving an overview of new features in PHP, gave some great tips on deploying PHP atomically, and switched to inspire the audience to work on things and projects that make a difference in people’s lives.

photo 2

Talks

The talks were well balanced, not only on skill level, but there was was a good variety of talks, even some excellent non-php talks to help us broaden our horizons. For example, Elizabeth Naramore gave an excellent talk about how Github organises itself using their product and how organisations can do the same. It got us thinking how we organise our company since we also use Github as a communication tool here at ServerGrove.

Elizabeth also gave example of how other people use Github. One that stuck was how Evan Coury used the issue tracker to track his relationship with Alissa. Alas, thanks to Elizabeth, we fear that he might be better known for his relationship tracker than his contributions to Zend Framework.

Other great non-PHP talk were given by Josh Broton on responsive design and Rowan Merewood on being better developers. I must admit, I really hated Josh talk – and Josh itself- for that matter. It made me realize I need to rip apart the front-end of our new control panel and start from scratch. In the other hand, Rowan’s talk was qualified by many attendees as one of the best of the whole conference. He was really entertaining and provided great tips to become a better developer, something we all want and getting to this conferences is just the first step in a long – but satisfying – journey.

On the PHP track, there were also some amazing talks. Anthony Ferrara, as always, did a great job explaining concepts such as cyclomatic complexity and NPath. This last concept is especially interesting as it gives you the minimum number of tests required to completely test a routine. The talk was really funny when Anthony calculated the size needed to test some functions with a high NPath complexity… long story short, to fully test the compose_pm function of phpBB3 at 1 line of code per test, you would require 15,000,000 Milky Way’s of MicroSDs worth of tests. So, keep you NPath complexity low!

It is worth to mention the other talk of Rowan Merewood about sorting and search algorithms. Some members of our team were really happy to see these kind of concepts in PHP conferences.

Organization

photo 1

The conference was well organised and there was plenty of time to meet the speakers, hang out and network. Mostly hang out. People were relaxed, the vibe was friendly and attendees were eager to share their opinions on code. Any conference veteran will tell you that the “hallway track” is one of the best things of any conference. Given the list of speakers hanging out in the hallway or sponsors room, the “hallway track” at SunshinePHP was amazing! With many speakers saying that next year they would like to have more meals with attendees, everyone should take the time to approach the speakers. A simple “hi, my name is ___ and I really appreciate the work you’ve done on ____. May I ask you about…” goes a long way to get the conversation started. So don’t be shy!

 

There was a lot of mentoring going on, something that seems to have been added by design by Adam Culp.

PHPWomen were out in force too. It was inspiring to see such a presence at SunshinePHP.

See you next year!

We look forward to SunshinePHP 2015.

February 14 / 2014
Author Kim
Category PHP
Comments No Comments

Zend Server 6.3 with PHP 5.5 available at ServerGrove

ZS6

Zend released the new version of Zend Server, which includes a lot of great features, the most important one in our opinion is the support for PHP 5.5.

Additionally, they announced their official Long-Term Support (LTS) policy for PHP, enabling users to confidently continue using a given major version of PHP.

We have integrated Zend Server into our control panel making it easy to access and monitor. The Zend Server is only visible in the Applications section of Servers running the Zend Server image or if you installed Zend Server manually.

Order your VPS with the Zend Server pre-installed and get your app up and running in minutes!

What’s new for Zend Server 6.3:

- Expanded version support: Zend Server will now support PHP 5.5, and will be certified to run on Ubuntu 13.10 using Apache 2.4.

- New options for Windows PHP developers coding for the IBM i platform: the XML Toolkit that allows IBM i resources to be leveraged by PHP apps will now be easily deployable on Window-based Zend Server development systems.

- Faster getting up to speed with popular PHP packaged applications: Zend Server comes with sample applications ready for deployment, including Drupal, Magento, WordPress and others.

Related Article:
Preconfigured VPS images with Zend Server

More Information:
Zend.com

February 11 / 2014
Author Alex
Category PHP, VPS
Comments No Comments

PHPBenelux 2014 review

orgs

ServerGrove was present at the 2014 edition of PHPBenelux Conference. Not only we sponsored it, but we also had two members of our team attending. Aaron and myself traveled to Antwerp, Belgium for the 5th edition of one the best events of the PHP conference season.

And for this 5th edition, the organizers went all out. The conference is not only famous for the quality of the talks, but they put a lot of emphasis on the networking and social aspects, and it really shows. I have attended numerous conferences, thanks to our commitment with the community, and I can assure you, these guys know how to put together a FUN conference.

The event took place in the Hotel Ter Elst in Edegem, a few miles from Antwerp. This year, they had the talks split in three rooms and for the first time they added an unconference track. It feels that it was very much needed, because all the slots filled up quickly on each day. I was contemplating doing a talk about AngularJS but when I saw the whiteboard to signup it was too late, the slots were filled up, oh well, will try again next time.

The talks were in English with speakers from all over. Several of them came from the US. The first morning featured workshops, then was followed by the main talks. The keynote was presented by Elizabeth Smith, she talked about the importance of mentorship, from both sides: why was important being a mentor for those with more experience and why looking for a mentor is an amazing opportunity for those looking to advance in their careers. The talk was very inspiring and perfect for kickstarting a PHP conference. I hope this talk can be presented at more events in the future, including our home grown SunshinePHP. The crowd then split into different rooms. A big problem when having multiple tracks is deciding which talks to attend. Several times very interesting talks coincided, and I was torn apart because cloning is not available and I was forced to miss very interesting talks. This indeed happened a few times.

We chose Joshua Thijssen‘s talk about the first few milliseconds of HTTPS were he discussed several aspects of SSL, TLS, and encrypted and authenticated connections, and as a proof that you can always learn something even when you think you know quite a bit about a subject, we learned that with HTTPS it is possible to have the browser show a secure connection, without being encrypted, because you could configure the web server to use the cypher TLS_NULL_WITH_NULL_NULL. Quite unexpected!

A quick break followed, with coffee and delicious Belgian sweets all located in the sponsors and social events hall, which included a booth with the Dutch Web Alliance radio station broadcasting live music and interviews with attendees, all conducted by the talented Stefan Skoopmanschap.

The last talk of the day that I attended was about choosing a PHP framework by Rowan Merewood. I consider Rowan one of the best speakers out there and I enjoy all of his talks. He discussed why it’s a bad idea to build your own framework and gave pointers on how to choose one of the millions we have in the PHP world. I really liked one of his quotes that pretty much summarizes it all: “There are the frameworks everybody hates, and there are the frameworks nobody uses”. And it is very true, even the best framework will have lots of people that dislike it and disagree with its philosophy, this is why we have so many options, but then you have those frameworks that nobody uses and there are good reasons why, so stay away from those frameworks that nobody talks about and keep an eye on those that people talk about; even if it is negative. Then he ventured into what everyone was waiting for: which framework is the best, and his opinion on the most popular frameworks. As I was expecting the answer pretty much depends on your needs, preferences, and other various factors, and there is no one single best framework.

Now, on previous years, the after-hours social event included bowling, but the hotel removed this from the venue so the PHPBenelux team was forced to come up with something new. If you don’t believe a PHP conference can sport a track of bumper cars, think again. Yes, attendees ended up with bruises, back pain, and who knows what else. To cure the pain there was a really long line to get a taste of those amazing Belgian fries that is another signature of this event, and be assured, the cold wait outside is very much worth it!

The second day started early at 9am which proved to be quite tough for those of us that socialized until almost midnight. But it was worth the effort. I attended Ross Tuck‘s talk about models and service layers. I’ve heard that Ross was a great speaker and that his talks were very interesting, so I really wanted to see this one. Now, talks about MVC and patterns in general are very popular, you may find one or more of these in every conference. What I found really interesting about this talk is that Ross ventured into more advanced patterns, ones that people are starting to hear, and that solve more advanced problems. I considered this talk the best of the conference and highly recommend everyone to take a look at the slides or hopefully see it at some other conference.

After the morning break, I had to make the tough choice of picking the talk to see out of three really interesting ones: “Ansible: Orchestrate your Infrastructure” by Jeremy Coates from PHP Northwest, “Application monitoring with Heka and statsd” by Jordi Boggiano (coauthor of Composer) and “Docker, contain him, he is fast !” by Joel Wurtz. Since I’ve been hearing a lot about Docker, I wanted to see his take on it. Unfortunately Joel’s english was not very good and was hard to follow.

After a few more talks, which included one by Sara Golemon from Facebook about their project HHVM (something we will be including in ServerGrove soon), everyone came together one more time for the closing remarks and raffles. It was the time for the PHPBenelux team to share some of the insights of what takes to organize a top notch event. They also did a great job mentioning and thanking every one of the sponsors, and there are a lot of them. This highlights the importance of this conference and its quality. Companies want to be associated with an event where developers learn, have fun, make connections and friends. And when companies get involved, amazing things happen! And this is why we are very proud and happy to be part of PHPBenelux and we look forward to the next edition. Finally, all the organizers, volunteers and speakers were called to the front. It was an impressive sight looking at the stage completely full, a confirmation that takes a lot of effort and talent to make this happen.

I left Antwerp quite amazed at the ability of the organizers on bettering themselves year after year. I can’t wait to see what they come up in 2015. I hope to be there again. Until then, I look forward to attend more conferences. Luckily we will be at SunshinePHP in Miami in just 2 weeks. If you have not attended a conference before, you must consider doing it, it most probably change your life in some way. And SunshinePHP is a great opportunity to do so. If you can’t, we keep an ongoing list of PHP conferences on our blog.

Photo credit: Brett Gaasbeek @BrettPXL.

January 27 / 2014
Author Pablo
Category Conferences, PHP
Comments No Comments
Tags