Edit Symfony behavior with AJAX actions

2020-08-05 11:00发布

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
}

标签: php ajax symfony
2条回答
萌系小妹纸
2楼-- · 2020-08-05 11:07

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

查看更多
Anthone
3楼-- · 2020-08-05 11:11

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.

查看更多
登录 后发表回答