I have a problem. I am using slim and I have route for my main page:
$app->get('/', function() use ($app) { ...
In one of my controllers I want to redirect to the main page, so I write
$app->response->redirect('/', 303);
But instead of redirection to the '/' route I'm getting redirected to the root of my local server which is http://localhost/
What am I doing wrong? How should I use redirect method?
Slim allows you to name routes, and then redirect back to them based upon this name, using urlFor(). In your example, change your route to:
$app->get('/', function() use ($app) { ... })->name("root");
and then your redirection becomes:
$app->response->redirect($app->urlFor('root'), 303);
See Route Helpers in the Slim documentation for more information.
From Slim3 docs
http://www.slimframework.com/docs/start/upgrade.html
$app->get('/', function ($req, $res, $args) {
return $res->withStatus(302)->withHeader('Location', 'your-new-uri');
});
Slim 3
$app->get('/', function ($req, $res, $args) {
$url = 'https://example.org';
return $res->withRedirect($url);
});
Reference: https://www.slimframework.com/docs/v3/objects/response.html#returning-a-redirect
give your '/' route a name,
$app = new \Slim\Slim();
$app->get('/', function () {
echo "root page";
})->name('root');
$app->get('/foo', function () use ($app) {
$app->redirect($app->urlFor('root') );
});
$app->run();
This should give you the correct url to redirect
http://docs.slimframework.com/routing/names/
http://docs.slimframework.com/routing/helpers/#redirect
//Set Default index or home page
$app->get('/', function() use ($app) {
$app->response->redirect('login.php');
});
Slim 4:
$response->withHeader('Location', '/redirect/to');
Or in place of fixed string:
use Slim\Routing\RouteContext;
$routeParser = RouteContext::fromRequest($request)->getRouteParser();
$url = $routeParser->urlFor('login');
return $response->withHeader('Location', $url);
Slim Documentation: http://www.slimframework.com/docs/v4/objects/response.html#returning-a-redirect
RouteContext: https://discourse.slimframework.com/t/redirect-to-another-route/3582
For Slim v3.x:
Use $response->withStatus(302)->withHeader('Location', $url); instead of $app->redirect();
In Slim v2.x one would use the helper function $app->redirect(); to trigger a redirect request. In Slim v3.x one can do the same with using the Response class like so (see the following example)[1].
Use pathFor() instead of urlFor():
urlFor() has been renamed pathFor() and can be found in the router object.
Also, pathFor() is base path aware[2].
Example:
$app->get('/', function ( $request, $response, $args ) use ( $app ) {
$url = $this->router->pathFor('loginRoute');
return $response->withStatus(302)->withHeader('Location', $url);
});
Note: additional parameters can be supplied by passing an associative array of parameter names and values as a second argument of pathFor() like: $this->router->pathFor('viewPost', ['id' => 1]);.
The router’s pathFor() method accepts two arguments:
The route name
Associative array of route pattern placeholders and replacement values[3]
References:
Changed Redirect
urlFor() is now pathFor() in the router
Route names
I think using ./ instead of / will work also.
I think I faced a similar problem, and the issue was with my .htaccess config file. It should actually be something like this:
RewriteEngine On
RewriteBase /api #if your web service is inside a subfolder of your app,
# you need to pre-append the relative path to that folder, hope this helps you!
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
Related
After upgrading to Slim v4 I'm trying to replace my simple $app->subRequest call with $app->handle as specified in the changelog. However there are no details on how to do this in either the changelog or upgrade guide and my best effort to fix it ends up creating an infinite loop:
$app->get("/foo", function (Request $req) use ($app) {
$uri = $req->getUri();
$newUri = $uri->withPath("/bar");
$barReq = $req->withUri($newUri);
// Here we get stuck in endless loop instead of ending up in the /bar route handler below
$app->handle($barReq);
});
$app->get("/bar", function (Request $req) use ($app) {
echo 'bar!';
die;
});
It's like even though $barReq is a new request object with a completely new uri (and path) the router does not resolve which route handler that should handle it, instead it's just handled by the same one again.
My previous simplified (v3) code looked like and worked fine to get the result of the /bar route when calling /foo:
$app->get("/foo", function (Request $req) use ($app) {
$app->subRequest('GET', '/bar');
});
I'm probably missing some central concept on how Slim 4 handles requests and routes internally and would appreciate some help!
Edit: Should perhaps add that what I mean with internal redirect is that client should not be aware that a redirect has been made. I.e. any regular redirect function returning something to client is not applicable here.
As #remy stated, use the ServerRequestFactory implementing ServerRequestFactoryInterface.
For slim/psr7 it is: Slim\Psr7\Factory\ServerRequestFactory
A silent redirect to another route is then as simple as:
use Slim\Psr7\Factory\ServerRequestFactory;
...
...
$app->get('/foo', function ($request, $response, $args)
{
global $app;
return $app
->handle((new ServerRequestFactory())->createServerRequest('GET', '/bar'));
});
I'm using the Bramus PHP router for my application, but it only seems to work on the index route which is /. Here's the piece of code that won't work:
public function handle(): Response
{
$response = null;
$request = new Request($_REQUEST);
$uri = $request->getRequestUri();
$container = $this->configureContainer();
$renderer = new RendererFactory();
$router = $this->configureRouter();
$controllerFactory = new ControllerFactory();
$controller = $controllerFactory->create($request, $container, $renderer, $uri);
$router->get($uri, function () use ($uri, $controller, &$response) {
$response = $controller->get();
});
$router->run();
return $response;
}
So when I go to the homepage, it works fine and returns the response with the correct value. However, when I go to say /about-us, the $router->get() never fires at all. It doesn't execute the anonymous function inside. Even replacing the $uri parameter with a hardcoded string like $router->get('/about-us'...) doesn't make the anonymous function execute.
I confirmed that the ControllerFactory does in fact return the right controller, so if the $router->get() fires, the get() method is in there and the $response should not be null. But now I get an error saying $response is null because the $router->get() won't fire.
What's the mistake I'm missing here? How can the index route work perfectly fine, but the router won't accept another route?
Edit Did some digging and added a var_dump to the Bramus Router
I added a var_dump() in the handle function inside the package itself, and it always says that the result of $this->getCurrentUri() is /, and not the URI in the browser.
My .htaccess is in the root directory and I redirect all requests to /public/index.php. Maybe that's the culprit? But I don't know how to fix it. My .htaccess:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /public/index.php?path=$1 [NC,L,QSA]
Forgot to add $router->setBasePath('/');, and my folder structure and .htaccess config made the router go crazy.
I want to pass an ID "0" to the controller if my url is user/new, how can i do it on the route.php in laravel?
I imagined something like this, but I don't think is that simple.
Route::get('user/new','UserController#edit', ['id'=>'0']);
Route::get('user/edit/{id}','UserController#edit');
With normal .htaccess i'd do something like this:
RewriteRule ^user/new /www/user/edit.php?id=0 [L,QSA]
RewriteRule ^user/(.*) /www/user/edit.php?id=$1 [L,QSA]
Do I need a middleware? Is there a more simple way to do it?
That's semantically weird, creating an user with an edit function, anyways...
Why not use a php default paramenter value?
// UserController.php
public function edit($id = 0) // NOTICE THIS
{
// your id is zero if none passed (when /new is called)
}
Your already existing edit wouldn't change and you don't have to touch your routes.
One way would be to use a closure in your routes, like this:
Route::get('user/new', function() {
return App::make('UserController')->edit(0);
});
But the Laravel way would be to use RESTful resource controllers, which makes routes for create, edit and delete for you:
Route::resource('user', 'UserController');
Im not sure why you want to do this, but you can do something like this in your controller:
function newuser()
{
return $this->edit(0);
}
function edit($id)
{
// Do stuff
}
Is it possible to forward a request in Slim?
The meaning of "forward", like in JavaEE, is to internally redirect to another route without return the response to the client and maintaining the model.
For example:
$app->get('/logout',function () use ($app) {
//logout code
$app->view->set("logout",true);
$app->forward('login'); //no redirect to client please
})->name("logout");
$app->get('/login',function () use ($app) {
$app->render('login.html');
})->name("login");
In my opinion, the best way to do this would be by using Slim's internal router (Slim\Router) capabilities and dispatching (Slim\Route::dispatch()) the matched route (meaning: executing the callable from a matched route without any redirect). There are a couple of options that come to mind (depending on your setup):
1. calling a named route + callable doesn't take any arguments (your example)
$app->get('/logout',function () use ($app) {
$app->view->set("logout",true);
// here comes the magic:
// getting the named route
$route = $app->router()->getNamedRoute('login');
// dispatching the matched route
$route->dispatch();
})->name("logout");
This should definitely do the trick for you, but I still want to show the other scenarios ...
2. calling a named route + callable with arguments
The above example will fail ... because now we need to pass arguments to the callable
// getting the named route
$route = $app->router()->getNamedRoute('another_route');
// calling the function with an argument or array of arguments
call_user_func($route->getCallable(), 'argument');
Dispatching the route (with $route->dispatch()) will invoke all middleware, but here we are just calling the the callable directly ... so to get the full package we should consider the next option ...
3. calling any route
Without named routes we can get a route by finding the one matching the a http method and pattern. For this we use Router::getMatchedRoutes($httpMethod, $pattern, $reload) with reload set to TRUE.
// getting the matched route
$matched = $app->router()->getMatchedRoutes('GET','/classes/name', true);
// dispatching the (first) matched route
$matched[0]->dispatch();
Here you might want to add some checks and for example dispatch notFound in case no route is matched.
I hope you get the idea =)
There is redirect() method. However it sends an 302 Temporary Redirect response which you do not want.
$app->get("/foo", function () use ($app) {
$app->redirect("/bar");
});
Another possibility is pass() which tells application to continue to next matching route. When pass() is called Slim will immediately stop processing the current matching route and invoke the next matching route.
If no subsequent matching route is found, a 404 Not Found is sent to the client.
$app->get('/hello/foo', function () use ($app) {
echo "You won't see this...";
$app->pass();
});
$app->get('/hello/:name', function ($name) use ($app) {
echo "But you will see this!";
});
I think you have to redirect them. There is no forward in Slim. But you can set a status code for example in the redirect function. When you redirect to a route you should get that functionality you want.
// With route
$app->redirect('login');
// With path and status code
$app->redirect('/foo', 303);
here is an example from the documentation:
<?php
$authenticateForRole = function ( $role = 'member' ) {
return function () use ( $role ) {
$user = User::fetchFromDatabaseSomehow();
if ( $user->belongsToRole($role) === false ) {
$app = \Slim\Slim::getInstance();
$app->flash('error', 'Login required');
$app->redirect('/login');
}
};
};
If I have a silex route like:
$app->get('/project/{projectName}', function (Request $request, $projectName) use ($app) {
return $projectName;
})
->value('projectName', 'all')
->bind('project');
Why can't I define another route like:
$app->get('/projects', ...)
->bind('projects');
Whenever I try to access the /projects route I get redirected to /projects/ and shown an error message (NotFoundHttpException: No route found for "GET /projects/").
Is there some pluralization logic under the hood that prevents this or what else could be interfering here? (When renaming the second route to anything else it works just fine, so there is something specific to this project/projects naming, I assume.)
This is really strange. I tried this:
$app->get('/project/{projectName}', function (Request $request, $projectName) use ($app) {
return $projectName;
})
->value('projectName', 'all')
->bind('project');
$app->get('/projects', function(Request $request) use ($app) {
return 'TEST';
})
->bind('projects');
And calling /projects in the browser works for me. I get 'TEST' printed. This should work. Check your strings, maybe you misspelled something.
*EDIT 19.09.2013 *
You may also consider modifying your route matching by regular expressions. For this you can use the assert method. Here is an example:
$app->get('/{value}', function(Request $request) use ($app) {
return 'TEST';
})
->bind('projects')
->assert('value', '(projects)/{0,1}');
By using this method, I get 'TEST' when opening both /projects and /projects/. It all depends on what you want to achieve. Another helpful article might be How to allow slashes in routes (from the Symfony documentation)