Code snippets for symfony 1.x

Navigation

Refine Tags

Snippets tagged "filter accept"

Auto-detect format (from URL and/or Acceptable content types)

As of Symfony 1.1, using alternative formats has become simple. However, automatic use of these formats is now disabled by default.

In the URL

Add support for sf_format in your routing factory :

/apps/myapp/config/factories.yml

all:
  routing:
    ...
    param:
      ...
      suffix: .:sf_format
 

This way, each time you go to http://mysite/module.format, the corresponding format will be detected and used.

Following URLs will automatically work and be rendered as XML : - http://mysite/module.xml # renders indexSuccess.xml.php - http://mysite/module/action.xml # renders actionSuccess.xml.php - http://mysite/module/action/param/value.xml # equals http://mysite/module/action.xml?param=value

If you want the suffix not to be mandatory (e.g. http://mysite/module/action == http://mysite/module/action.html) you'll have to add "sf_format: html" in you routing rules parameters. This is required if you want your old calls to link_to() and url_for() (who don't specifies sf_format parameter) still work.

/apps/myapp/config/routing.yml

default:
  url:   /:module/:action/*
 

myTemplate.php

link_to('hey !', 'module/action') // Produces an error !
link_to('hey !', 'module/action?sf_format=html') // Works, but hey, you'll have to add this to *all* your links :/
 

Add the default format :

/apps/myapp/config/routing.yml

default:
  url:   /:module/:action/*
  param: { sf_format: html }
 

myTemplate.php

link_to('hey !', 'module/action') // Works :)
link_to('hey !', 'module/action?sf_format=xml') // Works too, of course :)
 

Using the Accept HTTP header

We can use a filter, or plug to an even in the ProjectConfiguration class. My choice was a filter.

/apps/myapp/config/filters.yml

# insert your own filters here
detect_format:
  class: DetectFormatFilter
 

/lib/DetectFormatFilter.php

class DetectFormatFilter extends sfFilter
{
 
  public $default_formats = array(
    'html' => array('text/html', 'application/xhtml+xml'),
  );
 
  public function execute($filterChain)
  {
    $request = $this->context->getRequest();
 
    // Only if format is not already defined
    if (!$request->getRequestFormat()) {
 
      // Complete with the filter default formats
      foreach ($this->default_formats as $format => $mimeTypes) {
        foreach ($mimeTypes as $mimeType) {
          if (!$request->getFormat($mimeType)) {
            $request->setFormat($format, $mimeType);
          }
        }
      }
 
      // Detect format depending on acceptable contant types : first is prefered
      foreach ($request->getAcceptableContentTypes() as $mimeType) {
        if ($format = $request->getFormat($mimeType)) {
          $request->setRequestFormat($format);
          break;
        }
      }
 
    }
 
    // execute next filter
    $filterChain->execute();
  }
 
}
 

Take a look at the fact we automatically add "html" to the formats, attached to the two standard mime types. This could be done by adding the corresponding options to the request part of factories.yml, but I wanted this filter to be "ready-to-use" without touching other parts of configuration. "text/html" must be handled apart because as "html" is the default format, Symfony just does not handle it. So when we browse "Accept" headers, we will pass on "text/html", and just skip it because it's not configured. Without adding this part, "html" format would never been rendered, quite annoying isn't it ;)

With this configuration, you can just add the "Accept" header to say you want an XML content, and your ".xml.php" templates will then be rendered.

An interesting evolution of this filter would be to allow it to test if the format can be rendered, and if not, fall back to a default one.

Conclusion

It's quite easy to enable back auto-detection of the format. However, as Fabien says in the ticket 4920, Accept header is sometimes unreliable, and some badly configured browsers could make you think they prefer XML, which will not be the case of the user behind this browser ;)

That said, even if the URL suffix method is probably the best choice, this auto-detection method works and could be useful in some projects...

by Nicolas Chambrier on 2009-03-21, tagged accept  filter  format  routing 
(2 comments)