Change connection on saving-event - laravel

I'm trying to change the connection on the saving event. Here is what I have done so far:
I make and event on the saving method:
protected static function boot()
{
parent::boot();
static::saving(function($model)
{
$model->connection = 'test';
var_dump($model);
return $model;
});
}
And then I make a save on User.
$user = new User();
$user->save();
When that is done, it still uses the default connection instead of the test-connection I have set.
I have both a default and a test connection configured in app/config/database.php which you can see below: (OBS: The change is the prefix)
// ...
'connections' => array(
'default' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database',
'username' => 'username',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'test' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database',
'username' => 'username',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => 'test_',
),
),
// ...
The var_dump turns out with the following, where you can see that the $model->connection have been changed.
object(User)[159]
...
protected 'connection' => string 'default' (length=7)
...
But for some reasons it stills goes into the table users instead of test_users.
Does anyone have any idea how to make this work?

I figured out a way to do this by overriding Eloquent's save-method.
public function save(array $options = array())
{
// set draft connection
Config::set('database.default', 'test');
// do the actual save
parent::save($options);
// change back to original connection
Config::set('database.default', 'default');
}

Related

Change database connection when using Laravel Auth

In a multi-tenant Laravel app, each tenant has its own database connection. So after the user has selected his database, I want to authenticate the user using Auth::loginUsingId. Still, no matter what I do, I cannot change the Users Model's connection to another default.
If I set the connection in the model, it does connect to the specific database, but I want this to be done dynamically.
Is there a way to specify the connection dynamically that Laravel's auth should use for the authentication?
You could define another connection in your config/database.php file like this:
return array(
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database1',
'username' => 'user1',
'password' => 'pass1'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'second_db_connection' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database2',
'username' => 'user2',
'password' => 'pass2'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
)
And change the User model to be like this:
class User extends Model {
protected $connection = 'second_db_connection';
}
Before authenticating the user, change the database connection temporarily for the current request only using Conifg::set
$db = "database_name";
Config::set("database.connections.mysql.database", $db);

I am trying to access database name in model relationshipt by config using laravel 8

Hi i am trying to access database name by using config but unfortunately it's not working please help me how can i resolve that thanks.
Property model
public function editedBy()
{
return $this->belongsToMany('App\User',config('database.connections.web.database'), 'property_id', 'user_id')->withTimestamps();
}
app/config/database/
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
],
'web' => [
'driver' => 'mysql',
'host' => env('DB_WEB_HOST'),
'port' => env('DB_WEB_PORT'),
'database' => env('DB_WEB_DATABASE'),
'username' => env('DB_WEB_USERNAME'),
'password' => env('DB_WEB_PASSWORD'),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],
],
You can try using to database name using env('DB_DATABASE'). Its displaying that you have change the default variables so, it may be like this in your case.
public function editedBy()
{
return $this->belongsToMany('App\User',env('DB_WEB_DATABASE'), 'property_id', 'user_id')->withTimestamps();
}
or if you really want to use config this is the example.
public function getDatabaseName()
{
$databaseName = Config::get('database.connections.'.Config::get('database.default'));
dd($databaseName['database']);
}

Override table prefix for a model

Hello I've in config/database.php a prefix (mysql) like this:
'prefix' => 'myprefix_',
But I need, only for one model, to use a different prefix like:
protected $table = 'otherprefix_mytable';
In this way laravel looking for "myprefix_otherprefix_mytable".
Any help?
In your app/config/database.php make 2 different connections like
'connections' => array(
# first prefix
'mysql1' => array(
'driver' => 'mysql',
'host' => 'host1',
'database' => 'database1',
'username' => 'user1',
'password' => 'pass1'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => 'prefix1',
),
# second prefix
'mysql2' => array(
'driver' => 'mysql',
'host' => 'host1',
'database' => 'database1',
'username' => 'user1',
'password' => 'pass1'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => 'prefix2',
),
),
And then later in model you can use different connection
class SomeModel extends Eloquent {
protected $connection = 'mysql2';
}
For more help check this
Default table prefix can be overriding in laravel model as following example:
use Illuminate\Support\Facades\Config;
public function __construct(array $attributes = array()) {
$collection = Config::get('database');
$collection['connections']['mysql']['prefix'] = 'consultancy_';
Config::set('database',$collection);
parent::__construct($attributes);
}

Orchestral/tenanti multi database

I build an application for many tenants and each tenant has it's own database. The name of the database is the same as the tenants id.(the id exists out of five numbers). After authentication the user should be connected with his own database and redirected to his dashboard.
I tried to connect the user with his database with the following code, which I placed in Authenticate.php
if (!Auth::guest() && Auth::user()->tenant) {
$user = Auth::id();
Tenanti::driver('user')->asDefaultDatabase($user, 'users_{id}');
Config::set('database.connections.mysql.database', 'user_'.$user);
}
The if statement checks in the main database if the logged in user is a tenant(boolean).
The config/database.php contains the following code:
'tenants' => [
'user_1' => [
'driver' => 'mysql',
'host' => 'localhost', // for user with id=1
'database' => '86097', // for user with id=1
'username' => 'root', // for user with id=1
'password' => 'root', // for user with id=1
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
],
AppServiceProvider:
<?php namespace App\Providers;
use Orchestra\Support\Facades\Tenanti;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Tenanti::setupMultiDatabase('tenants', function (User $entity, array $template) {
$template['database'] = "user_{$entity->getKey()}";
return $template;
});
}
}
?>
I don't get an error, but the connection hasn't changed. The user database is empty and therefore I shouldn't see any data when I log in with user_id=1 . Thanks in advance for helping.
The configuration should be:
'tenants' => [
'driver' => 'mysql',
'host' => 'localhost', // for user with id=1
'database' => '86097', // for user with id=1
'username' => 'root', // for user with id=1
'password' => 'root', // for user with id=1
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
Other than that please replace Tenanti::setupMultiDatabase() with Tenanti::connection() (we have deprecated the old method).
And change the following:
Tenanti::driver('user')->asDefaultConnection(Auth::user(), 'tenants_{id}');
Obviously if you want to use users_{id} you would then need to replace all tenants to users.

Dynamically edit config/database.php file in Laravel

First time when user runs my application i want to set database details as entered by the user in my application.
Please let me know how i can edit config/database.php file in Laravel and update database credentials as provided by user.
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => '*********',
'database' => '********',
'username' => '********',
'password' => '*******',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
),
The simplest solution is probably to use placeholders in the initial config file:
'mysql' => array(
'driver' => 'mysql',
'host' => '%host%',
'database' => '%database%',
'username' => '%username%',
'password' => '%password%',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
And then just replace them with the actual values:
$path = app_path('config/database.php');
$contents = File::get($path);
$contents .= str_replace('%host%', $host, $contents);
// and so on
File::put($path, $contents);
This way you don't have to actually parse the file.
You might also want to use some kind of default database.php.dist and create the actual database.php when filling in the values. This way you could always repeat the set up process by using the original .dist file.
If you want to set the database connection dynamically for just one request you can also use the following option.
Config::set('database.connections.local.host', '<New Host IP>');
Config::set('database.connections.local.database', '<New DB>');
Config::set('database.connections.local.username', '<New Username>');
Config::set('database.connections.local.password', '<New Password>');
Your DB config can looks like this in that case, or just provide default connection information and override it via the above commands.
'connections' => array(
'local' => array(
'driver' => 'mysql',
'host' => '',
'database' => '',
'username' => '',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_cli',
'prefix' => '',
),
),
There's no built-in functionality to do what you want here. However, I have done a similar thing myself and I just load the file in, do a string replacement operation and then write it back out. This, by the way, is the way that laravel's own 'set application key' command works, so at least we aren't missing any undocumented functionality!
Something like this, in your command's fire method:
$dialog = $this->getHelperSet()->get('dialog');
$host = $dialog->ask($this->output, '<question>Hostname?</question> ');
$db = $dialog->ask($this->output, '<question>Database?</question> ');
$user = $dialog->ask($this->output, '<question>Username?</question> ');
$pass = $dialog->ask($this->output, '<question>Password?</question> ');
if ($file = file_get_contents(app_path('config/database.php')) {
$file = str_replace("'host' => '*********'", "'host' => '".$host."'", $file);
$file = str_replace("'database' => '********'", "'database' => '".$db."'", $file);
$file = str_replace("'username' => '********'", "'username' => '".$user."'", $file);
$file = str_replace("'password' => '*******'", "'password' => '".$pass."'", $file);
file_put_contents(app_path('config.database.php'));
}

Resources