laravel icon indicating copy to clipboard operation
laravel copied to clipboard

No database selected when backup dynamic database

Open martiendt opened this issue 7 years ago • 6 comments

Hello, i tried to backup my database dynamically but i got error no database selected, this is my code, i run this via console command

foreach($clients as $client) {
    Config::set('database.connections.tenant', array(
        'driver'    => 'mysql',
        'host'      => 'localhost',
        'database'  => $client->db_name,
        'username'  => env('DB_USERNAME'),
        'password'  => env('DB_PASSWORD'),
        'charset'   => 'utf8',
        'collation' => 'utf8_general_ci',
        'prefix'    => '',
    ));

    Artisan::call('db:backup', [
        '--database' => 'tenant',
        '--destination' => 'local',
        '--destinationPath' => 'backup/database/' . $client->db_name,
        '--compression' => 'gzip'
    ]);
}

Error message

[BackupManager\ShellProcessing\ShellProcessFailed]                                    
  mysqldump: [Warning] Using a password on the command line interface can be insecure.  
  mysqldump: Got error: 1046: No database selected when selecting the database     

NOTE :

  • i also check that my database $client->db_name is exists
  • i successfully backup my database if i use mysqldump
  • if i put database name in config file it's work, but i need to run my code like my example above
  • i think the problem is when i call Artisan::call('db_backup') it's not see my setup above

i'm using Backup Manager v1.1.2 and Laravel 5.1

martiendt avatar Jul 12 '17 02:07 martiendt

@martiendt firstly which multi-tenancy package are you using ?

I see that you are setting the dynamic connections config which is correct , But u cannot use artisan cli while running the backup since artisan runs a different instance (i think as per my understanding). What I suggest is try to run the backup using Manager instance.

if you are running this in any controller inject the Manager into the __construct & Don't forget to type hint the Manager and Destination Facades.

use BackupManager\Manager;
use BackupManager\Filesystems\Destination;

Class Controller {
var $manager;
public function __construct(Manager $manager){
   $this->manager = $manager;
}

public function backup() {

foreach($clients as $client) {
    Config::set('database.connections.tenant', array(
        'driver'    => 'mysql',
        'host'      => 'localhost',
        'database'  => $client->db_name,
        'username'  => env('DB_USERNAME'),
        'password'  => env('DB_PASSWORD'),
        'charset'   => 'utf8',
        'collation' => 'utf8_general_ci',
        'prefix'    => '',
    ));

   $this->manager->makeBackup()->run('tenant', [new Destination('local', ''backup/database/' . $client->db_name,')], 'gzip');
 }
}
}

This is what i would have done.

gopal-g avatar Aug 03 '17 11:08 gopal-g

Yea, I wouldn't in general call an artisan command using Artisan::call() I'm not saying it's a bad idea. But, I prefer to design in such a way that either my web or command-line interfaces can interact with a SEPARATE instance that then does the work.

If you inject the manager you should have no problems.

ShawnMcCool avatar Aug 03 '17 14:08 ShawnMcCool

Same issue. Used the code above (tweaked for my multi-tenancy code) but still not working. Can't set the database during runtime.

tflowers3 avatar Apr 05 '18 03:04 tflowers3

Is there any solution to this issue? I am having the same problem with my multi-tenancy app.

clevonnoel avatar May 23 '18 10:05 clevonnoel

I'm open to solutions. Got anything in mind?

The stand-alone "driver" has details necessary for using it in any circumstance. The library is infinitely extendable so new procedures and tasks can be created as well.

Let me know if you have thoughts.

ShawnMcCool avatar May 23 '18 10:05 ShawnMcCool

This may not be the best solution, but I got this to work.

I've created an environment variable in the database config to specify the database name.

 ...
   'tenant' => [
            'driver' => 'mysql',
            ....
            'database' => env('DB_TENANT_DATABASE'),
            ....
    ],

Then in the place where I switch the database, I check if the app is running in console and write the name of the database to the .env file

 $databaseName = 'tenant_2'; // change this to you dynamic config

 if (App::runningInConsole())
 {
       $this->writeEnvironmentFileWith($databaseName);
 }

Here is the function to write to the .env file

protected function writeEnvironmentFileWith($key)
{
        file_put_contents(app()->environmentFilePath(), preg_replace(
            "/^DB_TENANT_DATABASE=(.+)/m",
            'DB_TENANT_DATABASE='.$key,
            file_get_contents(app()->environmentFilePath())
        ));
 }

This hasn't been fully tested or the best solution but works.

clevonnoel avatar May 23 '18 12:05 clevonnoel