pmusa's avatar
Level 2

grab REQUEST_URI parameters

Hello!

My route:

Route::get('/posts/archives/{year}/{month}', 'PostsController@index')
        ->where(['year' => '[0-9]{4}', 'month' => '[A-Za-z]+'])
        ->name('posts.archives');

My Controller:

    public function index()
    {
        //dd(request());
        $posts = Post::latest()
            ->filter(request(['year','month']))
            ->get();
        
        return view('posts.index', compact('posts'));
    }

My View:

<a href="{{ route('posts.archives', ['year' => $archive['year'], 'month' => $archive['month']]) }}">

My Model:

    public function scopeFilter($query, $filters)
    {

        if (isset($filters['month'])) {
            $query->whereMonth('created_at', Carbon::parse($filters['month'])->month);
        }

        if (isset($filters['$year'])) {
            $query->whereYear('created_at', $filters['$year']);
        }

    }

Is there a way to elegantly grab "2019" and "April" when the user visits https//dev.local/posts/archives/2019/March ?

This returns "null":

request(['year','month'])

I'd like to avoid the old fashioned way where I'd parse the $_SERVER['REQUEST_URI'] and explode() it for the fragments I'm looking for... I'm sure Laravel has something for me, right?

Thanks!

0 likes
5 replies
Nakov's avatar

I am not sure if you can get them by name, but as segments you can do it like this:

request()->segment(3); // year
request()->segment(4); // month

And another way is to bind them to the method, like this:

public function index($year, $month)
{
        dd($year, $month);
        $posts = Post::latest()
            ->filter(request(['year','month']))
            ->get();
        
        return view('posts.index', compact('posts'));
}
1 like
pmusa's avatar
Level 2

Not a big fan of the segment(), since I won't benefit from the route() in my view if I ever change the sequence in my web.php file.

However it works fine this way indeed :

    public function index($year='',$month='')
    {

        $posts = Post::latest()
            ->filter(compact('year','month'))
            ->get();
        
        return view('posts.index', compact('posts'));
    }

parameters are optional because I also have this:

Route::get('/posts', 'PostsController@index')->name('posts');

which references the same controller method. Not sure how elegant that is. I'm wondering if I should seperate the methods, although they run through the same Eloquent query and return the same view ...

Nakov's avatar

@pmusa If you are re-using the same method then you can do that by making the parameters optional on the route, like this:

/posts/archives/{year?}/{month?}

This will set them as null if you don't provide them, but you cannot use just one of them, it should either be both or none which is not pretty.

A cleaner way for your scenario is to have a separate controller for your case, because in one you are getting all the posts, but the other one should get archived posts as per your route, for that I would create a ArchivedPostsController. Adam Wathan has a nice talk about this, you can watch it on YouTube called Cruddy By Design.

Make sure that if any of these answers your question you can mark it as solved. Happy coding!

Jacobs's avatar
Jacobs
Best Answer
Level 2

You can access them simply with

request()->route(‘year’);
request()->route(‘month’);

Please or to participate in this conversation.