ceap80
10/27/2010 - 9:04 AM

multiplexer to json-ify any controller as well as call multiple separate controllers via one request

multiplexer to json-ify any controller as well as call multiple separate controllers via one request

<?php

namespace Application\FooBundle\Controller;

class MultiplexController
{
    /**
     * Request
     * @var Symfony\Component\HttpFoundation\Request
     */
    protected $request;

    /**
     * Response
     * @var Symfony\Component\HttpFoundation\Response
     */
    protected $response;

    /**
     * Kernel
     * @var Symfony\Component\HttpKernel\Kernel
     */
    protected $kernel;

    /**
     * Router
     * @var Symfony\Component\Routing\RouterInterface
     */
    protected $router;

    /**
     * assoc array with config parameters
     * @var array
     */
    protected $params;

    /**
     * Constructor
     *
     * @param array $params assoc array with config parameters
     * @param Symfony\Component\HttpFoundation\Request $request
     * @param Symfony\Component\HttpFoundation\Response $response
     * @param Symfony\Component\HttpKernel\Kernel $kernel
     * @param Symfony\Component\Routing\RouterInterface $router
     */
    public function __construct(array $params, $request, $response, $kernel, $router)
    {
        $this->params = $params;
        $this->request = $request;
        $this->response = $response;
        $this->kernel = $kernel;
        $this->router = $router;
    }

    /**
     * Handle a single request
     *
     * @param array $request array contains 'uri', 'method' and 'query'
     * @param string $id id value
     * @return array contains 'id', 'status' and 'html'
     */
    protected function handleRequest($request, $i)
    {
        if (empty($request['uri'])) {
            throw new \InvalidArgumentException('no uri given for index: '.$i);
        }
        $request['uri'] = preg_replace('/^('.preg_quote($this->request->getScriptName(), '/').')?\//', '', $request['uri']);

        if (empty($request['method'])) {
            $request['method'] = 'get';
        }
        if (empty($request['parameters'])) {
            $request['parameters'] = array();
        }

        $subRequest = $this->request->create($request['uri'], $request['method'], $request['parameters']);
        if (false === ($parameters = $this->router->match($subRequest->getPathInfo()))) {
            throw new \InvalidArgumentException('uri did not match a route for index: '.$i);
        }

        $subRequest->attributes->add($parameters);
        $subResponse = $this->kernel->handle($subRequest, \Symfony\Component\HttpKernel\HttpKernelInterface::SUB_REQUEST);
        if (substr($subResponse->getStatusCode(), 0, 1) === '3') {
            $request = array(
                'uri' => $subResponse->headers->get('location'),
                'method' => 'get',
                'parameters' => array(),
            );
            return $this->handleRequest($request, $i);
        }

        return array(
            'id' => $i,
            'status' => $subResponse->getStatusCode(),
            'html' => $subResponse->getContent(),
        );
    }

    /**
     * Handle the index request
     *
     * @param string $_format the format to use in the response (json, html ..)
     * @return Symfony\Component\HttpFoundation\Response
     */
    public function indexAction($_format)
    {
        $requests = (array)$this->request->get('requests');

        $content = array('response' => array());
        foreach ($requests as $i => $request) {
            if ($_format === 'html') {
                $content['response'][] = $this->handleRequest($request, $i);
            } else {
                try {
                    $content['response'][] = $this->handleRequest($request, $i);
                } catch (\Exception $e) {
                    // TODO: are our error messages safe to be returned?
                    $content['response'][] = array('id' => $i, 'status' => '500', 'html' => $e->getMessage());
                }
            }
        }

        $this->response->setStatusCode(200);
        $content['status'] = 'success';

        // TODO add xml?
        switch ($_format) {
        case 'json':
            $content = json_encode($content);
            break;
        case 'html':
        default:
            $content = '<pre>'.var_export($content, true).'</pre>';
            break;
        }

        $this->response->setContent($content);

        return $this->response;
    }
}