Laravel 5.8.0 is used. There are several databases whose data are populated from the admin panel. The standard config (/config/database.php), of course, does not get the data, but is recorded and stored in a separate JSON-config (/storage/app/databases.json).

The question is the following: How can I connect to a third-party database not by entering data into the config manually, but using my own automatically received data for connection?

I know about the existence of setConnection() . I tried to write something like this:

 $servers = conf()->get('servers'); //Пакет garf/laravel-conf, тут у меня массив с информацией по базам foreach($servers as $server){ if(empty(Config::get("database.connection.".$server['name_database']))){ Config::set( // И через config() тоже работать не будет 'database.connection.'.$server['name_database'], [ 'driver' => 'mysql', 'host' => $server['ip_database'] ?? '127.0.0.1', 'port' => $server['port_database'] ?? 3306, 'database' => $server['name_database'], 'username' => $server['user_database'], 'password' => $server['pass_database'], 'unix_socket' => '', 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, ] ); } $punishment = new Punishment; $punishment->setConnection($server['name_database']); $list = $punishment->where('name', '=', Auth::user()->name); } 

But Laravel damn it for two wants to put something into its config programmatically, so I get the error:

InvalidArgumentException Database [server_classic] not configured.

PS Just to write the connection directly (through the same PDO) does not see the point. And about “use one base” not to write, it will not work that way, because third-party databases are used locally on game servers and for servers, and you only need to receive some information from time to time.

    1 answer 1

    1. Create a descendant class from \Illuminate\Database\DatabaseManager and override its configuration() method in it. For example, I created this class in \App\Database\DatabaseManager . The result should be something like this:

       <?php namespace App\Database; use \Illuminate\Database\DatabaseManager as BaseDatabaseManager; class DatabaseManager extends BaseDatabaseManager { protected function configuration($name) { // аргумент $name содержит название подключения // по названию подключения находим и возвращаем соответствующий конфиг $servers = conf()->get('servers'); if (!empty($servers[$name])) { $server = $servers[$name]; return [ 'driver' => 'mysql', 'host' => $server['ip_database'] ?? '127.0.0.1', 'port' => $server['port_database'] ?? 3306, 'database' => $server['name_database'], 'username' => $server['user_database'], 'password' => $server['pass_database'], 'unix_socket' => '', 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, ]; } return parent::configuration($name); } } 
    2. To replace the standard DatabaseManager with our modified class, create your DatabaseServiceProvider :

       php artisan make:provider DatabaseServiceProvider 

    Laravel will create it along the path \App\Providers\DatabaseServiceProvider . Change its code as follows:

     <?php namespace App\Providers; use App\Database\DatabaseManager; use Illuminate\Database\Connectors\ConnectionFactory; use Illuminate\Database\DatabaseServiceProvider as BaseDatabaseServiceProvider; class DatabaseServiceProvider extends BaseDatabaseServiceProvider { protected function registerConnectionServices() { $this->app->singleton('db.factory', function ($app) { return new ConnectionFactory($app); }); $this->app->singleton('db', function ($app) { // здесь создается объект нашего кастомизированного менеджера вместо стандартного return new DatabaseManager($app, $app['db.factory']); }); $this->app->bind('db.connection', function ($app) { return $app['db']->connection(); }); } } 
    1. In the config/app.php in the providers section, replace the standard DatabaseServiceProvider with a new one:

       //Illuminate\Database\DatabaseServiceProvider::class, \App\Providers\DatabaseServiceProvider::class, 

    How it should work .

    In DatabaseManager :: configuration () you can implement any logic for obtaining configuration for connecting to the database. This input method receives the name of the connection, which is written (or specified dynamically) in the $ connection property of the model or is explicitly specified via DB :: connection (), and returns the required array of parameters for the connection.

    In relation to your situation. All settings for connections you get this way:

     $servers = conf()->get('servers'); 

    Your $servers should have something like this:

      $servers = [ 'connection_1' => [ 'driver' => 'mysql', 'host' => 'host_1', ... // остальные параметры подключения к первой БД ], 'connection_2' => [ 'driver' => 'mysql', 'host' => 'host_2', ... // остальные параметры подключения ко второй БД ], ]; 

    You can use one model on different databases like this:

     $punishment = new Punishment(); $punishment->setConnection('connection_1'); dump($advert->count()); // будет выведено количество моделей в первой БД $punishment->setConnection('connection_2'); dump($advert->count()); // будет выведено количество моделей во второй БД 

    Or the same thing through direct access to the tables:

     // получение количества записей таблицы в первой БД dump(\DB::connection('connection_1')->table('punishments')->count()); // получение количества записей таблицы во второй БД dump(\DB::connection('connection_2')->table('punishments')->count()); 
    • > the $ name argument contains what is specified in the $ connection model And if a model is just one needed, you need to go over each database to connect, take data and go further (as above, for example), and the database can be an indefinite number (10 20 quite to yourself)? Simply, as I understand it, for the $connection specified in $connection , the connection to the database is determined, and then you can connect to the database with the call? If so, then you need to somehow model the model then dynamically transfer the name of the connection, is it possible? So far I have done as you indicated, but still gives out "... not configured". - Vladimir Gonchar
    • He added the answer with the explanation “How it should work”. - P. Fateev 5:33 pm
    • Understood thanks. - Vladimir Gonchar