0
votes

I was reading through the "Faking the method with _method" section on the following URL: http://symfony.com/doc/current/cookbook/routing/method_parameters.html

After some experimentation, I realized that the documentation is either unclear or inaccurate. One can only override the HTTP method with the _method parameter if the browser uses POST (and not GET) to make the request.

Symfony\Component\HttpFoundation\Request

public function getMethod()
    {
        if (null === $this->method) {
            $this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));

            if ('POST' === $this->method) {
                if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
                    $this->method = strtoupper($method);
                } elseif (self::$httpMethodParameterOverride) {
                    $this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
                }
            }
        }

        return $this->method;
    }

In our application, we'd like to override the HTTP method for GET requests, because we're using JSONP. In our case, this is not a security issue as requests are signed using a CSRF token.

I found a solution for this in the "Overriding the Request" section here:

http://symfony.com/doc/current/components/http_foundation/introduction.html

This would involve making a sub-class of Symfony\Component\HttpFoundation\Request, over-riding the getMethod() method, and setting it using Request::setFactory().

use Symfony\Component\HttpFoundation\Request;

Request::setFactory(function (
    array $query = array(),
    array $request = array(),
    array $attributes = array(),
    array $cookies = array(),
    array $files = array(),
    array $server = array(),
    $content = null
) {
    return SpecialRequest::create(
        $query,
        $request,
        $attributes,
        $cookies,
        $files,
        $server,
        $content
    );
});

$request = Request::createFromGlobals();

My question is:

The only place I can see to do this is in app.php / app_dev.php / app_test.php. E.g.:

require_once __DIR__.'/../app/AppKernel.php';

$kernel = new AppKernel($env, $is_debug);
$kernel->loadClassCache();

// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
//Request::enableHttpMethodParameterOverride();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

Would this be the right place to do this?

I looked at kernel events, such as kernel.request, but at this point it seems too late for the event to be useful:

"1) The kernel.request Event Typical Purposes: To add more information to the Request, initialize parts of the system, or return a Response if possible (e.g. a security layer that denies access)."

http://symfony.com/doc/current/components/http_kernel/introduction.html

Any advice would be appreciated. Thank you.

3
This question should apply to Symfony 2.3 and above. - Jay Sheth
Starting in 2.4 you can adjust the factory used to create a Request object. symfony.com/doc/current/components/http_foundation/…. Otherwise I think you are on the right track. But do carefully consider exactly what you are trying to accomplish. The _method was to overcome browser limitations. Misusing it as you you propose will completely screw up all kinds of http caching issues. I suspect you will end up regretting going down this path. - Cerad

3 Answers

1
votes

To override the HTTP methods in symfony, it's not that hard, first add the parameter method to your routing :

blog_update:
    path:     /blog/{slug}
    defaults: { _controller: AcmeDemoBundle:Blog:update }
    methods:   [PUT]

Next, depending on which version of symfony you are using, enable Http Method Parameter Override, here's how you can do so : (from symfony doc)

The _method functionality shown here is disabled by default in Symfony 2.2 and enabled by default in Symfony 2.3. To control it in Symfony 2.2, you must call Request::enableHttpMethodParameterOverride before you handle the request (e.g. in your front controller). In Symfony 2.3, use the http_method_override option.

now if you are using symfony's FormBuilder, it should add a hidden input with the name "_method", or you can add it yourself if you are not using the symfony's form builder.

here's the full doc : http://symfony.com/doc/current/cookbook/routing/method_parameters.html

0
votes

To enable the Override of the HTTP method in symfony you should define the http_method_override in the config.yml

framework:
    http_method_override: true

kernel.http_method_override

0
votes

Overriding Request object

For those who are interested in overriding the Request base class.

There is actually a mistake in the doc, I will send a PR for this.


The following (see your example) is not correct:

use Symfony\Component\HttpFoundation\Request;

Request::setFactory(function (
    array $query = array(),
    array $request = array(),
    array $attributes = array(),
    array $cookies = array(),
    array $files = array(),
    array $server = array(),
    $content = null
) {
    return SpecialRequest::create(
        $query,
        $request,
        $attributes,
        $cookies,
        $files,
        $server,
        $content
    );
});

$request = Request::createFromGlobals();

The following is correct:

use Symfony\Component\HttpFoundation\Request;

Request::setFactory(function (
    array $query = array(),
    array $request = array(),
    array $attributes = array(),
    array $cookies = array(),
    array $files = array(),
    array $server = array(),
    $content = null
) {
    return new SpecialRequest(
        $query,
        $request,
        $attributes,
        $cookies,
        $files,
        $server,
        $content
    );
});

$request = Request::createFromGlobals();

Can you spot the difference?