Multiple Database Connections in Laravel 10

hawari

Hawari Muflih Munte

Posted on November 26, 2024

Multiple Database Connections in Laravel 10

Need to Connect to Multiple Databases in Laravel 10?
You're in the right place!

I'm assuming you already familiar with Laravel 10 basics. If not, no worries, this guide will still be easy to follow.

To start, let's break down the problem and the solution. First up, here's a flowchart to help you visualize the problem:

Image description

Laravel comes with a default .env file, pre-filled with default database credentials like these:

APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

...

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=A1
DB_USERNAME=CoolUsernameHere
DB_PASSWORD=HotHashedPass

...
Enter fullscreen mode Exit fullscreen mode

By default, Laravel provides the configuration in the .env.example file. You can remove the .example suffix to create your .env file, where you can then customize the settings to match your project's environment.

As shown above, this default configuration is set up for a single database connection.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=A1
DB_USERNAME=CoolUsernameHere
DB_PASSWORD=HotHashedPass
Enter fullscreen mode Exit fullscreen mode

This default configuration connects your project to a single database. If you need to add more connections, then you'll have to write more configurations in your .env file. For example:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=A1
DB_USERNAME=CoolUsernameHere
DB_PASSWORD=HotHashedPass

DB_SECOND_CONNECTION=second_connection
DB_SECOND_HOST=127.0.0.1
DB_SECOND_PORT=5528
DB_SECOND_DATABASE=B2
DB_SECOND_USERNAME=HotUsernameHere
DB_SECOND_PASSWORD=CoolHashedPass
Enter fullscreen mode Exit fullscreen mode

Next, define your new connection in config/database.php file:

'second_connection' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL'),
    'host' => env('DB_SECOND_HOST', '127.0.0.1'),
    'port' => env('DB_SECOND_PORT', '8809'),
    'database' => env('DB_SECOND_DATABASE', 'B2_fallback'),
    'username' => env('DB_SECOND_USERNAME', 'ShadowAdmin'),
    'password' => env('DB_SECOND_PASSWORD', 'AdminShadow'),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],
],
Enter fullscreen mode Exit fullscreen mode

Once you've added the code above, you can continue by registering it in your app/Http/Kernel.php.

/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array<string, class-string|string>
 */
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    // Add this line below
    'checkUserLevel' => \App\Http\Middleware\CheckUserLevel::class,
];
Enter fullscreen mode Exit fullscreen mode

Create a new middleware called CheckUserLevel.

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class CheckUserLevel
{
    public function handle(Request $request, Closure $next, $level)
    {
        Log::info('CheckUserLevel middleware:', [
            'required_level' => $level,
            'user_level' => session('level')
        ]);

        if (session('level') < $level) {
            // If custom credential for user not met, which in this case
            // we use level as custom credentials for user
            return redirect('/')->with('error', 'You have no access to this resources');
        }

        return $next($request);
    }
}
Enter fullscreen mode Exit fullscreen mode

In LoginController.php, you can write custom login logic below.

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Override method attemptLogin to include custom login logic.
     */
    protected function attemptLogin(Request $request)
    {
        // Step 1: check login with first default database (auth Laravel)
        if (Auth::attempt($this->credentials($request), $request->filled('remember'))) {
            return true;
        }

        // Step 2: If step 1 fails, then check second database
        $credentials = $this->credentials($request);
        $user = DB::connection('second_connection')->table('users')
            ->where('email', $credentials['email'])
            ->first();

        if ($user && Hash::check($credentials['password'], $user->password)) {
            // Create custom session if user successfully logged in
            // with second database credentials
            $this->createCustomSession($user);

            // Log user in using taken ID from second database.
            Auth::loginUsingId($user->id, $request->filled('remember'));

            return true;
        }

        return false;
    }

    /**
     * Handle custom session creation for second database users.
     */
    protected function createCustomSession($user)
    {
        // Save user ID and level to session
        session(['custom_session' => $user->id]);

        if (isset($user->level)) {
            session(['level' => $user->level]);
        }
    }

    /**
     * Override method sendFailedLoginResponse to handle error messages.
     */
    protected function sendFailedLoginResponse(Request $request)
    {
        return redirect()->back()->withErrors([
            $this->username() => __('auth.failed'),
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

And that's it -- you're all set! 🎉
Now you can use multiple database connections in your project as needed. If you have any questions, don't hesitate to ask! 😊

💖 💪 🙅 🚩
hawari
Hawari Muflih Munte

Posted on November 26, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related