I am wondering is it possible to do something similar to route model binding, but with request headers. I have a query that I check on my api endpoints, that looks like this:
User::where('telephone', $request->header('x-user'))->firstOrFail();
Is it possible to somehow avoid repeating this query in every method in controllers, but to apply it to routes, so that I could just get the user object just like in a route model binding with type hinting in a function, for every route that in an api routes folder:
public function userTransactions(User $user)
{
//
}
Create a middleware and assign it to the desired routes.
Option 1
In your middleware do:
$user = User::where('telephone', $request->header('x-user'))->firstOrFail();
request()->merge(['user_model' => $user]);
You can then request()->get('user_model') anywhere in your controller
Option 2
Start by creating a global scope class that conforms to your query. Here you'd get the header value and use that in the scope.
https://laravel.com/docs/5.5/eloquent#global-scopes
Next in the middleware, add the scope to the model using addGlobalScope
User::addGlobalScope(new HeaderScope())
Now all queries for User will have a where clause with your header value.
You can subsequently remove the scope or ignore global scopes if needed.
Related
Is there any way to customize what a controller returns based on a parameter (not a query parameter) provided in a route? For example, if there are two modes of display, but it depends on the URL accessed as far as which way it's displayed.
A simplified, made up example:
class MyController extends Controller
{
// $display_mode can be "large" or "small"
public function show($display_mode = null)
{
...
}
}
Route:
For /page1 I want $display_mode to be "large", for /page2, I want it to be "small." How do I pass that in via the function parameter? This would be the preferred way, but if Laravel does this a different way, let me know.
Route::get('/page1', [MyController::class, 'show']);
Route::get('/page2', [MyController::class, 'show']);
To get a better idea of what I want to accomplish. Say the controller function has five different customizable parameters based on both display and business logic. I can't know in advance what options will apply to the pages that the developer creating routes will want to display. I just want to make those options available.
Also, the developer making the routes does not want to make URLs with ugly paths such as mypage/large/tiled/system-only. The end user doesn't need to know about all of the options passed in as parameters to a function.
Rather, the routes should only be /a, /b, and /c and each of those routes underneath the hood represents zero to five customizable options by passing in the options as parameters to the controller function.
edit:
I tried the defaults() method and it works well. Note that in order for it to work, a separate default() call has to be made for each function parameter. For example:
Route::get('/login/main', [WAYFController::class, 'wayf'] )
->defaults('tiledUI', false)
->defaults('showAffiliateLogin', true)
->defaults('type', 'full');
Yea, you can do this. You can use the defaults method of the Route to pass a default value for a parameter:
Route::get('testit', function ($display_mode) {
dump($display_mode);
})->defaults('display_mode', 'large');
You can use this to pass arbitrary data to the 'action'.
Another use-case for this is if you had something like a PageController to display a single page but don't want the routes to be dynamic and instead explicitly define the routes you will have:
Route::get('about-us', [PageController::class, 'show'])
->defaults('page', 'about-us');
Route::get('history', [PageController::class, 'show'])
->defaults('page', 'our-history');
The Route class is Macroable so you could even create a macro to define these defaults on the route:
Route::get('about-us', [PageController::class, 'show'])
->page('about-us');
The Router itself is also Macroable so you could define a macro to define all of this into a single method call:
Route::page('about-us', 'about-us');
I am new in Laravel pardon me if question is silly. I have seen a doc where they used
For get request
Route::get("tags/{id}","TagsController#show");
For put request
Route::put("tags/{tag}","TagsController#update");
What is the difference and benefit between this ? I understood 1st one, confusion on put route.
There’s no real difference as it’s just a parameter name, but you’d need some way to differential parameters if you had more than one in a route, i.e. a nested resource controller:
Route::get('articles/{article}/comments/{comment}', 'ArticleCommentController#show');
Obviously you couldn’t use just {id} for both the article and comment parameters. For this reason, it’s best to use the “slug” version of a model for a parameter name, even if there’s just one in your route:
Route::get('articles/{article}', 'ArticleController#show');
You can also use route model binding. If you add a type-hint to your controller action for the parameter name, Laravel will attempt to look up an instance of the given class with the primary key in the URL.
Given the route in the second code example, if you had a controller that looked like this…
class ArticleController extends Controller
{
public function show(Article $article)
{
//
}
}
…and you requested /articles/123, then Laravel would attempt to look for an Article instance with the primary key of 123.
Route model binding is great as it removes a lot of find / findOrFail method calls in your controller. In most instances, you can reduce your controller actions to be one-liners:
class ArticleController extends Controller
{
public function show(Article $article)
{
return view('article.show', compact('article'));
}
}
Generally there's no practical difference unless you define a custom binding for a route parameter. Typically these bindings are defined in RouteServiceProvider as shown in the example in the docs
public function boot()
{
parent::boot();
Route::model('tag', App\Tag::class);
}
When you bind tag this way then your controller action can use the variable via model resultion:
public function update(Tag $tag) {
// $tag is resolved based on the identifier passed in the url
}
Usually models are automatically bound so doing it manually doesn't really need to be done however you can customise resolution logic if you do it manually
Normal way
Route::get("tags/{id}","TagsController#show");
function($id)
{
$tag = Tag::find($id);
dd($tag); // tag
}
With route model bindings
Route::put("tags/{tag}","TagsController#update");
function(Tag $tag) // Tag model binding
{
dd($tag); // tags
}
ref link https://laravel.com/docs/5.8/routing#implicit-binding
It's just a convention. You can call it all you want. Usually, and {id} refers to the id in your table. A tag, or similarly, a slug, is a string value. A tag could be 'entertainment' for video categories, while 'my-trip-to-spain' is a slug for the description of a video.
You have to chose the words what you are comfortable with. The value will be used to find in your database what record is needed to show the correct request in the view. Likewise you can use video/view/{id}/{slug} or any combination thereof.
Just make sure your URLs don't get too long. Because search engines won't show your website nicely in search results if you do. Find the balance between the unambiguous (for your database) and logic (for your visitors).
Check this out: Route model bindings
Use id, Laravel will get the id from route, and it will be the tag's id, it is integer.
function show($id) {
$tag = Tag::find($id);
}
Use tag, Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name.
In URL, your tag parameter is integer, however in your controller action $tag will be a model object:
function action(Tag $tag) {
$tag->name;
}
So you don't need to get the $tag by eloquent in your controller action. You just need to specify it is From model Tag $tag
It will do it automatically.
I have made a custom Request for validation and i don't know how to get the Model id on update.
I'm using route model binding and form model binding but this models id is not shown when i hit this Request for validation and i make
dd($this);
all fields are shown except the model id.
use route() method on request to retrive the route parameter
dd($this->route('param_name'));
if your route is like /users/{user_id} then $this->route('user_id'); will give you the parameter user_id value in request if you have bind custom parameter name in route model binding use that parametername in route() method
for ex. Route::model('user', App\User::class); then use $this->route('user'); to retrive the user model directly.
PS. $this means you should be in your Request class where you define rules() and messages() method.
For example your route is /insurance_contract_items/insurance_contract_item/
You can use $this->insurance_contract_item to get your model instance.
As you read on previous answer you can use also $this->route('insurance_contract_item').
I am attempting to create a route in Laravel for a dynamic URL to load a particular controller action. I am able to get it to route to a controller using the following code:
Route::get('/something.html', array('uses' => 'MyController#getView'));
What I am having trouble figuring out is how I can pass a variable from this route to the controller. In this case I would like to pass along an id value to the controller action.
Is this possible in Laravel? Is there another way to do this?
You are not giving us enough information, so you need to ask yourself two basic questions: where this information coming from? Can you have access to this information inside your controller without passing it via the routes.php file?
If you are about to produce this information somehow in your ´routes.php´ file:
$information = WhateverService::getInformation();
You cannot pass it here to your controller, because your controller is not really being fired in this file, this is just a list of available routes, wich may or may not be hit at some point. When a route is hit, Laravel will fire the route via another internal service.
But you probably will be able to use the very same line of code in your controller:
class MyController extends BaseController {
function getView()
{
$information = WhateverService::getInformation();
return View::make('myview')->with(compact('information'));
}
}
In MVC, Controllers are meant to receive HTTP requests and produce information via Models (or services or repositores) to pass to your Views, which can produce new web pages.
If this information is something you have in your page and you want to sneak it to your something.html route, use a POST method instead of GET:
Route::post('/something.html', array('uses' => 'MyController#getView'));
And inside your controller receive that information via:
class MyController extends BaseController {
function getView()
{
$information = Input::get('information');
return View::make('myview')->with(compact('information'));
}
}
I read the docs on the Laravel website, Stack Overflow, and Google but still don't understand the difference between Route::resource and Route::controller.
One of the answers said Route::resource was for crud. However, with Route::controller we can accomplish the same thing as with Route::resource and we can specify only the needed actions.
They appear to be like siblings:
Route::controller('post','PostController');
Route::resource('post','PostController');
How we can choose what to use? What is good practice?
RESTful Resource controller
A RESTful resource controller sets up some default routes for you and even names them.
Route::resource('users', 'UsersController');
Gives you these named routes:
Verb Path Action Route Name
GET /users index users.index
GET /users/create create users.create
POST /users store users.store
GET /users/{user} show users.show
GET /users/{user}/edit edit users.edit
PUT|PATCH /users/{user} update users.update
DELETE /users/{user} destroy users.destroy
And you would set up your controller something like this (actions = methods)
class UsersController extends BaseController {
public function index() {}
public function show($id) {}
public function store() {}
}
You can also choose what actions are included or excluded like this:
Route::resource('users', 'UsersController', [
'only' => ['index', 'show']
]);
Route::resource('monkeys', 'MonkeysController', [
'except' => ['edit', 'create']
]);
API Resource controller
Laravel 5.5 added another method for dealing with routes for resource controllers. API Resource Controller acts exactly like shown above, but does not register create and edit routes. It is meant to be used for ease of mapping routes used in RESTful APIs - where you typically do not have any kind of data located in create nor edit methods.
Route::apiResource('users', 'UsersController');
RESTful Resource Controller documentation
Implicit controller
An Implicit controller is more flexible. You get routed to your controller methods based on the HTTP request type and name. However, you don't have route names defined for you and it will catch all subfolders for the same route.
Route::controller('users', 'UserController');
Would lead you to set up the controller with a sort of RESTful naming scheme:
class UserController extends BaseController {
public function getIndex()
{
// GET request to index
}
public function getShow($id)
{
// get request to 'users/show/{id}'
}
public function postStore()
{
// POST request to 'users/store'
}
}
Implicit Controller documentation
It is good practice to use what you need, as per your preference. I personally don't like the Implicit controllers, because they can be messy, don't provide names and can be confusing when using php artisan routes. I typically use RESTful Resource controllers in combination with explicit routes.
For route controller method we have to define only one route. In get or post method we have to define the route separately.
And the resources method is used to creates multiple routes to handle a variety of Restful actions.
Here the Laravel documentation about this.
i'm using Laravel 8 in my project
and in my route file web.php
i add this route
Route::controller(SitesController::class)->group(function() {
Route::get('index', 'index')->name('index');
}
in the Route::controller group we pass controller name we will use
inside the group we define the route we'll use as below syntax
Route::method-used('prefix in the URL', 'function used in the specified controller ')->name(); if the name not used in your code just delete it