Recently on a project I had a situation where I was using the Symfony2 forms component without an entity. In addition to each field’s constraints, I needed to something similar to symfony 1.4’s conditional validator so that I could make sure that the form on the whole was valid. There are a bunch of docs out there on how to use callback functions on an entity to do this, however I didn’t see much on how to get the entire form that has no entity to do a callback. After reading some of the source code, found that you can set up some ‘form level’ constraints in the setDefaultOptions method. So it will look something like this:

You pass the Callback constraint an array methods which it can call. If you pass one of those methods is an array it is parsed as class::method. In my case by passing $this it uses the currently instantiated form, rather than trying to call the method statically.

From there you can do something like this:

The first parameter is the form’s data fields. From there you can add global level errors to the form, such as if a combination of fields are not valid.

Good luck out there.

Posted In: PHP, Symfony

Tags: , , , , , ,

Recently we were getting ready to deploy a new project which functions only over SSL.  The project is deployed on AWS using the Elastic Load Balancers (ELB).  We have the ELB doing the SSL termination to reduce the load on the server and to help simply management of the SSL certs.  Anyways the the point of this short post.  One of the developers noticed that on some of the internal links she kept getting a link something like “https://dev.app.com:80/….”, it was properly generating the link to HTTPS but then specify port 80. Of course your browser really does not like that as its conflicting calls of port 80 and 443.  After a quick look into the project we found that we had yet to enable the proxy headers and specify the proxy(s), it was we had to turn on `trust_proxy_headers`.  However, doing this did not fix the issue.  You must in addition to enable the headers specify which ones you trust.  This can be easily done via the following:

Here is a very simple example of how you could specify them. You just let it know the IP’s of the proxy(s) and it will then properly generate your links.

You can read up on this more in the Symfony documentation on trusting proxies.

Anyways just wanted to put throw this out there incase you see this and realize you forgot to configure the proxy in your app!

Posted In: Amazon AWS, PHP, Symfony, Tips n' Tricks

Tags: , , , ,

Recently I was working on a project in which it admins were able to impersonate other users.  It’s a fairly easy task to add to Symfony2, merely adding a switch_user reference to your firewall can make it possible, consult the Symfony docs for more on that.  One thing I noticed was that every now and then when testing I would get weird errors after switching between multiple users, however it didn’t always happen.  After some digging around, it turns out when you switch user it does not clear that sessions attributes, ie if you set attribute ‘hello’ to value ‘world’ it would persist after you’ve impersonated another user.  This caused a few issues as on this application we used the session to store a few things like which set of database connections you currently use.

After looking at the SecurityBundle configuration setup it was clear that there wasn’t any options to have it clear all session attributes on switch user.  At this point it was clear I needed to use an event listener as the firewall dispatched the SwitchUserEvent when a user successfully switched user.  Below is an excerpt from my services.yml
This makes it so that it will call the following code on a successful impersonation of a user:

It’s as simple as that, you can get the actual user by calling $event->getTargetUser(). Long story short, the session can have some tainted values when using switch user as all attributes are not cleared.

Posted In: Symfony, Tips n' Tricks

Tags: , , , , ,

A couple of months ago we started building out a Symfony 1.4 project for a client that involved allowing a “super admin” to add Doctrine models and columns at runtime. I know, I know, crazy/terrible/stupid idea but it mapped so well in to the problem space that we decided that a little “grossness” to benefit the readability of the rest of the project was worth it. Since users were adding models and columns at runtime we had to subsequently perform model rebuilds as things were added. Things worked fine for awhile, but eventually there were so many tables and columns that a single model rebuild was taking ~1.5 minutes on an EC2 large.

Initially, we decided to move the rebuild to a background cron process but even that began to take a prohibitively long time and made load balancing the app impossible. Then I started wondering is it possible to partially rebuild a Doctrine model for only the pieces that have changed?

Turns out it is possible. Looking at sfDoctrineBuildModelTask it looked like you could reasonably just copy the execute() method out and update a few lines.

Then, the next piece was just building the forms for the corresponding models. Again, looking at sfDoctrineBuildFormsTask it looked like it would be possible to extract and update the execute() method.

Anyway, without further ado here is the class I whipped up:

Using it is pretty straightforward, just call FastModelRebuild::doRebuild( array(“sfGuardUser”, “sfGuardUserProfile”) ); and thats it!

Anyway, fair warning I’d only do something like this if you “Know what you are doing” ™

As always, questions and comments are welcome.

Posted In: Demo, Symfony

Tags: , ,

Recently I was working on a project where we had a page which loads tons of data from numerous sources. I decided after a while that we wanted to AJAX each section of data so that the page would load a bit quicker. After splitting up the requests and sending them asyncronously, there was little improvement. I thought at first it may be due to the fact we were pinging a single API for most of the data multiple times, that wasn’t it. Maybe it was a browser limit? Nope was still far below the 6 requests most allow. I setup xdebug and kcachegrind and to my surprise it was the session_start() that was taking the most time on the requests.

I looked around the web for a while trying to figure out what in the world was going on. It turns out that PHP’s default session_start will block future session_starts for the same session until the session is closed. This is because the default method uses a file on the filesystem which it locks until you close it. If you want more information on this and how to close it you can read a bit more here.

We switched over to database based sessions and it fixed it. In symfony 1.4 the default session storage uses the file system, however switching over to sfPDOSessionStorage is very easy and quick.

Posted In: PHP, Tips n' Tricks

Tags: , , ,