Laravel 5.2 Routing with optional params - php

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

Related

It is possible to pass 2 differents types of parameters to a Laravel controller?

I already have a GET route with an URI /projects/{id} which displays Infos of a project with a given id. I also have a GET index route (/projects), which shows all my projects.
My problem is that I currently try to create different indexes (for example one which only displays the projects where I am assigned [e.g. on /projects/mines], or the projects which are pending administrator approval [e.g. on /projects/proposals], and still others displays).
So I want to know if I can have two GET routes /projects/{id}and /projects/{display_mode} which will be calling two differents methods of my ProjectController (respectively show and index).
Thanks for your help! :)
You may have one route /projects which returns all projects as default.
If there is query parameter like
/projects?displayMode=proposals
then you can apply filters.
In your controller it would look something like this
$projects = Project::query();
if ($request->query('displayMode') == 'proposals')
$projects->where('pending', true)
return $projects->get();
You can add multiple filters too in the same way
I'm not sure about specific Laravel options for the route definitions (sorry!), but if the {id} will always be an integer and {display_mode} will always have non-digits in it, you could keep just one route, but do the conditional handling in your controller. Just have the mainAction do something likeā€¦
return preg_match('/^\d+$/', $param) ? idHelperAction($param) : displayModeHelperAction($param);
Then create those two helper functions and have them return whatever you want.
$param is supposed to be whatever you get from that route parameter -- /projects/{param}.
That should call the idHelperAction for routes where $param is all digits and nothing else; otherwise, it should call the displayModeHelperAction. Either way, it sends the same $param to the helper function and returns whatever that helper function returns -- effectively splitting one route definition into two possible actions.
Of course, you might have to add some context in the code sample. If the functions are all defined in the same class, you might need to use $this->idHelperAction($param) or self::idHelperAction($param) (and the same with the other helper action), depending on whether it's static or not; or tell it where to find the functions if you put them in another class, etc., etc. -- all the normal contextual requirements.

Is it good to use ( $request->get('sth') ) instead of ( setting some parameters ) in controller function in Laravel

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.

Codeigniter complex wildcard Routing

Hi guys I am trying to achieve something that I hope is possible but couldn't find the right way to find.
I am using codeigniter 2.2.0
I want to use an url in codeigniter like
domain/username/controller/method/$args
Let me explain When user types an url like
domain/mike/job/editJob/12/urgent/
Here "mike" is someone's user name
"job" will be a controller alias
"editJob" will be a method
"12" and "urgent" will be parameter of editJob method.
editJob method will have three parameters.
I want "mike" as 1st parameter,
then "12" and "urgent" as second and third parameter.
So far what I have done in my routes
$route['(:any)/job/(:any)'] = 'job_c/$2/$1';
When I type in the url
domain/mike/job/editJob/12/urgent
in Job controller I get
"12" as first parameter
"urgent" as second parameter
and "mike" as third parameter
**
Is there any possible way to get "mike" as first parameter and then the rest is okay**
Edited:
One more thing if I pass three parameters after method then I am not
getting the username!!
I need to have the username as first parameter because there may have multiple parameters in any method and there is a possibility to have conditional parameters as well.
One more thing I want to know. Is it possible to make such route that will work the same as my given route but the controller alias will also be wildcard. Or if there is any way to check if a segment in url is a controller then one route and if not a controller then something else should happen.
I am not a well describer still tried to keep it simple. If anyone knows something that will help me a lot.
Thanks
UPDATE
Is there any way to keep the username "mike" in session from routes.php file thus I don't have to pass this as a parameter.
Updating Again
I have solved the issue somehow.
I am using
$route['(:any)/garage/([^/]*)/([^/]*)/(.*)'] = '$2/$3/$1/$4';
Here garage is nothing but a simple identifier for the route. This route will work when it gets garage as a second segment in url. It will work like
domain/user/garage/anyControler/anyMethod/manyParameters
It's completely dynamic only the garage is used as identifier. If you want you can use your controller name instead of using any identifier. then you don't have to declare same thing multiple times for multiple controllers but it will work fine. It will work for any controller and any method. In addition it supports dynamic number of parameters.
I don't know if there is any better way to do this but it solves my issue. If anyone know something better then this then please share.
I think what is happening is that you are accessing
domain/mike/job/editJob/12/urgent
and its being parsed like:
job_c/editJob/12/urgent/mike
Because:
$route['(:any)/job/(:any)'] = 'job_c/$2/$1';
$2 = (:any)/job/(:any) = editJob/12/urgent
$1 = (:any)/job/(:any) = mike
Substituting:
job_c/editJob/12/urgent/mike
You could try to keep your route as similar as your current one:
$route['(:any)/job/(:any)/(:any)'] = 'job_c/$2/$1/$3';
This will allow you to match $2 to any method name, and have $1 as the first parameter and $3 as the rest of params.
But, I would suggest, if this is a very specific route, substituting the $2 :any, with the actual method name and the expected type of the params, otherwise, you might receive unexpected values to every method in the matching controller.
I would use something like:
$route['(:any)/job/editJob/(:num)/(:any)'] = 'job_c/editJob/$1/$2/$3';
Hope this helps.
Update:
For the controller matching: Code Igniter uses the form controller/method/param1/param2/...
As long as you create routes that matches controllers, methods and params in that order, you can do anything.
$route['(:any)/(:any)/(:any)'] = '$1/$2/$3';
or just
$route['(:any)'] = '$1';
and hopefully it will contain a controller and method and the required params.
I think this will totally be missing the point of having a routing system.

How to build optional parameters as question marks in Slim?

I've built my first RESTful API ever and used Slim as my framework. It works well so far.
Now I have seen a great API Design Guide which explained, the best way to build an API is to keep the levels flat. I want to do that and try to figure out how to build an URI like this:
my-domain.int/groups/search?q=my_query
The /groups part already works with GET, POST, PUT, DELETE and also the search query works like this:
my-domain.int/groups/search/my_query
This is the code I use for the routing in PHP:
$app->get('/groups/search/:query', 'findByName');
I just can't figure out how to build optional parameters with an question mark in Slim. I wasn't able to find anything on Google.
EDIT:
Since the search not seems to be suitable for my scenario I try to show another way of what I want to realize:
Let's say I want to get a partial response from the API. The request should look like that:
my-domain.int/groups?fields=name,description
Not like that:
my-domain.int/groups/fields/name/description
How do I realize that in the routing?
The parameters supplied with the query string, the GET parameters, don't have to be specified in the route parameter. The framework will try to match the URI without those values. To access the GET parameters you can use the standard php approach, which is using the superglobal $_GET:
$app->get('/groups/test/', function() use ($app) {
if (isset($_GET['fields']){
$test = $_GET('fields');
echo "This is a GET route with $test";
}
});
Or you can use the framework's approach, as #Raphael mentioned in his answer:
$app->get('/groups/test/', function() use ($app) {
$test = $app->request()->get('fields');
echo "This is a GET route with $test";
});
Ok I found an example that does what I need on http://help.slimframework.com/discussions/problems/844-instead
If you want to construct an URI Style like
home.int/groups/test?fields=name,description
you need to build a rout like this
$app->get('/groups/test/', function() use ($app) {
$test = $app->request()->get('fields');
echo "This is a GET route with $test";
});
It echoes:
This is a GET route with name,description
Even though it's not an array at least I can use the question mark. With Wildcards I have to use /
You may also have optional route parameters. These are ideal for using one route for a blog archive. To declare optional route parameters, specify your route pattern like this:
<?php
$app = new Slim();
$app->get('/archive(/:year(/:month(/:day)))', function ($year = 2010, $month = 12, $day = 05) {
echo sprintf('%s-%s-%s', $year, $month, $day);
});
Each subsequent route segment is optional. This route will accept HTTP requests for:
/archive
/archive/2010
/archive/2010/12
/archive/2010/12/05
If an optional route segment is omitted from the HTTP request, the default values in the callback signature are used instead.
Search query is not suitable for url parameters, as the search string might contain url separator (/ in your case). There's nothing wrong to keep it as query parameter, you don't have to push this concept everywhere.
But to answer your question, optional parameters are solved as another url:
$app->get('/groups/search/:query', 'findByName');
$app->get('/groups/search/strict/:query', 'findByNameStrict');
EDIT: It seems you want to use Slim's wildcard routes. You just need to make sure there's only one interpratation of the route.
$app->get('/groups/fields/:fields+', 'getGroupsFiltered');
Parameter $fields will be an array.

How can I change Zend Framework's routing schema to not use key/value pairs?

Rather than using controller/action/key1/value1/key2/value2 as my URL, I'd like to use controller/action/value1/value2. I think I could do this by defining a custom route in my Bootstrap class, but I want my entire application to behave this way, so adding a custom route for each action is out of the question.
Is this possible? If so, how would I then access valueN? I'd like to be able to define the parameters in my action method's signature. e.x.:
// PostsController.php
public function view($postID) {
echo 'post ID: ' . $postID;
}
I'm using Zend Framework 1.9.3
Thanks!
While I don't think it's possible with the current router to allow N values (a fixed number would work) you could write a custom router that would do it for you.
I would question this approach, however, and suggest that actually listing all of your routes won't take long and will be easier in the long run. A route designed as you've suggested would mean that either your named parameters are always in the same order, i.e.
/controller/action/id/title/colour
or that they are almost anonymous
/controller/action/value1/value2/value3
With code like
$this->getRequest()->getParam('value2'); //fairly meaningless
Does it have to be N or can you say some finite value? For instance can you imagine that you'll never need more than say 5 params? If so you can set up a route:
/:controller/:action/:param0/:param1/:param2/:param3/:param4
Which will work even if you don't specify all 5 params for every action. If you ever need 6 somewhere else you can just add another /:paramN onto the route.
Another solution I've worked with before is to write a plugin which parses the REQUEST_URI and puts all the extra params in the request object in the dispatchLoopStartup() method. I like the first method better as it makes it more obvious where the params are coming from.

Categories