How to create optional REST parameter in Laravel - php

I'd like my API to handle calls of the such:
/teams/colors
/teams/1/colors
The first would return all colors of all teams, the second would return colors of team 1 only.
How would I write a route rule for this in Laravel?

This should be simple using a laravel route.
Route::pattern('teamid', '[0-9]+');
Route::get('/teams/{teamid}/colors', 'controller#method');
Route::get('/teams/colors', 'controller#method');
Using the pattern, it lets you specify that a route variable must match a specific pattern. This would be possible without the pattern also.
I noticed you mentioned REST in the title. Note that my response is not using Laravel's restful routes system, but its normal routes system, but I'm sure this could be adapted to be restul, or work with the restful system.
Hope this helps.
Edit:
After a bit of looking around, you may be able to use this if you are using Route::resource or Route::controller.
Route::resource('teams', 'TeamsController');
Route::any('teams/{teamid}/colors', 'TeamsController#Method');
// Or to use a different route for post, get and so on.
Route::get('teams/{teamid}/colors', 'TeamsController#getMethod');
Route::post('teams/{teamid}/colors', 'TeamsController#postMethod');
Note: the resource word above can be replaced with ::controller.
*Note 2: I have not tested this and am unable to guarantee it would work, but it does seem possible.*

You may try something like this:
class TeamsController extends BaseController {
// GET : http://example.com/teams
public function getIndex()
{
dd('Colors of all teams');
}
// GET : http://example.com/teams/1/colors
public function getColorsById($id)
{
dd("Colors of team $id");
}
// This method will call the "getColorsById" method
public function missingMethod($parameter = array())
{
if(count($parameter) == 2) {
return call_user_func_array(array($this, 'getColorsById'), $parameter);
}
// You may throw not found exception
}
}
Declare a single route for both methods:
Route::controller('/teams', 'TeamsController');

Related

Resource Controller methods with model as parameter not working

As in the basic Laracasts.com tutorial (Laracast 5.7 from scratch) I'm trying to use the following methods public function show(prototypes $prototypes) parameter to construct a view. However my view is created correctly but $prototypes is null.
The route works well(/prototypes/1/edit) and I ensured that a prototype object with the id 1 exists.
I found some older solution which stated to use something like (integer $id) as parameter but this leads to some more code. It should work like this:
Controller:
public function edit(prototypes $prototypes)
{
//
return view('prototypes.edit', compact('prototypes'));
}
According to Laracast From Scratch this should work.
Do you know how I could fix this?
What mechanism is behind this that the prototypes.edit method knows how to use the correct parameter?
For the Implicit Model Binding to works the injected variable name should match the route parameter name, in your case I think that your parameter name could be {prototype}, you can verify it by issuing the command php artisan route:list in the console.
If that is true you have to change the variable name to $prototype (please note the singular) in your controller function to match the parameter name {prototype}, like this:
public function edit(prototypes $prototype)
{
return view('prototypes.edit', compact('prototype'));
}
Update: BTW the laravel convention on Model's name is singular camel case, in your case your Model should be named Prototype not prototypes, i.e.:
public function edit(Prototype $prototype)
{
return view('prototypes.edit', compact('prototype'));
}
In order to inject the Prototypes model into the controller variable $prototypes, Laravel is expecting a matched name from the route to the input of the method. So in your routing, this:
/prototypes/1/edit
Needs to be
/prototypes/{prototypes}/edit
in order for the edit method to inject the correct instance of your prototypes model.

Two Controllers and 1 View in Laravel

I have one issue to solve about some calculations in Laravel 5.1, and until now the best solution that I found is to create Two different controllers, one to handle calculation for a specific item:
Route::get('company/convert/{note}','ScenarioController#NoteConvert');
And one for all items:
Route::get('company/convert','ScenarioController#AllNotesConvert');
Both will use render the same view.
My question is: Is a good practice to do this ?
In my head one good solution is to use just one route and receive 1 specific note or all of them in some variable through the request.
Something like:
$http.get('/company/convert/',data)
Where data will receive 1 or all notes that will be converted.
P.S.: I'm using AngularJS to call this routes.
If you prefer having one method in your controller you have to change your route a bit:
Route::get('company/convert/{note?}','ScenarioController#NoteConvert');
And your method would be something like
public function NoteConvert($note=null)
{
if ($note == null) {
// do all convertions
return view()
}
// single convertion
...
}
This way NoteConvert method will be the one that will handle multiple and single convertions.
Don't forget to remove
Route::get('company/convert','ScenarioController#AllNotesConvert');
It won't be necessary anymore
Edit:
https://laravel.com/docs/5.2/routing#parameters-optional-parameters
the best way for me, will be to passe an optional parameter in the url and check it on the controller.
i think your task is to produce the data of all items and specific data with filter using note argument in the view.
i reccomend you to create the route like this
Route::controller('company', 'ScenarioController');
then create a controller with two function like this
public function getIndex()
{
return view('convert');
}
here convert is name view blade .
public function postFilter($note)
{
$x= // do what you want
return view('convert', compact('x'));
}
then add a filter in the blade using a checkbox and make the form action url as
"company/filter/{note}".
this is the better practice i think.
refer implicit routing here. https://laravel.com/docs/5.1/controllers

Respect/Rest uri part corresponds to controller name

i'm trying to implement Respect/Rest in my existing CMS.
The Problem:
I would like to create a single magic route to works like: /admin/*/save, calls the * controller...
I would like to make something like this:
$r->any('/admin/*/save/*/', function($controller, $id = null) use ($r) {
return $r->dispatchClass($controller,array($id));
});
Note that i don't know which HTTP method user is using.
Actually I "solved" this problem with something like:
$r->any('/admin/*/save/*/', function($controller, $id = null) use ($tcn) {
$r = new Router;
$r->any('/admin/*/save/*/', $tcn($controller . '_save'), array($id));
return $r->run();
});
$tcn is a named function that returns the full namespace of the controller.
I know it's not a good approach.
EDIT:
This project wants to be Open Source, but it's still being created.
We're trying to transport an old project made on functional paradigm to OOP.
We are trying to learn about OOP while making an useful project.
Actuall state of the files can be found at: https://github.com/dindigital/skeleton
Alganet: The bootstrap for admin routes can be found at: https://github.com/dindigital/skeleton/blob/master/admin_routes.php
A simple controller sample: https://github.com/dindigital/skeleton/blob/master/src/app/admin/controllers/TagController.php
https://github.com/dindigital/skeleton/blob/master/src/app/admin/controllers/TagSaveController.php
I liked the Forwards and also the Factory approach... I could not decide yet.
Tricky question! That depends a lot of why are you making these routes dynamic. Can you show us some sample structure for your controllers so I can improve the answer?
Meanwhile, two native features that can help:
Forwards
You can treat the problem as an internal forward (does not make redirects). It's normally to redirect to other static routes, but you can redirect to a new one as well:
$r->any(
'/admin/*/save/*/',
function ($controller, $id) use ($tcn, $r) {
return $r->any(
"/admin/$controller/save",
$tcn($controller . '_save'),
array($id)
);
}
);
Factory Routes
Also, Respect\Rest implements factory routes. It is experimental but stable in tests:
$r->factoryRoute(
'ANY',
'/admin/*/save/*/',
'MyAbstractController',
function ($method, array $params) use ($tcn) {
return new $tcn($params[0] . '_save');
}
);

How to define routes with multiple parameters without pretty urls in Laravel

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.

How to reference a function after an argument in CodeIgniter URLs?

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);
}
}

Categories