slimphp / Slim

Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs.
http://slimframework.com
MIT License
11.98k stars 1.95k forks source link

BasePath and redirects #1440

Closed akrabat closed 9 years ago

akrabat commented 9 years ago

I'm beginning to think that basePath is more of a hinderance than a help in Uri!

Consider a very usual use case of a view item page where you want to redirect if the item cannot be found. The basic route callback is:

$app->get('/books/{id}', function ($request, $response, $args) {
    $book = Book::find($args['id']);
    if (!$book) {
        // redirect to the route named 'book'
    }

    // return a response with the book information 
})->setName('view-book');

Now... how do we create the redirect?

I think that if you're using a URL like http://locahost/slim3/develop-testbed/public/books/2 where the base path is /slim3/develop-testbed/public, then you have to do this:

        $path = $this->router->pathFor('books-list');
        $basePath = $request->getUri()->getBasePath();
        $uri = $request->getUri()->withQuery('')->withPath($path);
        $uri = $uri->withBasePath($basePath); // has to be after withPath() call
        return $response->withRedirect((string)$uri, 307);

This is silly! i.e. Surely we can do better?

JoeBengalen commented 9 years ago

Wont $request->getUri()->withPath('books') just work? You could remove the query and fragment part, but that has nothing to do with the basePath.

Also in your code sample, why do you declare the local $basePath? You are not using it.

JoeBengalen commented 9 years ago

Ah I think I see the problem now;

pathFor() returns a preceding slash, which is why the base path is ignored when using it directory in $uri->withPath().

$app->get('/test', function ($request, $response, $args) {

    var_dump((string) $request->getUri()->withPath('books'));
    // -> http://localhost/dev/slim/index.php/books

    $path = $this->router->pathFor('books');
    var_dump((string) $request->getUri()->withPath($path));
    // -> http://localhost/books 

    $basePath = $request->getUri()->getBasePath();
    var_dump((string) $request->getUri()->withPath($basePath . $path));
    // -> http://localhost/dev/slim/index.php/books

    // ltrim would work here ...
    var_dump((string) $request->getUri()->withPath(ltrim($path, '/')));
    // -> http://localhost/dev/slim/index.php/books
});

$app->get('/books', function ($request, $response, $args) {})->setName('books');

Point being the pathFor and Uri not working very well in relation to the basePath.

akrabat commented 9 years ago

Chatting with @JoeBengalen, one idea we've had is making the router basePath aware. This means that pathFor would always create a path that is absolute including the basePath.

Here's one possible implementation: https://github.com/slimphp/Slim/compare/3.x...akrabat:basepath-work?expand=1 is one solution

silentworks commented 9 years ago

Just to add some previous feedback on having this in the past. https://github.com/slimphp/Slim/issues/838#issuecomment-76093849

I also looked at a similar issue on Silex repo: https://github.com/silexphp/Silex/issues/678