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 ResultPrinter
s. 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
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.
Create an Extension
First make sure that your bundle has a /DependencyInjection/[BundleNameWithoutBundle]Extension.php
containing the extension class:
Symfony2: use a bootstrap file for your PHPUnit tests and run some console commands
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:
Symfony2: create a response filter and set extra response headers
Sometimes you need to make changes to the Response object, after it is returned by your controller, but before it is rendered as output to the client (e.g. the browser). You may want to set some extra response headers, or “completely mess up the content” of the response. You can accomplish this by creating an event listener that listens to the kernel.response
event. I give you a sample event listener which changes the Content-Type
header in case the requested format is “json” and the browser’s accepted response format contains “text/html”; in that case, at least in my experience, the browser doesn’t render the JSON string as plain text when the status code is 4xx or 5xx. So in these situations, the event listener changes the “Content-Type” to “text/plain”, to be sure you always get decent output in the browser.
Symfony2: How to create a UserProvider
Symfony2 firewalls depend for their authentication on UserProviders
. These providers are requested by the authentication layer to provide a User
object, for a given username. Symfony will check whether the password of this User
is correct (i.e. verify it’s password) and will then generate a security token, so the user may stay authenticated during the current session. Out of the box, Symfony has a “in_memory” user provider and an “entity” user provider. In this post I’ll show you how to create your own UserProvider
. The UserProvider
in this example, tries to load a Yaml file containing information about users in the following format:
Symfony2 service container: how to make your service use tags
First of all: dependency injection is GREAT!
Several of Symfony2’s core services depend on tags to recognize which user-defined services should be loaded, notified of events, etc. For example, Twig uses the tag twig.extension
to load extra extensions.
It would also be great to use tags in case your service implements some kind of “chain”, in which several alternative strategies are tried until one of them is successful. In this post I use the example of a so-called “TransportChain”. This chain consists of a set of classes which implement the Swift_Transport
interface. Using the chain, the mailer may try several ways of transport, until one succeeds. This post focuses on the “dependency injection” part of the story. The implementation of the real TransportChain
is left to the reader (as an exercise ;)).