Как подключиться к различным базам данных во время выполнения?

Я делаю многопользовательское приложение с несколькими базами данных, в котором есть одна центральная база данных и множество подбатарей.

Приложение создает экземпляр организации в центральной базе данных, и в каждой организации создается суб-база данных с разными таблицами.

Чтобы достичь этого, я создал классную программу Setup которая

  1. Создает Организацию
  2. Создает свою базу данных
  3. Настраивает соединение с этой базой данных и подключается к ней
  4. Выполняет соответствующие миграции.

Все завершено в конструкторе, поэтому при Setup::create все это выполняется правильно.

Большинство настроек и подключения базы данных вдохновляются этим учебным пособием .

Чтобы проверить, идет ли моя логика, как я хотел, я взаимодействовал с моим приложением через:

  1. паять
  2. Веб-браузер.

К моему удивлению, в обоих случаях результат различен и никогда не нужен для связи с другой базой данных.

Взаимодействие с мастером :

После создания вызова моей Setup::create и вывода, в котором говорится, что все прошло хорошо, я пытаюсь проверить, какая база данных я сейчас использую. Использование:

 DB::connection()->getDatabaseName() 

Он выводит имя под-базы данных, которое мы только что создали для организации и связанное с ней, что логично и идет соответствующим образом.

Тем не менее, я пытаюсь подключиться к другой базе данных, создав для нее новую конфигурацию, а затем подключившись к ней с помощью методов DB которые я предоставил, это не работает, я все еще на суббадре, в которой я был.


Взаимодействие с браузером :

На этот раз, когда моя Setup::create завершена правильно в коде моего контроллера, я снова пытаюсь проверить все, я также сделал строку в своем макете, чтобы вывести мне текущую базу данных:

 <?php echo DB::connection()->getDatabaseName() ?> 

Сначала, пока я все еще нахожусь в центральной базе данных, появляется его имя, однако после вызова Setup::create он переключается на под-базу данных – что ожидается – но затем, после одного обновления, я снова попал в центральную базу данных – Что совершенно неожиданно

Итак, что здесь происходит? и как мне добраться до всех моих разных баз данных, как я хочу, когда захочу?

Дополнительно :

Тестирование во владении, я перешел к точке, где я прокомментировал код миграции, и оставил создание базы данных, а также соединение с ней. К моему удивлению, он не подключается к базе данных. поэтому я начал думать, что код миграции имеет какое-то отношение к подключению к базе данных, или, может быть, возиться с разными поведением, которые я полностью задерживаю.

Важно :

  • Я столкнулся с проблемами, когда упоминались решения, использующие QueryBuilders
  • Пожалуйста, не предоставляйте такие ответы, потому что моя цель – полностью переключить базы данных до такой степени, что я могу использовать события красноречивой модели без проблем.
    • Под этим я подразумеваю, что хочу иметь возможность использовать Model::create после подключения к базе данных вместо DB::connection()->....

Технические характеристики :

Я использую Laravel 5 с mysql-сервером на Ubuntu Machine.

Я наткнулся на этот вопрос, и у меня был мой ответ.

Я создал класс под названием DatabaseConnection :

 class DatabaseConnection extends Model { static $instances=array(); protected $database; protected $connection; public function __construct($options = null) { // Set the database $database = $options['database']; $this->database = $database; // Figure out the driver and get the default configuration for the driver $driver = isset($options['driver']) ? $options['driver'] : Config::get("database.default"); $default = Config::get("database.connections.$driver"); // Loop through our default array and update options if we have non-defaults foreach($default as $item => $value) { $default[$item] = isset($options[$item]) ? $options[$item] : $default[$item]; } $capsule = new Capsule; $capsule->addConnection($default); $capsule->setEventDispatcher(new Dispatcher(new Container)); $capsule->setAsGlobal(); $capsule->bootEloquent(); // Create the connection $this->connection = $capsule->getConnection(); DatabaseConnection::$instances[] = $capsule; return $this->connection; } } по class DatabaseConnection extends Model { static $instances=array(); protected $database; protected $connection; public function __construct($options = null) { // Set the database $database = $options['database']; $this->database = $database; // Figure out the driver and get the default configuration for the driver $driver = isset($options['driver']) ? $options['driver'] : Config::get("database.default"); $default = Config::get("database.connections.$driver"); // Loop through our default array and update options if we have non-defaults foreach($default as $item => $value) { $default[$item] = isset($options[$item]) ? $options[$item] : $default[$item]; } $capsule = new Capsule; $capsule->addConnection($default); $capsule->setEventDispatcher(new Dispatcher(new Container)); $capsule->setAsGlobal(); $capsule->bootEloquent(); // Create the connection $this->connection = $capsule->getConnection(); DatabaseConnection::$instances[] = $capsule; return $this->connection; } } 

Итак, всякий раз, когда я нахожусь в контроллере, который управляет таблицами суббазы, я просто иду так:

 public function RandomActionInMyController() { $db_connection = new DatabaseConnection(['database' => 'name_of_db']); $someModel = new Model/Model::find()..// Basically anything return myreturnstuff; } 

Дополнительный бонус :

Использование статического атрибута $instances в моем DatabaseConnection сводится к тому, чтобы восстановить мое последнее соединение с базой данных для удобства использования.

Например, если бы я когда-либо хотел получить его, он был бы завернут в функцию, такую ​​как

 function CurrentOrLatestDbConnection() { if( !empty(DatabaseConnection::$instances) ) { return end(DatabaseConnection::$instances)->getConnection()->getDatabaseName(); } } 

Примечания :

Если вы столкнулись с такими ошибками, как Unknown class 'Container' или « Capsule или что-нибудь в этом роде, убедитесь, что вы проверяете ссылку на вопрос, которую я предоставил, и правильно use утверждения use .

Что касается предстоящих ответов :

Мне кажется, что это соединение с базой данных живет в скобках действия контроллера, поэтому, когда я перехожу к другому действию, который не указывает на соединение, он автоматически возвращается в центральную базу данных.

Который заставил меня думать, что должен быть способ установить соединение с базой данных с суб-базой «глобальным» способом для всей функции, например, промежуточного программного обеспечения или чего-то еще.

Мне бы хотелось увидеть ответ, воплотив такую ​​вещь.

Обновление :

Я придумал более аккуратный способ сделать это.

Я предполагаю, что вы на том же основании, что и я, желая изменить базы данных условно в соответствии с каждым контроллером … скажем, для каждого из ваших контроллеров требуется другая база данных только ради аргумента.

То, что мы будем использовать для решения этой проблемы, – «Middlewares».

Во-первых, чтобы объяснить, что мы собираемся делать.

Мы собираемся проверить имя контроллера (и даже действие), а затем установить нужную базу данных, которую мы хотим установить.

  1. Перейдите в свою командную строку, введите:

    php artisan make:middleware SetDatabaseConnectionMiddleware

Создание промежуточного программного обеспечения с готовым шаблоном.

Или, если вам это нравится, перейдите в свое приложение app_name / app / Http / Middleware и создайте его вручную.

  1. Перейдите в свой файл методов-помощников (если у вас уже есть один, если нет, чувак сделает это!)

      function getControllerAndActionName() { $action = app('request')->route()->getAction(); $controller = class_basename($action['controller']); list($controller, $action) = explode('@', $controller); return ['action' => $action, 'controller' => $controller]; } 

Это вернет вам массив с именем действия и именем контроллера, если вы хотите ограничить просто имя контроллера, не стесняйтесь удалять 'action' => $action из кода.

  1. Внутри вашего промежуточного ПО это будет выглядеть так:

  namespace App\Http\Middleware; use Closure; use DatabaseConnection; class SetProperDatabase { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $database_name = ''; $controllerAndActionName = getControllerAndActionName(); $controller_name = $controllerAndActionName['controller']; $action_name = $controllerAndActionName['action']; if($controller_name == 'my_controller_nameController') { $database_name = 'your_proper_database_name'; } else { $database_name = 'other_db'; } $database_connection = new DatabaseConnection(['database' => $database_name']); return $next($request); } } 

4. Теперь, что вы правильно создали свое промежуточное ПО, давайте расскажем вашему приложению, где его найти и под каким именем.

  1. Перейдите в свое app_name / app / Http / Kernel.php
  2. В переменной $routeMiddleware добавьте эту строку

    'set_proper_database' => \App\Http\Middleware\SetProperDatabase::class,

Таким образом, мы знаем, как это назвать.

  1. Наконец, настройте его.

    1. Перейдите в свой Controller.php (класс Abstract, из которого наследуется все наследование вашего контроллера)

    public function __construct() { $this->middleware('set_proper_database'); }

И это должно сделать это за вас.

Если у вас есть дополнительные вопросы, не стесняйтесь комментировать.

// Ресурсы :

1. Имя контроллера и действия

2. Документация промежуточного программного обеспечения

3. Дальнейшие примечания по документации промежуточного программного обеспечения : я был бы признателен за некоторые издания, касающиеся моего стиля и отступов кода, так как кажется, что я изо всех сил пытался правильно подстроить свой код здесь, но тщетно, у меня не было никаких отступов.