I am currently using CodeIgniter.
I am trying to write a function that can take an unlimited number of paramaters.
So in the controller it will be something like
function test($name, $others){
foreach($others){
//do something
}
}
and I could call it like
example.com/control/test/some name/param1/param2/param3/param4/param5...
How can I set this up?
you could also do it like this:
function foo($params=array())
{
$params=func_get_args();
//print_r($params);
}
so any url like:
site.com/controller/foo/param1/param2/param3/param4
would create an array of parameters.
You can get an associated array of URI segments with the uri_to_assoc function in the URI class. So in your controller, you might do something like this:
function test($name){
$uri_seg = $this->uri->uri_to_assoc(4);
foreach($uri_seg as $para){
// Do something with each of the URI segments passed in here after $name
}
}
It's not clear why you need an unlimited (variable) number of arguments, but you may want to consider why you need them.
You can use alternative URI semantics for certain types of arguments. Often the URI design is the path to a thing in a system. Unlimited parameters may not refer to the resource, but rather describe its attributes. Tags are a good example of this.
/chicken/red+tall+fat
Tags implement easily in CodeIgniter with a single parameter.
If the parameters refer to a node, you can consider a similar approach:
/hen-house.bunk4.topshelf/chicken
Or, if the hierarchy is important as a path, you can use the func_get_args() solution above.
Related
I am creating a simple product search engine in Laravel 5.2. I can use either get or post, whichever can accomplish what I'm wanting, even if I need to do some backend processing then pass the pretty URL to another method to show the products.
My parameters are
- query
- merchant
- brand
- page
- sort
All of these parameters can be used on their own or separately.
I'm wanting to use pretty URLs if at all possible.
Basically I want the URLs to look something like this:
/shop/query/shoes
/shop/query/shoes/brand/nike
/shop/query/sort/price
/shop/merchant/amazon
There can be many different routes formed by these 5 parameters, but they are all optional. So what is the best solution to making this route work how I'm wanting, without coding for every single possible route.
I'm sure I am overlooking something. I've used Zend Framework before and just use a * after shop and then I can pass anything in regardless.
If you need any other information, let me know. I appreciate any help.
Try something like this
Route::get('shop/{params?}', function(Request $request, $params = '') {
// everything after "shop/" will be in $params
// you need to add custom logic to parse and handle $params string
return $params;
})->where('params', '(([a-zA-Z0-9-_]+)\/?)+');
{params?} is Optional Parameter
Occasionally you may need to specify a route parameter, but make the presence of that route parameter optional. You may do so by placing a ? mark after the parameter name. Make sure to give the route's corresponding variable a default value
->where('params', ...) is Regular Expression Constraint
You may constrain the format of your route parameters using the where method on a route instance. The where method accepts the name of the parameter and a regular expression defining how the parameter should be constrained
NOTE
Make sure that you tweak (([a-zA-Z0-9-_]+)/?)+ regular expression to cover all of your cases, as this is something that I added to quickly test your examples
Is it OK to use
$id = $request->get('some_id');
instead of setting some parameters in Routes AND Controller like:
Route::get('some_page/{parameters}', 'controllerName#functionName');
function functionName($parameters)
{
$id = $parameters;
}
Appreciation
Of course it's good. When you're using GET, both ways are similar and if you like to use $request->get() for some reason, it's totally ok.
If you're using Form, it's the only right way. Plus, you can create custom Request class to use it for validation and other operations:
https://laravel.com/docs/master/validation#form-request-validation
They have two fundamentally different goals.
Using $request->get() is a way to retrieve a value from inside the php's REQUEST object regardless of its association with routing pattern you use.
Following HTTP's standards, you probably use $_GET to read some value without it changing the database [significantly] and you use $_POST to write data to you server.
While {pattern} in routing ONLY and ONLY should be used as a way for your application to locate something, some resource(s); in other words, its only goal is to help you route something in your server.
Nevertheless, in certain cases, such as /user/{id} the value of {id} might encounter some overlapping as to whether be treated as a route parameter or as a key of $_REQUEST.
Things such as tokens, filters criteria, sorting rules, referrers (when not significantly) etc. can be read right from $_REQUEST without interfering them into routing pattern of you application.
I am using Laravel. I would like users to be able to perform a search on my website using up to 3 criteria. These criteria are: Class, Brand and Model.
They should be free to use any or all of them when searching. As the relationship between these isn't as simple as Many->1, Many->1, Many->1, and also given the criteria will be numbered if blank, I dont want to use pretty urls to post the search criteria as they would look like this:
/SearchResults/0/BMW/0
which is meaningless to users and search engines. I therefore want to use normal dynamic addresses for this route as follows:
/SearchResults/?Class=0&Brand="BMW"&Model=0
How do I define a route that allows me to extract these three criteria and pass it to a custom method in my resource controller?
I have tried this but it isnt working:
Route::get('/SearchResults/?Class={$class}&Brand={$brand}&Model={$type}', 'AdvertController#searchResults');
Many thanks
The Symfony Routing components fetch the REQUEST_URI server variable for matching routes, and thus Laravel's Route Facade would not pick up URL parameters.
Instead, make use of Input::get() to fetch them.
For example, you would start by checking if the class param exists by using Input::has('class'), and then fetching it with Input::get('class'). Once you have all three, or just some of them, you'd start your model/SQL query so that you may return your results to the user.
You will need to route all to the same method and then, within the controller, reroute that given action to the correct method within the controller.
For that, I recommend using the strategy pattern (read more here).
I would do something like this:
route.php
Route::get('/SearchResults', 'AdvertController#searchResults');
AdvertController.php
use Input;
...
private $strategy = [];
public function __construct(){
$strategy = [
/*class => handler*/
'0'=> $this->class0Handler,
'1'=>$this->class1Handler,
...];
}
private function class0Handler(){
//your handler method
}
public function searchResults(){
if( !array_key_exists(Input::get('class'),$this->strategy))
abort(404);
return $this->strategy[Input::get('class')]();
}
In case you are breaking down search by other types, you define the handler in the $strategy variable.
Strategy pattern has a lot of benefits. I would strongly recommend it.
I'm making a tutorialsystem with Codeigniter, but I'm a bit stuck with using subcategories for my tutorials.
The URL-structure is like this: /tutorials/test/123/this-is-a-tutorial
tutorials is the controller
test is a shortcode for the category
123 is the tutorial ID (used in the SQL query)
this-is-a-tutorial is just a slug to prettify the URL
What I do is passing the category as a first parameter and the ID as a second parameter to my controller function:
public function tutorial($category = NULL, $tutorial_id = NULL);
Now, if I want subcategories (unlimited depth), like: /tutorials/test/test2/123/another-tutorial. How would I implement this?
Thanks!
For reading infinite arguments, you have at least two useful tools:
func_get_args()
The URI class
So in your controller:
Pop the last segment/argument (this is your slug, not needed)
Assume the last argument is the tutorial ID
Assume the rest are categories
Something like this:
public function tutorial()
{
$args = func_get_args();
// ...or use $this->uri->segment_array()
$slug = array_pop($args);
$tutorial_id = array_pop($args); // Might want to make sure this is a digit
// $args are your categories in order
// Your code here
}
The rest of the code and the validation depends on what specifically you want to do with the arguments.
If you need variable categories you could use the URI class: $this->uri->uri_to_assoc(n)
Another option you may want to consider is CodeIgniter's controller function remapping functionality which you can use to override the default behaviour. You would be able to define a single function inside a controller that would handle all the calls to that controller and have the remaining URI parameters passed in as an array. You could then do whatever you want with them.
See here for the docs reference on the matter.
Whenever I try to pass a variable through url with the l() function like:
l(t($row['salon_name']),'admin/content/edit-salons-products-services?sid='.$row[salon_id] );
? is replaced by "%3F"
= is replaced by "%3D"
Why is this happening and how can I fix it?
Change it to: 'admin/content/edit-salons-products-services/.$row[salon_id]'.
You can access the salon id with arg(3).
You may also need to change your module's menu declaration to allow this URL.
As Finbarr said, it's often better to pass variables as path components, rather than query parameters, but query parameters are still possible with l().
Query parameters are passed into l() outside the base $path, in the $options parameter. This makes it easier to programmatically alter query values, without needing to parse a string. What you want is something like this:
l(t($row['salon_name']),'admin/content/edit-salons-products-services', array('query' => array('side' => $row['salon_id'])));