Filtering objects using annotations
- PHP
- August 11, 2011
Filtering with Annotations
PHP does not have native Annotations support, however many projects have been using doc blocks to add value and semantics to code, like PHPUnit, Doctrine and Symfony. The Doctrine did a really good job in making available a Annotation parser kit, which allows you to bring the power of annotations into you own project. This opens up a few possibilities.
Input Validation and Filtering
Rule #1 of the developer is “Filter input, escape output”. To me treating input has two distinct steps which are very important: Filtering and Validation. Symfony 2 has come out with a very cool Validation library which makes validation possible using annotations. It relies on a set of constraints which can be attached to properties of your object, allowing you to simply pass your objects to a validation service and it will do the rest for you. Like this:
<?php // src/Acme/BlogBundle/Entity/Author.php use Symfony\\Component\\Validator\\Constraints as Assert;
class Author { /\*\* \* @Assert\\NotBlank() \*/ public $name; } ?>
``` ```php
<?php $author = new Author();
$validator = $this->get('validator'); $errorList = $validator->validate($author); ?>
This is a very nice and clean way of handling validation, it allows all rules to be centered on the entities, making maintenance easy. A nice complement is that constraints can be added to the class so they use more then one variable, as well as allowing you to create your own contraints.
However the library lacks one thing, which Zend_Filter_Input does very well, Filtering. Most data needs to be filtered before going in for validation, and even of Symfony2 offers a Data Transformer, that is not quite what is needed here, so I came out with the only other solution, build one myself.
DMS\Filter
I wanted a library with all the power of the filters out there and the advantage of using annotations to provide its interface. So i set about studying the annotations implementation in doctrine and the Symfony2 Validator and came up with my own Filter library. It was designed to be simple and to be used alongside doctrine and symfony validator, so it depends on Doctrine Common.
Its composed of a filter service which is capable of reading “filter rules” from object properties and iterate over them, even private and protected ones, filtering the values. It works based on the object instance which is not cloned, so the object is altered and does not need to be returned nd re-assigned.
To add rules to you properties, just declare the namespace use and go for it, like this:
<?php
namespace App\\Entity;
//Import Annotations use DMS\\Filter\\Rules as Filter;
class User {
/\*\* \* @Filter\\StripTags() \* @Filter\\Trim() \* @Filter\\StripNewlines() \* \* @var string \*/ public $name;
/\*\* \* @Filter\\StripTags() \* @Filter\\Trim() \* @Filter\\StripNewlines() \* \* @var string \*/ public $email;
} ?>
To filter your instance, just do it like this:
<?php //Get Doctrine Reader $reader = new Annotations\\AnnotationReader(); $reader->setEnableParsePhpImports(true);
//Load AnnotationLoader $loader = new Mapping\\Loader\\AnnotationLoader($reader); $this->loader = $loader;
//Get a MetadataFactory $metadataFactory = new Mapping\\ClassMetadataFactory($loader);
//Get a Filter $filter = new DMS\\Filter\\Filter($metadataFactory);
//Get your Entity $user = new App\\Entity\\User(); $user->name = "My <b>name</b>"; $user->email = " [email protected]";
//Filter you entity $filter->filter($user);
echo $user->name; //"My name" echo $user->email; //"[email protected]" ?>
You can also recycle an AnnotationReader already in use by Symfony Validator for example. The AnnotationReader is currently changing in Doctrine Common, but DMS\Filter tries to auto-configure its namespace, I will be keeping an eye on this in the future.
The project is available in two forms, inside the DMS library on github , or as a standalone component, also on github (sub tree split FTW!). It has a limited number of filters, but you can develop your own filters to use or just open up an issue and i’ll create them.
Hope the library is useful and you enjoy it.