is there any possible way to send parameters within the redirection function from Codeigniter 4?
Important, it is a named route:
$routes->get('edit', 'Test_Controller::editTest/$1', ["as" => "editTest", "filter" => 'testFilter']);
And i want to do a redirect like this:
this works fine:
return $this->redirectTo('test/edit/' . $id1);
this would be nice, if it works:
return redirect('editTest', array($passingID));
or
return redirect('editTest')->with($passingID);
Why? I have HMVC and I would like to name every module with the same routes but different functions ofc. And this would help me having same site urls. (edit, add, a.s.o.)
The short answer is no its not possible. Take a look at system/Common.php and you'll see there is only 1 parameter to the redirect() function.
The longer answer however is take a look at what the redirect function does.
function redirect(?string $route = null): RedirectResponse
{
$response = Services::redirectresponse(null, true);
if (! empty($route)) {
return $response->route($route);
}
return $response;
}
Based on the current (4.1.4) redirect function you'll see it calls route(). It turns out that route() allows a second parameter which are the parameters.
So the solution would probably be to do your own redirect() function (see https://codeigniter.com/user_guide/extending/common.html?highlight=common) and allow a second parameter.
Related
If I have a function that checks to see if a string is numeric and redirects back if it is not but does nothing if it is ie
function check_numeric(string $param) {
if(!is_numeric($param)) {
return Redirect::back()->with('Failed', 'Number!');
}
}
How would I test this in PHPUnit? I have tried to use assertRedirect but I am not sure of how to implement it (if it is even possible)
To be clear. The check_numeric() function is a standalone function that is imported into controllers to be used by the different controller classes. The fucntion itself does not have a class nor a route.
What I would like to do is test the function directly without its use in a controller or route.
I can test the pass cases by doing:
$this->assertNull(check_numeric('1')); // does what I want!!
However I would also like to directly check the fail cases with something like
$previousUrl = '/';
$this->from($previousUrl)->(check_numeric('five'))->assertRedirect($previousUrl);
I think there is not automatic way to check if it's redirecting back, but you can build it.
To approaches comes to mind.
All samples assumed under phpunit, test extending Tests\TestCase;
1 - Check the URL before you make the request
$currentUrl = "/";
$response = $this->post('check-number', "five" );
$response->assertRedirect($currentUrl);
2 - Validate the message you're sending back when the validation fails.
$response = $this->post('/check-number', "five" );
$this->followRedirects($response)->assertSee('Failed');
YourController.php
function check_numeric(string $param) {
if(!is_numeric($param)) {
return Redirect::back()->with('Failed', 'Number!');
}
}
web.php
Route::post('/check-number', 'App\Http\Controllers\YourControllerController#check_numeric');
In the other hand, responding to your previous question, if you want to test the function directly, you have to go with what you're expecting, in this case you're not returning anything if everything is OK, so the way to go on that case would be:
$this->assertNull(app('App\Http\Controllers\YourControllerController')->check_numeric("five"));
This would fail, if you pass a number it would pass.
Doesthat help?
After logout, I tried to redirect for the home page. I tried to few ways, but not redirected.
class User extends BaseController
{
public function __construct()
{
helper('url');
}
for the logout function. I used three ways
redirect('/');
or
header("Location:".base_url());
or
route_to('/');
as per CI 4
use
return redirect()->to('url');
if you are using route then use
return redirect()->route('named_route');
I use this and it works
return redirect()->to(site_url());
In codeigniter 4 redirect()->to() returns a RedirectResponse object, which you need to return from your controller to do the redirect.
for ex.
class Home extends BaseController {
public function index() {
return redirect()->to('https://example.com');
}
}
I am new to CI4. In my case, I had to properly set $baseURL in App.php. For example, if the port is set incorrectly in your local development, it will just hang.
eg. public $baseURL = 'http://localhost:8888/';
Its worth saying that unlike the former CI3 redirect() function this one must be called from within a Controller. It won't work for example within a Library.
Update 2021
It is in fact possible to do this! Simply check that the returned response is an object and return it instead. So if a library returns a RedirectResponse, check it using the following code and return if applicable.
if (!empty($log) && is_object($log)){
return $log;
}
You could of course do get_class() to make sure the object is a type of RedirectResponse if there is any possibility of another object being returned.
If you using unnamed route:
$this->response->redirect(site_url('/user'));
'/user': It is my controller name. You can also used controller/function name.
Please look at the documentation
// Go back to the previous page
return redirect()->back();
// Go to specific URI
return redirect()->to('/admin');
// Go to a named route
return redirect()->route('named_route');
// Keep the old input values upon redirect so they can be used by the old() function
return redirect()->back()->withInput();
// Set a flash message
return redirect()->back()->with('foo', 'message');
// Copies all cookies from global response instance
return redirect()->back()->withCookies();
// Copies all headers from the global response instance
return redirect()->back()->withHeaders();
If you find:
{0, string} route cannot be found while reverse-routing
This error:
Please Go to system\HTTP\RedirectResponse Line no 91 :
Change:
throw HTTPException::forInvalidRedirectRoute($route);
To:
return $this->redirect(site_url('/Home'));
(dashboard after login)
The redirect statement in code igniter sends the user to the specified web page using a redirect header statement.
This statement resides in the URL helper which is loaded in the following way:
$this->load->helper('url');
The redirect function loads a local URI specified in the first parameter of the function call and built using the options specified in your config file.
The second parameter allows the developer to use different HTTP commands to perform the redirect "location" or "refresh".
According to the Code Igniter documentation: "Location is faster, but on Windows servers it can sometimes be a problem."
Example:
if ($user_logged_in === FALSE)
{
redirect('/account/login', 'refresh');
}
Original Answer: https://stackoverflow.com/a/725200/5700401
I am currently using the lumen framework (5.6) to build an API, this API can be used to request a page by for example its title. The route for this is:
Route::group(["prefix" => '/api/v1', "middleware" => ["ContentTypeJson","Paginator"]], function () {
Route::group(["prefix" => '/{databaseIdentifier}', "middleware"=>"DatabaseIdentifier"], function () {
Route::group(["prefix" => '/pages'], function () {
Route::group(["prefix" => '/{title}'], function () {
Route::get("/", "PageController#getPageByTitle");
Route::get("/parents", "SearchController#getParentalSpecies");
Route::get("/all", "PageController#getPageByTitleWithLinks");
Route::get("/overlap/{overlapProperty}", "PageController#getPagesWithOverlap");
Route::put("/", "PageController#overwritePage");
});
});
});
As you can see the title is used in multiple functions and controllers, the same applies to the databaseIdentifier which is used in the middleware to determine which database needs to be used.
However all url parameters with a space will be converted with %20 instead of a space, which is the expected behaviour. However I would like to convert this back to the raw string, which can be done with urldecode().
But since this is applied in every controller and function I would like to use some kind of preprocessing step for this.
I have tried using a middleware for this to alter the route parameters as suggested here (using $request->route()->setParameter('key', $value);).
Unfortunately this does not work in lumen since the result of $request->route() is an array and not an object. I have tried altering this array but I can not get it to change the actual array in the Request object. No error appears here.
So in short: I am looking for a way to urldecode every URL parameter which is passed to my controllers and functions without putting $param = urldecode($param); everywhere.
If you need more information feel free to ask
Thank you in advance
For anyone who also encounters this issue I have found a solution using middleware.
In the middleware I do the following:
public function handle(Request $request, Closure $next)
{
$routeParameters = $request->route(null)[2];
foreach ($routeParameters as $key=>$routeParameter) {
$routeParameters[$key] = urldecode($routeParameter);
}
$routeArray = $request->route();
$routeArray[2] = $routeParameters;
$request->setRouteResolver(function() use ($routeArray)
{
return $routeArray;
});
return $next($request);
}
This code will decode every route parameter and save it in an array, then I take the whole route array which is created by lumen itself (which contains the url encoded parameters), these are then replaced with the url decoded version of the parameter. This is not enough because this does not affect the route array in the Request object.
In order to apply these changes I alter the routeResolver so it will return the changed array instead of the one created by lumen.
I have a problem with Laravel 5, and to be precise, I can't find the solution for it.
In C# (ASP.NET MVC) it's easy to solve.
For example, I have these routes (I'll just type the route content, and the function header, for the sake of simplicity)
/{category}/Page{page}
/Page{page}
/{category}
The function is defined inside Product controller.
function header looks like this:
public function list($page = 1, $category = null)
the problem is, whenever I enter just one argument, it doesn't send the value for the parameter by the name I set in the route, but rather, it pushes values by function parameter order.
So, when I open /Page1, it works properly, value of 1 is sent to $page variable,
but when I access /Golf(made up on the spot), it also sends the value to the $page variable.
Any possible idea how to avoid this, or do I really need to make different functions to handle these cases?
In C#, it properly sends the value, and keeps the default value for undefined parameter.
Hope you have an answer for me.
Thank you in advance and have a nice day :)
So, as you've seen the parameters are passed to the function in order, not by name.
To achieve what you want, you can access these route parameters from within your function by type hinting the request object to it like this:
class ProductController extends Controller
{
function list(Request $request){ # <----------- don't pass the params, just the request object
$page = $request->route('page'); # <--- Then access by name
$category = $request->route('category');
dd("Page: $page | Category: $category");
}
}
Then of course you would set all 3 of your routes to hit that same controller method:
Route::get('/{category}/Page{page}', 'ProductController#list');
Route::get('/Page{page}', 'ProductController#list');
Route::get('/{category}', 'ProductController#list');
Hope this helps..!
if you want to get the parameters in your controller, you can use this:
public function list() {
$params = $this->getRouter()->getCurrentRoute()->parameters();
}
for /aaa/Page3, the $params would be array(category => 'aaa', page => '3')
for /Page3, the $params would be array(page => '3')
for /aaa, the $params would be array(category => 'aaa')
My desired URL structure for a section of a web application is as follows:
/user/FooBar42/edit/privacy, and I would like this to route to controller: user, function: edit, with FooBar42 and privacy as arguments (in that order). How should I accomplish this with CodeIgniter?
Defining this route in application/config/routes.php should work:
$route['user/(:any)/edit/(:any)'] = "user/edit/$1/$2";
However, be aware that (:any) in the above route would match multiple segments. For example, user/one/two/edit/three would call the edit function in the user controller but only pass one as the fist parameter and two as the second.
Replacing the (:any) with the regex ([a-zA-Z0-9]+) will only allow one only alphanumeric values of length at least 1. This mitigates the issue above, where a / would be permitted allowing multiple segments to be allowed. Now, if user/one/two/edit/three was used, a 404 page would be shown.
$route['user/([a-zA-Z0-9]+)/edit/([a-zA-Z0-9]+)'] = "user/edit/$1/$2";
You can also use the remapping option of the CI controller
http://ellislab.com/codeigniter/user-guide/general/controllers.html#remapping
and doing something like this:
public function _remap($method, $params = array())
{
// check if the method exists
if (method_exists($this, $method))
{
// run the method
return call_user_func_array(array($this, $method), $params);
}
else
{
// method does not exists so you can call nay other method you want
$this->edit($params);
}
}