I found myself stuck or lost in docs!
I'm using Laravel 5.4 and I'm trying to create validation in a controller which requires a request object.
My problem is my route passes parameters, I can't find in the docs an example how you include the Request $request argument and the $id parameter in a Controller method.
Here is my example:
1: SomeController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
...
public function edit($id) {
$request = Request; // <-- Do I use that instead of passing an arg?
}
2: Routes with a Paramter in -- routes/web.php
Route::match(['GET', 'POST'], '/some/edit/{id}', 'SomeController#edit');
In their example # https://laravel.com/docs/5.4/requests#accessing-the-request they have Request $request this in their controller, but what happens to Route parameters?:
public function store(Request $request) {}
Question: Do I need to edit the route or is the first parameter ignored if its a request?
A: Or would I do this in **SomeController.php?**
public function edit(Request $request, $id)
{
// I would get the $request, but what happens to $id?
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
]);
}
B: Perhaps, something like this?:
public function edit($id)
{
// Or Request::getInstance()?
$this->validate(Request, [
'title' => 'required|unique:posts|max:255',
]);
}
Any advice would help, or even an example!
Doing
public function edit(Request $request, $id)
should match the route you already have. So it's ok to do that. Request $request here is not a required parameter that you pass. Laravel will take care of it.
It works this way because everytime you send a request, well Laravel 'sends' a request for you (GET, POST). So, it always exist. But you can use use it within your controller if you dont pass it to the controller function as a parameter.
However, you can access it through the global helper function request() if you dont want to pass it as a function parameter.
$request = request();
$name = $request->name; // or
$name = request('name');
Related
i am try to make policy in Post Model, i follow the documentation but still return always false
in api.php
Route::put('post/{id}','PostController#update')->middleware('auth:api');
in post controller
public function update(Request $request, Post $post,$id){
$this->authorize('update',$post);
$request->validate(['content'=>'required']);
$post = $post->find($id);
$post->content = $request->content;
$post->save();
return response()->json($post, 200);
}
in PostPolicy
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
in AuthServiceProvider
protected $policies = [
'App\Post' => 'App\Policies\PostPolicy',
];
please ignore for model since model is working properly, if i comment $this->authorize in controller is working, but there is no authentication, user can update any thing in model
i test from postman using api using
authorization = Bearer 'api_token'
The reason you're having this issue is because the update method in the policy expects a loaded instance of the model, however, with your current setup, you're passing an unloaded/empty instance of the model.
You could get around this by using Route Model Binding. Change {id} in your route to be {post}:
Route::put('post/{post}','PostController#update')->middleware('auth:api');
Then remove the $id argument from your update() method:
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
$request->validate(['content' => 'required']);
$post->content = $request->content;
$post->save();
return response()->json($post, 200);
}
Also, notice now how you're not having to use find to load the model, this is because Laravel is loading the model for you under-the-hood.
Route model binding works by looking for a param name with the same name as the uri segment i.e. {post} on the route and $post the method argument, and since $post is type-hinted to be a model Laravel knows to use the value of {post} to load (find) the Post model.
This is my url -> http://localhost:82/?search=asd
How do I catch 'asd' in route?
I try this -> Route::get('/?search={SearchValue}', 'TryController#search');
But it didn't work.
It won't even get into the controller.
You don't have to adjust the routes. But include $request in your controller method. Then use your request object to access it.
use Illuminate\Http\Request;
public function search(Request $request) {
// to access the query parameters
$search = $request->query->get('search');
// similar but different syntax
$search = $request->query('search');
// generic method that checks all input including query
$search = $request->input('search');
}
You should just only need something like this:
Route::get('/search', 'TryController#search')->name('try.search');
Once you have the route correctly set you can call:
public function search(Request $request)
{
$request->get('search')
to get the url parameter you passed into the request.
I am very obviously a noob to Laravel and hope that someone can help me out.
The about screen is accessed through the route
Route::get('/about', array('as' => 'about', function()
{
return View::make('about')->with('title','About Screen')->with('class','about');
}));
The variables $title and $class are accessible in about.blade.php by {{ $title }} and {{ $class }}. If instead, I have a Controller in between,
Route::get('hello/create', array('as' => 'create', 'uses' =>
'HelloController#create', function()
{
return View::make('hello/create')->with('title','Create')->with('class','hello.create');
}));
How do I access $title and $class in the HelloController.php code (so that I can propagate the values to the coming View)?
P.S. I do know about the /hello/create/{name of variable} which is the answer on nearly all questions similar to this, but don't know how to use it to transmit variables NOT keyed onto the Http Request.
$title and $class are the values you are manually giving to the blade. These aren't the values that you are receiving in GET parameters in your route. So, you would do it the same way as you did in the closure.
Your route:
Route::get('hello/create', array('as' => 'create', 'uses' => 'HelloController#create'));
Controller method:
class HelloController{
public function create(){
return View::make('hello/create')->with('title','Create')->with('class','hello.create');
}
}
UPDATE:
From what I understood, you can also call controller's method inside the route's closure and pass parameters to the controller and call the view with these values inside the controller's method.
Your route file:
use App\Http\Controllers\HelloController;
Route::get('hello/create',function(){
$hello_obj = new HelloController();
return $hello_obj->create('create','hello.create');
});
Controller method:
class HelloController{
public function create($title,$class){
return View::make('hello/create')->with('title',$title)->with('class',$class);
}
}
First you need to clear your flow. You are -at the moment- manually setting the variables to be returnet to the view, so your route should look like this:
Route::get('hello/create', 'HelloController#create');
Then, your controller handles the logic:
public function create(Request $request)
{
return view('hello.create')->with('title','Create')->with('class','hello.create');
}
Now, if you need to send parameters from your frontend to your controller, you have two options:
Define route parameters.
Use query params.
Option 1
For the first option, you'll need to define your required/optional parameters in the route itselft:
Route::get('hello/create/{a_variable}', 'HelloController#create');
Then you access this parameter in any of this ways:
public function create(Request $request)
{
return view('hello.create')->with('a_variable', $request->a_variable);
}
or injecting the variable in the method:
public function create(Request $request, $a_variable)
{
return view('hello.create')->with('a_variable', $a_variable);
}
Option 2
For the use of query params, you should include this options when making the request. If your route looks like this:
Route::get('hello/create', 'HelloController#create');
You could specify query params like this:
GET www.my-domain.com/hello/create?first_parameter=value_1&second_parameter=value_2
So in your controller you access this values like this:
public function create(Request $request)
{
$value_1 = $request->get('first_parameter');
$value_2 = $request->get('second_parameter');
return view('hello.create')
->with('value_1', $value_1)
->with('value_2', $value_2);
}
You are alreading sending data to view using with().
Echo it in your view file using $variablename set in with() Example: <?php echo $title; ?>
I'm doing an existence check within a middleware, by checking a route-parameter.
If the check succeeds, I'm attaching it's model to the request to make it available throughout the rest of the request-cycle, application.
// App\Http\Middleware\CheckForExistence.php:
...
public function handle($request, Closure $next)
{
// some checks...
// success
$request->attributes->add([
'company' => $someModel
]);
}
I now have a controller which 'needs' this information in a couple of methods. So my thought was to add it to the construct of the controller and add it as a protected var in the whole controller:
// App\Http\Controllers\MyController.php
<?php
use Illuminate\Http\Request;
class MyController extends Controller
{
protected $company;
public function __construct(Request $request)
{
$this->company = $request->attributes->get('company');
}
public function index()
{
dd($this->company); // returns null
}
}
This controllers index() returns null instead of the give model.
If I change the index() method to:
public function index(Request $request)
{
return $request->attributes->get('company');
}
This returns the model; as expected.
Why is this happening? It looks like the middleware is not run when the controller is constructed.... Is there a way to circumvent it?
Or am I missing the obvious here.....
I could off course repeat myself in each method; but that is not very DRY ;)
You can't access the session or authenticated user in your controller's constructor because the middleware has not run yet, So you can do it like this :
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->company = $request->attributes->get('company');
return $next($request);
});
}
For reasons currently unclear to me, the controller object is constructed before the request changes are reflected in the request object. In short the request is not considered properly constructed when a controller is constructed. This post seems to imply that.
There's two ways to work around this (if for a second we ignore what you're trying to do).
Use request dependency injection
public function index(Request $request)
{
$compary = $request->attributes->get('company');
}
This is not really WET because you're just swapping $this->company with $request->attributes->get('company') it's just a refactor. You should be injecting the request in the controller action anyway and if you don't want to do that you can use the request() helper.
Use a callback middleware in the constructor (Maraboc's answer explains how)
Now if you want a more case specific solution though you can use case specific dependency injection:
If you need to bind a model to a specific route parameter you can use route model binding and add the following in your RouteServiceProvider (or any provider).
Route::bind("companyAsARouteVarName", function () {
// this is why more details in the question are invaluable. I don't know if this is the right way for you.
//checks
// success
return $someModel;
});
Then you will register your route as:
Route::get("/something/{companyAsARouteVarName}", "SomeController#index");
and your controller will be:
public function index(Company $companyAsARouteVarName) {
//Magic
}
Controller constructor will be initialized before middleware execution.
You can get data from Injected $request object in controller functions.
I guess I'm missing something really obvious here but how do you access URL params in Lumen? I have the following route:
$app->get('user/{id}', ['uses' => 'userController#testId']);
Then in my user controller I have:
public function testId(Request $request) {
return $request->input('id');
}
But the ID is always null what have I missed even in this very basic example?
Okay, doesn't matter, as I thought I'm the tool here.
For anyone else (and myself in the future when I land on this page after a Google with the exact same problem next year) the documentation states:
If your controller method is also expecting input from a route parameter, simply list your route arguments after your other dependencies. For example, if your route is defined like so:
$app->put('user/{id}', 'UserController#update');
public function update(Request $request, $id)
{
//
}
So you need to pass any URL params into the function, they don't appear to be accessible via Lumens $request object.
public function testId(Request $request, $id) {
return $id;
}
According to https://laravel.com/docs/master/requests you can do the following:
$app->get('user/{id}', ['uses' => 'userController#testId']);
public function testId(Request $request, $id) {
//$id is from the path
}
The reasoning is that id is part of the request path and not the request input
Try with this
public function testId(Request $request) {
return $request->id;
}