Laravel 5 - Getting URL Parameters in Middleware on Resources - php

Let's say that I have a resource defined in my Routes as:
Route::resource('account', 'AccountController', ['only'=> ['index','update']]);
And then I have the Middleware attached to the Controller from within as:
public function __construct() {
$this->middleware('BeforeAccount', ['only' => ['update']]);
}
Let's say I want to access the uri parameter that happens after account (i.e. example.com/account/2) within my Middleware - how do I go about grabbing that variable?

You can use the following code to achieve that:
public function handle($request, Closure $next)
{
$account_id = $request->route()->parameter('accounts');
//...
}
Since the handle method receives the Request object as the first argument. The middleware gets executed only after the route has been matched so the Request object contains the current route and no need to match the route again using Route::getRoutes()->match($request).

Doing this way you don't have to supply the \Request object:
Route::current()->parameter('parameter');

Related

Laravel - Routes: Controller nested controller

My routes:
Route::apiResource('courses', 'CourseController');
Route::apiResource('courses.classrooms', 'ClassroomController');
List: php artisan route:list
api/v1/courses/{course}
api/v1/courses/{course}/classrooms/{classroom}
My question is: all my functions in classroom controller needs the course, something like that
public function index($course_id)
{
$classroom = Classroom::where('course_id', $course_id)->get();
return $classroom;
}
public function store($course_id, Request $request)
{
// ...
$classroom->course_id = $course_id;
// ...
}
public function show($course_id, $id)
{
$classroom = Classroom::where('course_id', $course_id)->find($id);
return $classroom;
}
// ...
Have some Policy/Helper in Laravel to accomplish this automatically?
I believe it's not necessary to add the property $course_id in all functions manually, what can I do?
You can use a group to enclose all your routes. Something like:
Route::group(['prefix' => '{course}'], function () {
// you can place your routes here
});
So all the routes that exist in that group will already have the course value in the url path and you don't have to "rewrite it" for every route.
If that field is set by you for example an env variable then inside your RouteServiceProvider you can put the prefix you want in the mapApiRoutes function.
protected function mapApiRoutes()
{
Route::prefix('/api/v1/courses/'.config('app.myVariable'))
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
That way ALL your api endpoints will start with that prefix and you can have it in all the endpoints.
If the routes are registered correctly like you posted, your methods in the ClassroomsController should receive an additional parameter that's the course id fragment from the url.
For example if you request /api/v1/courses/1/classrooms route, the controller will receive the correct {course} parameter set to 1 as the first parameter.
You could then implement the index method of the ClassroomsController to use implicit model binding and get the Course instance with the given url id for the course.
To do so you have to type-hint the Course model for the first function's parameter and name the variable as the url fragment you want to use to retrive your model.
In your code example, you should do:
public function index(Course $course)
{
return $course->classrooms;
}
Note: I assume you have a relationship between Course and Classroom models to retrive the classrooms from the course model instance
You can read more about that on the official documentation here

How can I redirect a Laravel route without a parameter to a controller method with a default parameter?

Assume the following routes in a Laravel 5.5 API:
// custom routes for THIS user (the user making the request)
Route::get('/user', 'UserController#show');
Route::get('/user/edit', 'UserController#edit');
// register CRUDdy resource routes for users
Route::resource('users', 'UserController');
Let's use edit as the example:
public function edit(User $user)
{
...
}
As you can see, the edit route contains a type-hinted $user parameter. This works just fine for the users/13/edit route, as expected. However, I'd to configure the route /user/edit to pass along the $request->user() user object to the function. I don't want to check for the user object in the actual edit method as that could interfere with other validation (for instance, I don't want to default to the current user if someone passes a non-existent user ID, I want to return an error in that case).
In short: how can I register a route to first create a parameter, then pass it to the given controller method? My first thought was to use a closure:
Route::get('/user/edit', function(Request $request){
$user = $request->user();
});
But once inside the closure, I'm not certain how to then carry the request forward to the appropriate controller method.
Instead of a closure, you could make a new controller method that calls edit with the current user.
Let's say your route is this:
Route::get('/user/edit', 'UserController#editSelf');
Then in your controller:
public function editSelf(Request $request)
{
$this->edit($request->user());
}

Laravel getting {id} get parameter in middleware

The problem: I can't get the {id} parameter to be 'found' in the Middleware. My middleware needs to get the {id} param, in order to verify if the Auth::user() is the owner of the specified group.
Request example: groups/admin/open/4 --> group 4 will be opened.
What I have:
Route:
Route::post('groups/admin/open/{id}', 'GroupController#opengroup')->middleware(['auth','owner']);
My middleware ('owner') is still empty.
What I tried:
1. Adding an $id parameter in the function (like you do in Controllers), like so:
public function handle($request, /* Added -> */ $id, Closure $next)
{
dd(Input::get('id'));
return $next($request);
}
This returns an error:
Argument 3 passed to App\Http\Middleware\RedirectIfNotOwner::handle() must be an instance of Closure, none given
Different placement of the $id, at the end, results in the error:
Missing argument 3 for App\Http\Middleware\RedirectIfNotOwner::handle()
What I have tried 2: I have thought about is to change my url like this
Request example: groups/admin/open?groupparam=4
And use
Input::get('groupparam');
But this forces me to make changes to my controllers etc. Still this is an option.
Reason for asking: moreover I believe Laravel has the capability to retrieve {id} params in Middleware too, beautifully. I just don't know how.
Can you help me?
Thanks,
Eltyer
You can easily get route parameters in your route middleware with:
$id = $request->route('id');

Middleware not working as expected - Laravel

This is driving me crazy as I think I'm doing the right thing but its not working correctly.
I have a route with a middleware attached to it like below;
Route::get('post/{id}/{name}', 'BlogController#post')->name('blog-post')->middleware('blogGuard');
As you can see I've defined 2 route params
In my controller I have below;
public function post () {
return view('pages.blog.post');
}
With the middleware defined like this;
public function handle($request, Closure $next)
{
if (is_null($request->input('id')) ||
is_null($request->input('name'))) {
return redirect()->route('blog-home');
}
return $next($request);
}
Now if I click on a link like so; http://blog.example.co.uk/post/153/firstpost the middleware should not fire correct?
This is not the case. The middleware executes and I'm redirected. But if I remove the middleware then I'm able to access the page.
Any help appreciated.
If you are trying to access route parameters you probably want to explicitly get them from the route.
$request->route('id'); // pulls the $route->parameter('id');
$request->route('name'); // pulls the $route->parameter('name');
$request->id will check the request inputs before falling back to returning a route parameter.
$request->input('id') will only check the input sources for the request and not the route params.
If you use $request->id expecting to get the route param 'id', one could break your logic by passing id=anythinghere to the querystring or adding a 'id' var to a post request.
Try this
if (!$request->id ||
!$request->name)

Lumen: how can I get url parameters from middleware

This is my routes.php:
$app->get('/users/{id}/', ['middleware' => 'example', function () {
return "users";
}]);
This is the handle function in the middleware:
public function handle($request, Closure $next)
{
// I would like to get the value of the url parameter {id} here
return $next($request);
}
Is there a way I can get the parameter id from my middleware?
* Edit *
I'm using Lumen 5.1.0.
There are some conventional ways in Laravel doesn't work on Lumen. And get parameter form URI in middleware is one of them. In Laravel, I just need to call $request->id, it will work like magic. But here in order to get parameter in Lumen, I need to do something like this:
$request->route()[2]['id']
If the $request value passed in is an instance of Illuminate\Http\Request, which I think it might be, that class has a method called input(), which lets you do exactly that:
You should try this:
$id = $request->input('id');
i think the latest lumen 5.6 official tutorial about middleware is no longer applicable, and out of date.

Categories