Search code examples
databaselaraveleloquentconnectioncrud

Laravel resource controller and model the same for multiple databases


Is there any way I can use the same controller and model for multiple databases?

For example I have a Product model, and a ProductController (CRUD resource controller with index,show,store,update,destroy). The databases,models and controllers are identical.

The only way I found to change the connection is in the model protected $connection = 'connection_name'; But then I would need to duplicate the ProductController for each model.

I was thinking to make ProductController as BaseProductController and extend it for every database but I cannot figure out how to set the connection.


Solution

  • You could use Dependency Injection on your Product model with a resolving hook

    In a service provider:

    use App\Product;
    
    $this->app->resolving(Product::class, function ($product, $app) {
        $request = $app['request'];
        if ($request->isConnection1()) {
            $product->setConnection('connection1');
        }
        elseif ($request->isConnection2()) {
            $product->setConnection('connection2');
        }
    });
    

    My example obviously does not work because I don't know your context, but it shows you the way of thinking.

    Another way would be to add a middleware to your routes around ProductController which sets the DB default connection (used by your models when it's not specified)

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Database\ConnectionResolverInterface as DatabaseManager;
    
    class SwitchConnection
    {
        protected $dbManager;
    
        public function __construct(DatabaseManager $dbManager)
        {
            $this->dbManager = $dbManager;
        }
    
        public function handle($request, Closure $next, string $connection)
        {
            $this->dbManager->setDefaultConnection($connection);
            return $next($request);
        }
    }
    

    By the way, if you alias this middleware as switch.connection and add switch.connection:connection1 to a route's middlewares, it will automatically switch, and therefore you can use the same controller.