0

Assuming I have an application using a lot of AJAX requests.

Is there a way to edit Symfony behavior and autommatically call indexAjaxAction instead of indexAction when my request is AJAX made ?

I already know that I can test if a request is Ajax with the Request::isXmlHttpRequest() method but I want it to be autommatic (i.e without testing in each controllerAction).

Does a service/bundle already makes it ?

Example :

<?php 

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class FooController extends Controller
{
    public function indexAction($vars)
    {
        $request = $this->getRequest();         
        if($request->isXmlHttpRequest()) {
            return $this->indexAjaxAction($vars);
        }
        // Do Stuff
    }

    public function indexAjaxAction($vars){ /* Do AJAX stuff */ }
}

becomes

<?php 

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class FooController extends Controller
{
    public function indexAction($vars) { }
    public function indexAjaxAction($vars) { }

    // Other functions
}
Fabien Papet
  • 2,244
  • 2
  • 25
  • 52

2 Answers2

2

One way would be to use a slightly modified controller resolver that would be used instead of the current controller resolver in the regular KttpKernel::handleRaw process.

Please note that I may be wrong in my thinking here and it is untested.

The controller resolver class has the id controller_resolver.class which you could overwrite with your custom one in your config using

In your app/config/config.yml...

.. config stuff ..

parameters:
    controller_resolver.class: Acme\SomeBundle\Controller\ControllerResolver

And then in your new ControllerResolver...

namespace Acme\SomeBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver
                    as BaseControllerResolver;

class ControllerResolver extends BaseControllerResolver
{
    /**
     * {@inheritdoc
     */
    public function getArguments(Request $request, $controller)
    {
        if (is_array($controller) && $request->isXmlHttpRequest()) {
            $action = preg_replace(
                '/^(.*?)Action$/', 
                '$1AjaxAction', 
                $controller[1]
            );

            try {
                $r = new \ReflectionMethod($controller[0], $action);

                return $this->doGetArguments(
                    $request, 
                    $controller, 
                    $r->getParameters()
                );
            } catch( \Exception $e) {
                // Do nothing
            }
        }

        return parent::getArguments($request, $controller);
    }
}

This class just extends the current controller resolver and will attempt to use the youractionAjaxAction if it exists in the controller and then falls back to the regular resolver if it gets an error (method not found);

Alternatively you could just use...

if (is_array($controller) && $request->isXmlHttpRequest()) {
    $controller[1] = preg_replace(
        '/^(?P<action>.*?)Action$/', 
        '$1AjaxAction', 
        $controller[1]
    );
}

return parent::getArguments($request, $controller);

.. which would just update the called action and then send it through to the regular resolver with no fall back, meaning that every action that could be called using an XmlHttpRequest would require a corresponding AjaxAction.

qooplmao
  • 17,622
  • 2
  • 44
  • 69
1

You may want to look into FOSRestBundle for Symfony, it can be very useful if you have 1 action that can either return json data or rendered html template depending on the request method

mr1031011
  • 3,574
  • 5
  • 42
  • 59
  • +1 for that bundle, It can be useful but my question is more specific. What I am looking for does not depend on HTTP method I am using. – Fabien Papet Jul 10 '14 at 09:23
  • hi Fabien, that one will actually do the check for isAjaxRequest for you, so even with the same HTTP method, it will render differently. – mr1031011 Jul 10 '14 at 10:36