Laravel routing url with variable order of parameters - laravel-4

I am looking at routing to a Controller for GET URL whose parameters can vary in number or the order in which they appear in the URL. There could be many such combinations and I want to invoke the same controller action for all of these URLs
Examples of how my URLs could look like:
Route::get('route1/id/{id}',
'Controller1#controllerAction1');
Route::get('route1/id/{id}/name/{name}',
'Controller1#controllerAction1');
Route::get('route1/name/{name}',
'Controller1#controllerAction1');
Route::get('route1/id/{id}/name/{name}/orderby/{orderby}',
'Controller1#controllerAction1');
Route::get('route1/id/{id}/orderby/{orderby}',
'Controller1#controllerAction1');
Also in the Controller action, I ultimately want to break this query string into an array. For the second example mentioned above, I want the query string id/{id}/name/{name} to be converted to array ('id' => {id}, 'name' => {name})
To invoke the same controller action for all different variations of the URLs, I have the following code in my routes.php:
Route::get('route1{all}', 'Controller1#controllerAction1')->where('all', '.*')
which seems to invoke the "controllerAction1" of Controller1 for the different types of URLs mentioned above.
And in the function controllerAction1, I am doing
$route_input = Route::input('all');
var_dump($route_input);
which prints "/id/1/name/xyz" when I hit http://example.com/laravel/public/route1/id/1/name/xyz
I would like to know if:
Doing Route::get('route1{all}',
'Controller1#controllerAction1')->where('all', '.*') is the right
method to invoke same action for variable combination of get
parameters? Does Laravel offer any function to convert
"/id/1/name/xyz" to array('id' => 1, 'name' => 'xyz') or I need to
write custom function? Is there a better way to achieve my
requirements?

I believe not. Plus, in this way you won't be able to understand which values are being passed.
Even if there is one, I think you don't actually need to pass the array. IMHO, I prefer to keep the items separate, then manipulate them from the controller. This is just my personal suggestion, but if you need an array of data, why don't you use a POST method? (the only right answer, is that you want the users to be able to save the link :P )
The complicated part about your request, is that you want to keep everything under the same controller action, which messes the routes. I would try this (in your routes.php):
Route::pattern('id', '[0-9]+');
Route::pattern('name', '[a-Z]+');
Route::get('route1/{id}/{name?}/{orderby?}', 'Controller1#controllerAction1');
Route::get('route1/{name}/{orderby?}', 'Controller1#controllerAction1');
In this way:
you can have a route with just the ID, where NAME and ORDERBY are optional
if no ID is passed, you can have a route with only NAME, where ORDERBY is optional
Note how this is different from your URLs: it's much more complicated to put the routes as you wrote them id/{id}/name/{name}, than in the way I proposed {id}/{name}. If you need them exactly your way, why don't you call the links passing the variables from the GET function as follows? http://www.yoursite.com/route1?id=xxxx&name=yyyy&orderBy=zzzz

To have the route parameters convert from a set of individual parameters to an array that contains all the parameters in Laravel 5, you can call this from the Controller:
$routeParameters = $this->getRouter()->getCurrentRoute()->parameters()
For the route definition
Route::get('route1/id/{id}/name/{name}', 'Controller1#controllerAction1');
if a user hits the route with the following: /route1/id/2/name/john
$routeParameters would equal
array(id => 2, name => 'john')

Related

Optional query with a lot of parameter

I must have build a query from my store items. my store items have 10 field . I just let customer search in my item's optional.
for example first one maybe want to filter on field1 , second one maybe want to filter on field1 and field2,third one maybe want to filter on field6 and field8 and filde9,... .
how can i make a query more short more efficient for this ?
note 1: I don't want to use Raw method because of its vulnerability.
note 2: i see some answers in link 1 and link 2 but I think first one can not be use for
condition like : where('field1','>=','somevalue') or where('field2','like','%somevalue%') or any sort of condition with some complexity and second one has more "if" chaining and i want to have shorter than this if it's possible
You can do this in several ways depending on the syntax you'd like. One possible way is to use a separation symbol to pass multiple arguments:
/api/user?where[]=user_id|>=|5
/api/user?where[]=user_id|2
/api/user?where[]=user_id|2&where[]=status|activated
This simply allows you to pass multiple where options where the pipe | operator separates the arguments. Note that this may cause issues if you want the pipe character to be available as search argument for instance.
Then you could simply parse this url into your query like so:
foreach($request->get('where') as $i => $values) {
$values = explode('|', $values);
// Allow the third argument to be exchanged with the second one,
// similar to how the Laravel `where()` method works.
$query->where($values[0], $values[1], $values[2] ?? null);
}
Optionally, you can add a validation method so that the syntax will be properly checked beforehand. You can add this snippet to some boot() method of a service provider:
\Illuminate\Support\Facades\Validator::extend('query_where', function($attribute, $value) {
// Require minimum length of 2 parameters.
return count(explode('|', $value)) >= 2;
});
Next, your validation in your controller action would look like this:
$this->validate($request, [
'where' => 'nullable|array',
'where.*' => 'query_where',
]);
The possibilities are endless.

How to pass Query parameter using route name in laravel?

I know this one
{{route('editApplication', ['id' => $application->id])}} == /application/edit/{id}
But I need
?? == /application/edit?appId=id
Anyone, please replace the "??" with your answer that helps me out.
It depends how you route looks like:
If you route is:
Route::get('/application/edit/{id}', 'SomeController')->name('editApplication');
when you use
route('editApplication', ['id' => 5])
url will be like this:
/application/edit/5
However all other parameters (that are not in route parameters) will be used as query string so for example:
route('editApplication', ['id' => 5, 'first' => 'foo', 'second' => 'bar'])
will generate url like this:
/application/edit/5?first=foo&second=bar
In case you want to achieve url like this
/application/edit?appId=id
you should define route like this:
Route::get('/application/edit/', 'SomeController')->name('editApplication');
and then when you use
route('editApplication', ['appId' => 5])
you will get
/application/edit?appId=5
url.
route method accepts any set of variable and puts them as query string unless the variable name matches with defined route signature.
Thus, for your case you can do something as follows:
route('editApplication', ['appId' => <your id here>])
You can provide any number of variables with the array.
You need to modift your "editApplication" route without parameter option. If you stil want the parameter just add the following row in your controller and just catch the data by using;
$appId = $request->input('appId');

How to convert CodeIgniter urls into user friendly ones?

I've explored lot of questions and articles regarding this but I can't find how to get this done.
I'm doing a website which provides specifications of several products such as phones, tablets, tv etc. Here's what I've:
Controller - Specs (create and display specification of all products)
Method - Display (fetches detailed specs of selected model and shows)
Method - Index (lists names of all models stored in the table. this is where I build anchor links)
Display method takes three arguments (1, 2, 3).
1 - Type of product (Phones, Tablets, TV etc)
2 - Model Slug (iphone-6, galaxy-tab-s3, bravia-kdl-50w800d etc)
3 - Model ID (1, 4, 13 etc)
My URLs right now are like this:
localhost/sitename/specs/display/phones/iphone-6/1
localhost/sitename/specs/display/tablets/galaxy-tab-s3/4
localhost/sitename/specs/display/tv/bravia-kdl-50w800d/13
What I want to achieve is URLs which are like this:
localhost/sitename/iphone-6
localhost/sitename/galaxy-tab-s3
localhost/sitename/bravia-kdl-50w800d
I don't mind restructuring my tables/controllers/methods or anything else if this can be achieved using whatever.
Thanks for reading.
Edit:
Route.php
$route['default_controller'] = 'Specs/index';
$route['404_override'] = 'Errors/show_404';
$route['translate_uri_dashes'] = FALSE;
This is how I'm building the anchor links (view_file->index.php, called from Index method):
<?php
foreach model(in the table)
echo anchor(specs_controller.display_function.product_type.model_slug.model_id, model_name);
end foreach
?>
I can get the desired URLs with following code in route.php. Only problem is I'm not able to make the 'urlController/urlMethod' return a value in the function which can be assigned to $result variable.
$route['(:any)'] = function ($1)
{
$result = 'urlController/urlMethod/'.$1;
return $result;
};
I'm not sure how to do this. Can someone suggest how I should call 'urlController/urlMethod'?
You could achieve it with CodeIgniter URI Routing. Considering
localhost/sitename/galaxy-tab-s3
maps to
localhost/sitename/specs/display/tablets/galaxy-tab-s3/4
And, model id i.e 4, in this case, is static with respect to galaxy tab s3, as you have not mentioned any such Id in the simplified URL.
My understanding is with every URL localhost/sitename/iphone-6, you need three details about the string 'iphone-6'. i.e. type of product, model-slug, model id. One way could be write something like
$route['sitename/(:any)'] = 'routingController/commonRoutingMethod/$1';
Here, create a new routingController and write some logic into commonRoutingMethod() method, which takes the string like iphone-6 and fetches its all three details i.e. product type, model id etc. And then redirects by building the exact URL using
header('Location: http://localhost/sitename/specs/display/$productType/$modelSlug/$modelId/');
NOTE : There could be more forward ways just using regex match in routes.php, given that you create diffrentiated structure of the string, based on product type and model id e.g p_iphone-6_1 or t_galaxy-tab-s3_4.
Please use below routing code, to achieve it.
localhost/sitename/specs/display/phones/iphone-6/1
localhost/sitename/specs/display/tablets/galaxy-tab-s3/4
localhost/sitename/specs/display/tv/bravia-kdl-50w800d/13
localhost/sitename/iphone-6
localhost/sitename/galaxy-tab-s3
localhost/sitename/bravia-kdl-50w800d
$route['(:any)'] = 'specs/display/$1/$1/$1';
Let me know if you need any help.

Laravel route in view and send autocomplete parameter to another page

I have two webpages A and B, A has a link button like this
Link
and B is a page about article lists, and has a table with column [#, books_name, author......]
And also, B has a query table to query data, user can input books_name or author_name, then it'll show the data user wants.
My question is, how to modify link in A Page and let it send autocomplete parameter to B?
The result of B's url may be like this
https://{B's path}/?q_author_name={the parameter from Page A}
Hope someone can help me. Thanks!
You can pass the query parameter as second argument to route()
{{ route('to_B', ['q_author_name' => 'Author']) }}
would generate
https://{B's path}?q_author_name=Author
provided you don't have any route parameters in your route definition like
Route::get("{B's path}/{param1}", function () {})->name('to_B');
in that case the first key from the route array would be passed to the param1 making your route as
https://{B's path}/Author

Duplicate parameter in web api

I have an issue regarding duplicate parameter in WebApi.
http://localhost:xxxxx/api/getbook?UserId=7 in this API Controller I have one parameter string UserId and works fine but if i do something like that
http://localhost:xxxxx/api/getbook?UserId=7?UserId=7 gets the result
So how to prevent duplicate parameter in API ?
A couple of things to note:
There would be an & character between the parameters i.e. http://localhost:xxxxx/api/getbook?UserId=7&UserId=7
The first parameter of the same name will be used by default if you are taking a model in to a controller method
If you are keen to throw some error when you discover duplicate parameter names then you could do the following:
var queryParameters = Request.GetQueryNameValuePairs()
.GroupBy(k => k.Key)
.Where(g => g.Count() > 1)
.Select(q => q.Key)
.ToList();
This will give you a List<string> of parameter names that appear more than once.
If you are interested in whether the parameter name and value combination is repeated (as in your example), then just GroupBy(k => k) instead and you will get a list of KeyValuePair to work with.

Resources