If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
Yea, we can RSVP for an event. But it’s not super-impressive yet. You and I both know that a little AJAX could spice things up.
Our attend and unattend endpoints aren’t really ready for AJAX yet. They both return a redirect response, which really only makes sense when you want the browser to do full page refreshes.
So why not return something different, like a JSON response? JSON is great because it’s easy to create in PHP and easy for JavaScript to understand. And actually, could we make the endpoints return both? Why not!
Start by adding a format wildcard to both of the routes. Give it a default value of html:
# src/Yoda/EventBundle/Resources/config/routing/event.yml
# ...
event_attend:
pattern: /{id}/attend.{format}
defaults: { _controller: "EventBundle:Event:attend", format: html }
event_unattend:
pattern: /{id}/unattend.{format}
defaults: { _controller: "EventBundle:Event:unattend", format: html }
As soon as we give a wildcard a default value, it makes it optional. For us, it means that we can now go to /5/attend.json, but /5/attend still works too. So if the format part is missing, the route still matches.
In a truly RESTful API, it’s more “correct” to read the Accept header instead of putting the format in the URL like we’re doing here. If you’re interested in that, check out our REST Series, it’ll blow your mind.
I don’t really feel like also making the endpoints return XML, so let’s add a requirements key to the route:
# src/Yoda/EventBundle/Resources/config/routing/event.yml
# ...
event_attend:
pattern: /{id}/attend.{format}
defaults: { _controller: "EventBundle:Event:attend", format: html }
requirements:
format: json
event_unattend:
pattern: /{id}/unattend.{format}
defaults: { _controller: "EventBundle:Event:unattend", format: html }
requirements:
format: json
Now try going to the URL with .xml in the end. The route doesn’t match! Requirements are little regular expressions that you can use to restrict any wildcard.
With this new wildcard in our route, we can now use it to return JSON or a redirect response.
You know what the next step is: give attendAction a $format argument:
// src/Yoda/EventBundle/Controller/EventController.php
// ...
public function attendAction($id, $format)
{
// ...
}
If it’s equal to json, we can return a JSON string instead of a redirect:
// src/Yoda/EventBundle/Controller/EventController.php
// ...
use Symfony\Component\HttpFoundation\Response;
public function attendAction($id, $format)
{
// ...
$em->flush();
if ($format == 'json') {
$data = array(
'attending' => true
);
$response = new Response(json_encode($data));
return $response;
}
return $this->redirect($this->generateUrl('event_show', array(
'slug' => $event->getSlug()
)));
}
How? Just create an array and then convert it to JSON with json_encode. And do you remember the cardinal rule of controllers? A controller always returns a Symfony Response object. So just create a new Response object and set the JSON as its body. It’s that simple, stop over-complicating it!
Test it out by copying the link and adding .json to the end. Hello, beautiful JSON!
Tip
The JSON is pretty in my browser because of the JSONView Chrome extension.
Hey Wayne!
You have several options:
1) Create your XML string however you want to (Symfony doesn't have anything to help you do this as there are ways in PHP and other libraries). Then, simple create and return a "new Response($xml);" where $xml is the string. You can also (and should) set the XML Content-Type header in the Response. But basically, the message is that returning XML is no different than returning HTML or JSON (except that JSON has a handy, but optional JsonResponse class).
2) Watch our tutorial about doing REST in Symfony. We use a serializer there to create the JSON string, and this also supports creating XML.
Good luck!
// composer.json
{
"require": {
"php": ">=5.3.3",
"symfony/symfony": "~2.4", // v2.4.2
"doctrine/orm": "~2.2,>=2.2.3", // v2.4.2
"doctrine/doctrine-bundle": "~1.2", // v1.2.0
"twig/extensions": "~1.0", // v1.0.1
"symfony/assetic-bundle": "~2.3", // v2.3.0
"symfony/swiftmailer-bundle": "~2.3", // v2.3.5
"symfony/monolog-bundle": "~2.4", // v2.5.0
"sensio/distribution-bundle": "~2.3", // v2.3.4
"sensio/framework-extra-bundle": "~3.0", // v3.0.0
"sensio/generator-bundle": "~2.3", // v2.3.4
"incenteev/composer-parameter-handler": "~2.0", // v2.1.0
"doctrine/doctrine-fixtures-bundle": "~2.2.0", // v2.2.0
"ircmaxell/password-compat": "~1.0.3", // 1.0.3
"phpunit/phpunit": "~4.1", // 4.1.0
"stof/doctrine-extensions-bundle": "~1.1.0" // v1.1.0
}
}
How would one encode and return xml instead of json?