Search code examples
phplaravellaravel-routing

How to pass a model instance to all controllers and views based on a route parameter


I am working on a Laravel control panel project where we should be able to toggle from one site to another and get the detail of the site based on the ID passed in the route.

In itself this is quiet easy to do but as I will have several controllers using this technique it means for each controller and each controller instance I will have collect the site instance and it does not look very user friendly due to the many repetitions.

Here is what I have: Route:

Route::get(
    'cp/site/{website}/modules/feeds',
    'App\Http\Controllers\Modules_sites\Feeds\FeedController@index'
)->name('module_site.feeds.index'); 

Model:

class Website extends Model
{
    use HasFactory;
    protected $primaryKey ='site_id';
}

The database is simple with an id (site_id) and name

Controller:

public function index(Website $website)
{
    dd($website -> name);  
}

The above is working fine but I am going to end with dozens of methods across multiple controllers doing the same thing, and what if changes are required.

I have looked at the ID of using the AppServiceProvider to create the Website instance and then pass it to the controllers and views but I can't do this as the route is not defined at this stage and I only seem to be able to pass this to the view.

Essentially, I am looking to create something similar to the auth()->user() method that is available from controllers and routes without the needs to pass it to each controller.

Is this possible?


Solution

  • Perhaps you could use middleware to set this value? Something like this to put it in the session globally:

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    
    class CheckWebsite
    {
        public function handle(Request $request, Closure $next): mixed
        {
            $request->session()->put("website", $request->route("website"));
            return $next($request);
        }
    }
    

    Or this on a per-controller basis:

    <?php
    
    namespace App\Http\Controllers\Modules_sites\Feeds;
    
    use App\Http\Controllers\Controller;
    use Closure;
    use Illuminate\Http\Request;
    
    class FeedController extends Controller
    {
        public function __construct()
        {
            $this->middleware(function (Request $request, Closure $next) {
                $this->website = $request->route("website");
                return $next($request);
            });
        }
    
        public function index()
        {
            dd($this->website->name);
        }
    }
    

    Also worth mentioning that routes are not defined like that in Laravel 8 any longer. It should look like this:

    Route::get(
        'cp/site/{website}/modules/feeds',
        [FeedController::class, 'index']
    )->name('module_site.feeds.index');
    

    With an appropriate import for the controller class.