Using Symfony Validators outside the Symfony Framework

While we are quite doing fine with our current framework, we are stuck in terms of data validation especially when validation is done deep inside several layers of model classes. I’ve been thinking of either using Zend Validate classes (ZF2) or Symfony Validators but it just happen that I learn Symfony validators first and a guide was available to use it outside the Symfony framework stack.

CodeIgniter Form Validation

We are currently using CodeIgniter as our application framework. While CodeIgniter’s Form Validation class is working fine for us in simple workflow, it doesn’t work well when it comes to these workflows:

  • Validating inside a model – well it works, but not well, see below
  • Re-using callback validators via class inheritance/sub-classing models
    • Ex: It seems that callbacks can only be read from the Controller
  • Validating data other than the POST data

So instead of using the built-in form validators (and we are not even sure if we are validating forms), I’ve searched for a good validation library and somehow, picked Symfony validators.

Installing Symfony Validators

For the CodeIgniter structure, Symfony validator library can be installed inside application/third_party. I used composer to install it.

cd application/third_party
mkdir symfony
composer require symfony/validator

To autoload the Symfony classes, we include the autoloader.

<?php
require_once APPPATH.'third_party/symfony/vendor/autoload.php';

// ...
?>

Integration – sample validation

In Symfony, validations involves the following components:

  • Entity – the object being validated
  • Constraints – the validation rules
  • Validation wrapper class
  • Violations – objectives containing the details of the violated rules

Entity

The entity class contains properties which are being validated by those validation constraints. See an example below.

<?php

use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class ProjectEntity
{
    protected $title;
    protected $description;
    protected $startDate;
    protected $endDate;

    public function __construct(array $data) {
        // Set property values from data array
        foreach ($data as $field => $value) {
            if (property_exists($this, $field)) {
                $this->{$field} = $value;
            }
        }
    }
}

// ...
?>

Constraints

Symfony validation component has several constraints than be used to enforce most of the validation rules that a web application might need. These constraints are usually defined inside the entity but can also be defined in a configuration file. For our example, we define them inside the entity class.

<?php

// Namespaces
class ProjectEntity
{
    // Properties and methods
    // ...

    public static function loadValidatorMetadata(ClassMetadata $metadata) {
        // Title assertions
        $metadata->addPropertyConstraint('title', new Assert\NotBlank(array(
            'message' => 'Title is required.'
        )));
        $metadata->addPropertyConstraint('title', new Assert\Length(array(
            'min' => 5, 
            'max' => 100,
        )));

        // Description assertions
        $metadata->addPropertyConstraint('description', new Assert\NotBlank(array(
            'message' => 'Description is required.'
        )));
        $metadata->addPropertyConstraint('description', new Assert\Length(array(
            'min' => 5, 
            'max' => 200,
        )));

        // Start date constraints
        $metadata->addPropertyConstraint('startDate', new Assert\NotBlank(array(
            'message' => 'Start date is required.'
        )));
        $metadata->addPropertyConstraint('startDate', new Assert\Date(array(
            'message' => 'Start date is invalid.',
        )));

        // End date constraints
        $metadata->addPropertyConstraint('endDate', new Assert\NotBlank(array(
            'message' => 'End date is required.'
        )));
        $metadata->addPropertyConstraint('endDate', new Assert\Date(array(
            'message' => 'End date is invalid.',
        )));

        $metadata->addGetterConstraint('isValidDateRange', new Assert\IsTrue(array(
            'message' => 'Start and end date range should be valid.',
        )));
    }

    /**
     * Validate start and end date range 
     * 
     * @return boolean
     */
    public function getIsValidDateRange() {
        $validStart = ($this->startDate && strtotime($this->startDate));
        $validEnd = ($this->endDate && strtotime($this->endDate));

        if ($validStart && $validEnd) {
            $startDate = new DateTime($this->startDate);
            $endDate = new DateTime($this->endDate);
            $today = new DateTime();
            
            if ($startDate < $endDate && $endDate > $today) {
                // End is greater than start and end is in the future date
                return true;
            }
        }

        return false;
    }
}

// ...
?>

The getIsValidDateRange() method is called by the isValidDateRange getter constraint to check if the start date and end date is a valid range and the end date must be a date in the future. Although there are callback validators for Symfony validator, I can’t make it work properly. If it was working, I should have been using them.

The advantage of using the getter constraint validator is that it is not specific to to a property. This can be used against one or more properties just like what we did on start date and end date. This stye can also be used to validate against data from a data base or a web service for example.

Validation object

Symfony validation has a validator builder that creates an object and initializes it. In Symfony framework, this is done automatically. However, since we are using the Symfony validator outside the framework, we need to initialize it ourselves.

<?php

use Symfony\Component\Validator\Validation;

$validator = Validation::createValidatorBuilder()
    ->addMethodMapping('loadValidatorMetadata')
    ->getValidator();

$data = array(
    'title' => 'Test Project 1',
    'description' => 'This is just a test project...',
    'startDate' => '2015-08-23',
    'endDate' => '2015-09-30',
);

$entity = new \ProjectEntity($data);
$violations = $validator->validate($entity);

// ...
?>

Violations

If there are validation rules violated, violations are returned. We can then extract the validation messages for each violations.

<?php

if (count($violations) > 0) {
    foreach ($violations as $violation) {
        echo $violation->getMessage().'<br>';
    }
} else {
    echo 'No violations.<br>';
}

// ...
?>

That’s it! Enjoy and share.

Posted in Web Development | Tagged , , , , | Leave a comment

Using Assetic to manage CSS and JS

We’ve been using Assetic for some time and we’re quite happy with the results. Assetic can be used to consolidate your CSS and JS files into fewer files with options to minify (compress) them to minimize the file size and … Continue reading

Posted in CSS, JavaScript, Site Optimization, Web Development | Tagged , , , | Leave a comment

Importing Third Party Fonts like Google Fonts – put them on top

We were using a theme for quite some time which uses Google fonts. There are no issues encountered until the number of CSS files increases too much that we need to consolidate them into 1 or 2 CSS files. This … Continue reading

Posted in CSS, Web Development | Tagged , , , | 3 Comments

A sample application running on Docker container – part 1

I’ve been using Docker for several months on my development and production environments. With Docker, I’m able to run multiple PHP applications, Django apps and RabbitMQ messaging containers simulteanously without having to deal with software package conflicts. I’d like to … Continue reading

Posted in Linux, php | Tagged , | Leave a comment

PHP – Instantiate a class from a string with namespace

I know this is old but I just learned it today. Instantiating a class from a string requires a full namespace of the class, otherwise it won’t work. You cannot use a namespace to make shortcuts. See example below. Shortcut? … Continue reading

Posted in php, Programming | Tagged , | 2 Comments

CentOS 7 + SELinux + PHP + Apache – cannot write/access file no matter what

I’ve spent 2-3 hours pulling my hair trying to setup a supposed to be simple PHP/MySQL web application on an Amazon EC2 instance running on CentOS 7. Apache logs keep saying that it can’t write to file due to permission … Continue reading

Posted in Linux | Tagged , , , , | Leave a comment

jQuery DataTables – sort by date using timestamp data attribute

DataTables is an awesome “do-it-all” table plugin for jQuery. I was trying to display a locally formatted date but should still be sorted correctly. Current plugins may not work since it the date format uses long date format like “20 … Continue reading

Posted in JavaScript, Web Development | Tagged , , | Leave a comment

Pag-IBIG contributions – paying through payment centers?

Few days ago, I was thinking of paying my Pag-IBIG monthly contributions via third party payment centers. However, I’m hesitant to try. Today, I made up my mind and went to Pag-IBIG office to pay and at the same time, … Continue reading

Posted in Personal Blog | Tagged , , | Leave a comment

Pag-IBIG – Homebased – Change status from employed to individual payor

It turn’s out that it is not too hard to change your Pag-IBIG membership status from being employed to voluntary paying member. It only took me less than an hour to file the change of my status. Here is the … Continue reading

Posted in Personal Blog | Tagged , | Leave a comment

PHPStorm SFTP to a Linux machine

I tried setting up PHPStorm on Windows 8.1 with remote files stored on a Linux VM via VirtualBox bridged connection. However,upon trying to setup SFTP, I got this error: “Algorithm negotiation fail”. It seems related to SSH rather than specific … Continue reading

Posted in Linux, SSH | Leave a comment