Mixing AngularJS and Symfony

I enjoy being a PHP Developer. PHP is a very flexible language and Symfony2 is a modern framework that forces many SOLID habits on developers. I also enjoy working with AngularJS. AngularJS makes Javascript fun and much easier to work with. Moreover, much like Symfony2, it forces good habits on developers. Getting the two to work together, however, can be a little bit of a chore if not careful.

The Problem

For starters, when the AngularJS $http service POSTs data the header application/x-www-form-urlencoded is never set (unlike jQuery’s $.ajax()). Also, the $http data is not serialized when sent. Both of these facts mean that the $_POST variable is never set properly by php. Without the $_POST variable Symfony’s built in form handling cannot be used.

It should be noted that Symfony’s Request object allows for access to raw post content via the getContent() method; meaning POST data can be processed manually if needed.

When creating a FormType in Symfony, a name is required. By default that name will be called something like bundle_path_entityname, and all post content will need to be in a multidimensional array with the FormType name as the key. This means that the posted data we send with Angular will need to follow this standard.

Consider shortening the FormType name into something more meaningful.

The Fix

The fix is actually pretty simple:

  • angular needs to forced into setting a header
  • the data needs to be serialized
  • and the data needs to be normalized into a multidimensional array.

On all $http requests we can set a headers object. That means that the Content-Type header can be set on the $http request.

headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
}

To serialize the data being sent, jQuery works well. Just use $.param() on the data and be done with it.

data: $.param({
    postData
})

Normalizing the data into a proper serialized string is as simple as creating a javascript object. Remember that the FormType name needs to be the key or parent attribute on the object.

var postData = {
    formtype_name: {
        id: some_id,
        name: some_name
    }
}

Putting it all together, the javascript should look something like this:

var postData = {
    formtype_name: {
        id: some_id,
        name: some_name
    }
};

$http({
    method: "POST",
    url: url,
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    data: $.param(postData)
});

Doing all this work on the frontend will allow for use of the normal form processing built into Symfony.