Question

I'm trying to deal with aliases (friendly-urls) and probably I'm not doing it right. What I want to do is to transform urls like '/blog/my-post-about-something' into '/posts/23'.

I have written a listener for the kernel.request event that makes some operations and modifies the original request

class RequestListener
{

    public function onKernelRequest(KernelEvent $event)
    {
        $request = $event->getRequest();
        $converted_path = $this->getPathIfAny($request);
        if ($converted_path) {
            $request->server->set('REQUEST_URI', $converted_path);
        }
    }

    public function getPathIfAny(Request $request)
    {
        return $somePathOrNull;
    }
}

All the logic works properly and updates the original request. The problem is, even if I change the 'REQUEST_URI', the property $pathInfo remains unaltered and pointing to the previous path, so I keep getting 404 errors.

Is there any way to override the uri completely, or should I try to solve the problem in a different manner?

Here is the listener definition

my_cmf.request_listener:
    class: My\CMFBundle\Event\RequestListener
    tags:
      - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest , priority: -10}

Related link to this issue: https://github.com/symfony/symfony/issues/10478

Was it helpful?

Solution

I have a similar issue with my project. I was able to update the path info, but still struggling to get it passed to subsequent events

Try this:

$event->getRequest()->server->set('REQUEST_URI', '/en/guestbook');
$event->getRequest()->initialize($event->getRequest()->query->all(), $event->getRequest()->request->all(), $event->getRequest()->attributes->all(), $event->getRequest()->cookies->all(), $event->getRequest()->files->all(), $event->getRequest()->server->all(), $event->getRequest()->getContent());

var_dump($event->getRequest()->getPathInfo());

The initialize method resets the whole class.

OTHER TIPS

You can make sub-request for kernel but with another path info.

    $url = 'Your url here...';
    $subRequest = $request->duplicate(
        null, // query
        null, // request
        null, // attributes
        null, // cookies
        null, // files
        array_merge($request->server->all(), [
            'REQUEST_URI' => $url,
        ])
    );

    return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);

Investigating a bit more, I've found an issue on the Symfony2 github repository that speaks about the problem. Seems that it is a noticed design flaw in the Request class that will be fixed in Symfony 3.*. By now, I've found a provisional solution.

Dealing with the caching issues of the Request class is possible by extending it and adding a method that cleans the cached data.

use Symfony\Component\HttpFoundation\Request as BaseRequest;

class Request extends BaseRequest
{
    public function clearCache()
    {
        $this->requestUri = null;
        $this->pathInfo = null;
        $this->requestUri = null;
        $this->baseUrl = null;
        $this->basePath = null;
    }
}

Then it is possible to bypass the problem from the listener by calling the new method.

public function onKernelRequest(KernelEvent $event)
{
    $request = $event->getRequest();
    $converted_path = $this->getPathIfAny($request);
    if ($converted_path) {
        $request->clearCache();
        $request->server->set('REQUEST_URI', $converted_path);
    }
}

Clearing the cache will probably have a small effect in the performance of the app, but I'm sure it won't be noticeable, since the cache will be being built only twice.

In fact, this is not the behaviour supposed to be used.

The real question is not "I want to transform /post/my-super-post into /post/1234", but "I want to get the good post when using its alias".

First, make sure your Post entity have a UNIQUE slug attribute (which would contains the "my-super-post" here). Those can be generated by the STOF Doctrine Extension Bundle.

Then, on your routing.yml, use something like :

show_post:
    path: /post/{slug}
    defaults: { _controller: AcmeFooBundle:Bar:showPost }

and in your controller :

public function showPostAction(Post $post) {
...
}

will automatically be containing the $post you are looking for.

You can find more informations about slugs here : http://symfony.com/doc/current/cookbook/doctrine/common_extensions.html and ParamConverters here : http://symfony.com/doc/2.0/bundles/SensioFrameworkExtraBundle/annotations/converters.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top