Laravel 4: приложение для нескольких арендаторов, каждый арендатор имеет собственную базу данных и одну глобальную базу данных
В настоящее время у меня есть приложение, в котором размещаются несколько арендаторов, написанных в CodeIgniter.
Но я очень люблю Laravel 4, и мне бы хотелось начать переносить приложение в Laravel.
Вот текущая настройка:
- У каждого арендатора есть собственная база данных.
- Существует только один набор файлов приложений.
- Когда мы создаем нового арендатора, создается новая база данных и запускается установка script, а база данных засевается некоторой исходной информацией.
- У каждого арендатора также есть собственный субдомен. Вот как мы можем определить, какую базу данных использовать.
- Существует основная база данных, содержащая информацию арендатора и пользователей и некоторые другие общие таблицы.
- Когда требуется обновление схемы, мы просто создаем обновление script, которое будет выполняться для каждого арендатора. Это происходит через специально закодированный CLI script для Codeigniter
В Codeigniter относительно легко начать и завершить новые подключения к базе данных.
С Laravel у меня есть следующие вопросы/вопросы.
- Как вы можете запускать/завершать подключения к базе данных на лету?
- Я хотел бы использовать Migrations, но я хотел бы запускать их для каждого арендатора. Миграции в настоящее время работают только на "основном" подключении к базе данных. И он работает только один раз.
- То же самое касается посева..
Это мои основные проблемы, у меня есть и другие второстепенные вещи, но их можно обойти.
Надеюсь, кто-то может пролить немного света.
Ответы
Ответ 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) К сожалению, я не думаю, что посев поддерживает несколько соединений. Возможно, вам придется откатить свою собственную функцию посева.