an3/multisource
Laravel package for managing multiple data sources in one app. Define and switch between connections/providers (e.g., database or external services) at runtime, keeping config and resolution centralized for cleaner, scalable multi-tenant or multi-source setups.
Installation
composer require an3/multisource
Publish the config file:
php artisan vendor:publish --provider="An3\Multisource\MultisourceServiceProvider"
Configure Sources
Edit config/multisource.php to define your login sources (e.g., email, username, phone):
'sources' => [
'email' => 'email',
'username' => 'username',
'phone' => 'phone',
],
Extend User Model
Ensure your User model implements An3\Multisource\Contracts\MultisourceUser:
use An3\Multisource\Contracts\MultisourceUser;
class User extends Authenticatable implements MultisourceUser
{
// ...
}
First Use Case: Login
Replace Auth::attempt() with the package’s method:
use An3\Multisource\Facades\Multisource;
$credentials = ['username' => 'john_doe', 'password' => 'secret'];
if (Multisource::attempt($credentials)) {
// Authenticated
}
$credentials = ['phone' => '+1234567890', 'password' => 'password123'];
if (Multisource::attempt($credentials)) {
// Works for email/username/phone if configured
}
app/Providers/AppServiceProvider:
use An3\Multisource\Multisource;
public function boot()
{
Multisource::extend('phone', function ($source, $value) {
return Validator::make(['phone' => $value], [
'phone' => 'required|digits:10|starts_with:1',
])->passes();
});
}
Auth::attempt: Override app/Providers/AuthServiceProvider:
protected function authenticate()
{
return Multisource::attempt($this->credentials);
}
$token = Multisource::attempt($credentials)
? Auth::user()->createToken('API Token')->plainTextToken
: null;
config/multisource.php:
'fallback' => ['email', 'username', 'phone'],
Missing MultisourceUser Contract
Class User does not implement MultisourceUser.User model implements An3\Multisource\Contracts\MultisourceUser.Case-Sensitive Sources
Phone but works for phone.config/multisource.php:
'sources' => [
'phone' => 'phone', // Must match DB column exactly
],
Validation Short-Circuiting
extend() is called before Multisource::attempt().Password Hashing Mismatch
Hash::check() fails silently.password column in users table uses Laravel’s bcrypt hashing.Multisource::attempt($credentials, function ($source, $value) {
\Log::debug("Failed login for $source: $value");
});
php artisan config:clear
Then verify config/multisource.php is loaded.Custom Guards
Override MultisourceGuard in app/Providers/AuthServiceProvider:
Multisource::guard(function ($app) {
return new CustomMultisourceGuard($app['auth']->createUserProvider());
});
Dynamic Source Discovery Fetch sources from a DB table:
Multisource::setSources(function () {
return Source::all()->pluck('key')->toArray();
});
Rate Limiting
Integrate with Laravel’s throttle middleware:
Route::post('/login', function () {
return Multisource::attempt(request()->only(['source', 'value', 'password']))
? response()->json(['success' => true])
: response()->json(['error' => 'Invalid credentials'], 429);
})->middleware('throttle:5,1');
How can I help you explore Laravel packages today?