Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 FOSRESTBundle REST API to return PDF

I've made a Bundle and a REST controller inside. The "index" method return array in JSON-format, it's ok:

MyBundle/Controller/Api/Rest/BaconController.php

class BaconController extends Controller implements ClassResourceInterface
{
    /**
     * @var Request $request
     * @return array
     * @Rest\View
     */
    public function cgetAction(Request $request)
    {
        $mediaType = $request->attributes->get('media_type');
        $format = $request->getFormat($mediaType);
        my_dump($format);

        return array(
             array("id" => 1, "title" => "hello",),
             array("id" => 2, "title" => "there",),
        );
    }
}

MyBundle/Resources/config/api/routing_rest.yml

my_api_rest_bacon:
    type: rest
    resource: "MyBundle:Api/Rest/Bacon"
    name_prefix: api_rest_bacon_
    prefix: /my/bacon

So, at this point JSON results get returned perfectly:

mysite.com/app_dev.php/api/my/bacon/bacons.json

returns my array.

But now I need to get my controller generate a PDF with the data. So I want it to return PDF document when I call:

mysite.com/app_dev.php/api/my/bacon/bacons.pdf

I've found some half-manuals: RSS view handler, RSS config.ynal, CSV issue with answers. And tried to make something similar:

I've added these lines to

Symfony/app/config/config.yml

framework:
    [...some old stuff here...]
    request:
        formats:
            pdf: 'application/pdf'

fos_rest:
    body_converter:
        enabled:              true
    format_listener:
        rules:
            # Prototype array
            -
                # URL path info
                path:                 ~
                # URL host name
                host:                 ~
                prefer_extension:     true
                fallback_format:      html
                priorities:           [html,json]
            -
                path:                 ~
                host:                 ~
                prefer_extension:     true
                fallback_format:      pdf
                priorities:           [pdf]
    view:
        # @View or @Template
        view_response_listener: force #true
        formats:
            json: true
            pdf: true
            xls: true
            html: false
        templating_formats:
            pdf: false
            xls: false
        mime_types: {'pdf': ['application/pdf']}
    routing_loader:
        default_format: html
    param_fetcher_listener: true
    body_listener: true
    allowed_methods_listener: true

services:
    my.view_handler.pdf:
        class: Lobster\MyBundle\View\PdfViewHandler
    my.view_handler:
        parent: fos_rest.view_handler.default
        calls:
            - ['registerHandler', [ 'pdf', [@my.view_handler.pdf, 'createResponse'] ] ]

MyBundle/View/PdfViewHandler.php

namespace Lobster\MyBundle\View;

use FOS\RestBundle\View\View;
use FOS\RestBundle\View\ViewHandler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class PdfViewHandler
{
    public function createResponse(ViewHandler $handler, View $view, Request $request, $format)
    {
        my_dump('pdf createResponse started');

        $pdf = "some pdf";

        return new Response($pdf, 200, $view->getHeaders());
    }
}

So now when I call

mysite.com/app_dev.php/api/my/bacon/bacons.pdf

I see an error An Exception was thrown while handling: Format html not supported, handler must be implemented and my function my_dump saves to a text file info about file format: it is html, not pdf.

Also pdf createResponse didn't work. Why?

like image 868
dimaninc Avatar asked Feb 10 '23 13:02

dimaninc


2 Answers

So I've found the solution (I will describe how to enable 2 output formats: PDF and XLS):

1) This section in config.yml is not needed:

framework:
    [...some old stuff here...]
    request:
        formats:
            pdf: 'application/pdf'

2) fos_rest.format_listener section in config.yml should look like this:

format_listener:
    rules:
        -
            path:                 '^/api/my/bacon.*\.xls$'
            host:                 ~
            prefer_extension:     false
            fallback_format:      json
            priorities:           [xls, json]
        -
            path:                 '^/api/my/bacon.*\.pdf$'
            host:                 ~
            prefer_extension:     false
            fallback_format:      json
            priorities:           [pdf, json]
        -
            path:                 ~
            host:                 ~
            prefer_extension:     true
            fallback_format:      html
            priorities:           [html,json]

3) need to add service section into fos_rest in config.yml

fos_rest:
[...]
    service:
        view_handler: my.view_handler

4) services root section in config.yml should look like

services:
    my.view_handler.xls:
        class: Lobster\MyBundle\View\XlsViewHandler
    my.view_handler.pdf:
        class: Lobster\MyBundle\View\PdfViewHandler
    my.view_handler:
        parent: fos_rest.view_handler.default
        calls:
            - ['registerHandler', ['xls', [@my.view_handler.xls, 'createResponse'] ] ]
            - ['registerHandler', ['pdf', [@my.view_handler.pdf, 'createResponse'] ] ]

And this is it. Now it works perfect

like image 131
dimaninc Avatar answered Feb 13 '23 03:02

dimaninc


If files will have different data content, then Controller could as well generate file on their own, returning results in BinaryFileResponse.

  • No need to change any configuration
  • _format can be used to pick desired file format
  • All code reside inside controller (and some services related to particular format gen), so adding new stuff or changing existing require changes in small number of files.
like image 30
przemo_li Avatar answered Feb 13 '23 03:02

przemo_li