Подтвердить что ты не робот

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

В настоящее время у меня есть приложение, в котором размещаются несколько арендаторов, написанных в CodeIgniter. Но я очень люблю Laravel 4, и мне бы хотелось начать переносить приложение в Laravel.

Вот текущая настройка:

  • У каждого арендатора есть собственная база данных.
  • Существует только один набор файлов приложений.
  • Когда мы создаем нового арендатора, создается новая база данных и запускается установка script, а база данных засевается некоторой исходной информацией.
  • У каждого арендатора также есть собственный субдомен. Вот как мы можем определить, какую базу данных использовать.
  • Существует основная база данных, содержащая информацию арендатора и пользователей и некоторые другие общие таблицы.
  • Когда требуется обновление схемы, мы просто создаем обновление script, которое будет выполняться для каждого арендатора. Это происходит через специально закодированный CLI script для Codeigniter

В Codeigniter относительно легко начать и завершить новые подключения к базе данных.

С Laravel у меня есть следующие вопросы/вопросы.

  • Как вы можете запускать/завершать подключения к базе данных на лету?
  • Я хотел бы использовать Migrations, но я хотел бы запускать их для каждого арендатора. Миграции в настоящее время работают только на "основном" подключении к базе данных. И он работает только один раз.
  • То же самое касается посева..

Это мои основные проблемы, у меня есть и другие второстепенные вещи, но их можно обойти.

Надеюсь, кто-то может пролить немного света.

4b9b3361

Ответ 1

Я просто принимаю удар, так что будьте осторожны:) Класс DatabaseManager, который используется всякий раз, когда вы вызываете DB, имеет и расширяет метод. Здесь ссылка на источник. Метод DB:: connection() должен возвращать экземпляр Illuminate\Database\Connection. Из всего этого я создал бы новое пользовательское соединение следующим образом:

$user = Auth::user();
DB::extend($user->username, function() use ($user) {
   // $pdo = new PDO(); set this up how you see fit
    return new Illuminate\Database\Connection($pdo, $user->databaseName, $tablePrefix);
});

Лично я хотел бы добавить новый метод для каждого пользователя User:: databaseConnection() и вызвать его при расширении DatabaseManager.

DB::extend($user->username, function() use ($user) {
    return $user->databaseConnection();
});

Через ваше приложение вы можете позвонить зарегистрированному пользовательскому соединению через:

DB::connection(Auth::user()->username);

Обновление

В зависимости от того, как часто и когда вы вызываете соединение с арендатором, вы можете использовать контейнер IOC.

App::bind('tenantDB', function()
{
     return DB::connection(Auth::user()->username);
});

App::make('tenantDB')->insert(...);

Я забыл о миграции и посеве. Для миграции вы можете установить путь к файлу

php artisan migrate:make foo --path=app/migrations

Итак, если вы используете класс Config для установки базы данных по умолчанию или DB:: setDefaultConnection ($ username), я бы предположил, что все миграции и сеяние будут выполнены для текущего соединения. Когда этот процесс будет завершен, вы можете вернуться к основной базе данных.

Обновление 2

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

artisan migrate --database='userConnectionName' 
artisan db:seed --database='userConnectionName'

Глядя на ответ Барри, это, вероятно, намного проще, чем расширение DatabaseManager.

Если вы хотите, чтобы все параметры этих команд выполнялись только:

artisan help migrate
artisan help db:seed

Ответ 2

Вы можете создать 1 базу данных с учетными данными базы данных арендатора и динамически установить их в своем приложении:

$tenant = Tenant::where('username', '=', $username)->first();
Config::set('database.connections.tenant.username', $tenant->db_username);
Config::set('database.connections.tenant.password', $tenant->db_password);
Config::set('database.connections.tenant.database', $tenant->db_database);

Для этого потребуется создать 2 соединения в файле database.php. (например, приложение и арендатор) и укажите в своей модели, какую базу данных использовать (1 для хранения арендаторов, 1 для конкретной базы данных арендатора)

И, возможно, создайте маршрут / script для создания/обновления таблиц. Не уверен о миграции с несколькими базами данных.

Ответ 3

Вы можете создавать динамические соединения DB в laravel со следующим синтаксисом

Config::set('database.connections.key', array(
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'dbname',
    'username'  => 'dbuser',
    'password'  => 'dbpass',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
));

С этим DB::connection('key'); would just work.

Ответ 4

Недавно я столкнулся с подобной проблемой, пришлось использовать разные базы данных для нескольких моделей.

Я нашел следующее, чтобы сделать трюк.

  • В app/config/database.php добавьте новое подключение MY_NEW_CONNECTION
  • Для нового подключения установите имя базы данных на
  • В методах filters.php или routes.php или контроллера __construct добавьте следующее:

    $db = 'получить имя вашей базы данных'; Config:: набор ( 'database.connections.MY_NEW_CONNECTION.database', $дб); DB:: setDefaultConnection ( 'MY_NEW_CONNECTION');

Ответ 5

1) Вы можете определить несколько именованных соединений в конфигурационном файле database.php

'connections' => array(
    'tenant1' => array(
     ...
    ),
    'tenant2' => array(
     ...
    ),

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

$something = DB::connection('tenant1')->select(...);

2) Это не полное решение, так как я думаю, что это потребует некоторого взлома в ядре, но вы можете выбрать, для какого соединения выполнить миграцию. Возможно, вы могли бы перебирать список своих арендаторов и запускать их на всех.

Schema::connection('tenant1')->create('users', function($table)

3) К сожалению, я не думаю, что посев поддерживает несколько соединений. Возможно, вам придется откатить свою собственную функцию посева.