A collection of more than 250 articles about Software Design & Development Best Practices.
With code samples for PHP/Symfony and Fortran applications.
Symfony2 & Doctrine Common: creating powerful annotations
I was looking into the Doctrine Common library; it seems to me that especially the AnnotationReader is quite interesting. Several Symfony2 bundles use annotation for quick configuration. For example adding an @Route annotation to your actions allows you to add them “automatically” to the route collection. The bundles that leverage the possibilities of annotation all use the Doctrine Common AnnotationReader (in fact, the cached version) for retrieving all the annotations from your classes and methods. The annotation reader works like this: it looks for annotations, for which it tries to instantiate a class. This may be a class made available by adding a use statement to your file. That is why you have to add use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route to any PHP file in which you use the @Route annotation.
Symfony2: Extending forms globally ("you know, like with CSRF protection")
Please note: There is also an interesting Cookbook article about the same subject (not written by me).
With Symfony2, many things are managed through dependency injection. Except for forms. Oh, wait, forms can be services too of course! Remember? Any class instance can be a service… Now, as in many other cases, Symfony2’s FrameworkBundle adds some magic to the Form component by creating services that link several parts of the Form component together. For example, depending on the value of the framework.csrf_protection parameter in config.yml file a hidden field “_token” will be added to all forms, site-wide. To create this kind of very general “form extension” in your own project, you need to do just a few things (I am going to use the example of a “Captcha” form extension, but I don’t give a full implementation of this idea).
Symfony2: Creating a Validator with dependencies? Make it a service!
One of the ugly things about Symfony 1 validators was that their dependencies were generally fetched from far away, mainly by calling sfContext::getInstance(). With Symfony2 and it’s service container, this isn’t necessary anymore. Validators can be services. The example below is quite simple, but given you can inject anything you want, you can make it quite complicated. I show you how to create a validator that checks with the router of the value-under-validation is a route.
Symfony2: An alternative to Symfony 1's "routing.load_configuration" event
Symfony 1 had the lovely routing.load_configuration event. Listening to this event enabled the developer to add some routes dynamically, “on-the-fly”. Plugins used to do this most of the time. I was looking for a way to accomplish the same in Symfony 2. I’ve used the following as a solution.
We are going to listen to the kernel.request event, but we make sure we get notified in an early stage, so that the router hasn’t done it’s magic yet. Then we quickly add some extra routes to the RouteCollection.
PHPUnit: create a ResultPrinter for output in the browser
PHPUnit 3.6 allows us to create our own so-called ResultPrinters. Using such a printer is quite necessary in the case of running your unit tests from within the browser (see my previous post), since we don’t print to a console, but to a screen. You can make this all as nice as you like, but here is the basic version of it.
Create the HtmlResultPrinter
First create the file containing your (for example) HtmlResultPrinter, for example in /src/Acme/DemoBundle/PHPUnit/HtmlResultPrinter.
Symfony2: running PHPUnit from within a controller
When you don’t have access to the command-line of your webserver, it may be nice to still run all your unit tests; so you need a way to execute the phpunit command from within a controller. This way, you can call your test suite by browsing to a URL of your site. To do things right, we start with a “test” controller /web/app_test.php containing these lines of code:
if (!in_array(@$_SERVER['REMOTE_ADDR'], array(
'127.0.0.1',
'::1',
))) {
header('HTTP/1.0 403 Forbidden');
exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}
require_once __DIR__.'/../app/bootstrap.php.cache';
require_once __DIR__.'/../app/AppKernel.php';
use Symfony\Component\HttpFoundation\Request;
$kernel = new AppKernel('test', true);
$kernel->loadClassCache();
$kernel->handle(Request::createFromGlobals())->send();
In fact, just copy everything from /web/app_dev.php but replace the string “dev” by “test”.
Symfony2: define your bundle's configuration values using the TreeBuilder
Please note: After writing this article I’ve started to write more documentation for the Config component. First I published it here, then it became the official documentation of the Config component.
After reading the Cookbook article How to expose a Semantic Configuration for a Bundle I became interested in the possibilities for defining a configuration tree using the TreeBuilder from the Symfony component Config. This TreeBuilderallows you to build a schema against which the configuration values (or short: config) from/app/config.yml` and the like are to be validated.
Symfony2: use a bootstrap file for your PHPUnit tests and run some console commands
Please note: There are better solutions to accomplish what I describe in this article. I’d like to recommend the ICBaseTestBundle here, which automatically creates a database for you and loads fixture data into it.
One of the beautiful things about PHPUnit is the way it can be easily configured: for example you can alter the paths in which PHPUnit will look for TestCase classes. In your Symfony2 project this can be done in the file /app/phpunit.xml (if it is called phpunit.xml.dist, rename it to phpunit.xml first!). This file contains a default configuration which suffices in most situations, but in case your TestCase classes are housed somewhere else than in your *Bundle/Test, add an extra “directory” to the “testsuite” element in phpunit.xml:
Symfony2: how to create a custom Response using an event listener
In some cases you want to return a very specific Response in case the Request has some properties like a certain response format.
This situation calls for an event listener, which listens to the kernel.request event. The listener itself should be a service with some special characteristics: it has the tag “kernel.event_listener” and some extra attributes, i.e. the name of the event to which it listens and the method of the service that should be called when this event occurs. When you want to return a very specific Response, you should listen to the kernel.request event. We want the kernel to call the method onKernelRequest(), which we will define later.
Use DocBlox in Symfony2 for inspecting DocComment blocks
I was looking for a way to automatically generate some documentation, and because all the required information was already in the DocComment blocks. I downloaded the great documentation generator DocBlox (which is a PHP application by itself) and looked in it’s source code. Soon I found DocBlox’s Reflection classes which are able to parse a DocComment block. So I wanted to use these classes! Here is how you can do it: