简体   繁体   English

Laravel多租户迁移

[英]Laravel multi tenant migrate

Wondering if anyone knows how or of a package that allows migrations to be done on multiple databases without having the additional connection in the config file. 想知道是否有人知道如何允许在多个数据库上进行迁移而无需在配置文件中具有其他连接的软件包。 Currently I have two different connections, one for the default and another for the tenants. 目前,我有两种不同的连接方式,一种是默认连接,另一种是租户。 The tenant connection has the credentials input, but it doesn't have the database name since each tenant will have a different database name. 承租人连接具有凭据输入,但没有数据库名称,因为每个承租人将具有不同的数据库名称。 Problem is when I'm doing the initial setup and need the migrations to be run it will do it for the default or the tenant(if I edit the file to include the database name). 问题是当我进行初始设置并需要运行迁移时,它将对默认值或承租人执行此操作(如果我编辑文件以包含数据库名称)。 I had found a package that would do it but it is not currently compatible with laravel 5. Obviously if I have to do it manually it can be done. 我已经找到了可以使用它的软件包,但是目前与laravel 5不兼容。显然,如果我必须手动进行操作,则可以完成。 It would just be a pain. 那就太痛苦了。 Thanks in advance for suggestions. 在此先感谢您的建议。

Looking through the tenancy related questions here, I stumbled upon your open one. 在查看与租赁相关的问题时,我偶然发现了您的未解决问题。

What I've done is override the default MigrateCommand provided by Laravel and add the --tenant option. 我所做的是覆盖Laravel提供的默认MigrateCommand并添加--tenant选项。 This will allow me to migrate one, more or all tenants. 这将允许我迁移一个,多个或所有租户。 You can check the implementation out at my repository . 您可以在我的存储库中检查实现。 Knowing the code of conduct here, I'll also add an example implementation: 在这里了解行为准则后,我还将添加一个示例实现:

<?php

namespace Hyn\MultiTenant\Commands\Migrate;

use Hyn\MultiTenant\Traits\TenantDatabaseCommandTrait;
use Illuminate\Database\Migrations\Migrator;
use PDOException;

class MigrateCommand extends \Illuminate\Database\Console\Migrations\MigrateCommand
{
    use TenantDatabaseCommandTrait;

    /**
     * MigrateCommand constructor.
     *
     * @param Migrator $migrator
     */
    public function __construct(Migrator $migrator)
    {
        parent::__construct($migrator);

        $this->website = app('Hyn\MultiTenant\Contracts\WebsiteRepositoryContract');
    }

    public function fire()
    {

        // fallback to default behaviour if we're not talking about multi tenancy
        if (! $this->option('tenant')) {
            $this->info('No running tenancy migration, falling back on native laravel migrate command due to missing tenant option.');

            return parent::fire();
        }

        if (! $this->option('force') && ! $this->confirmToProceed()) {
            $this->error('Stopped no confirmation and not forced.');

            return;
        }

        $websites = $this->getWebsitesFromOption();

        // forces database to tenant
        if (! $this->option('database')) {
            $this->input->setOption('database', 'tenant');
        }

        foreach ($websites as $website) {
            $this->info("Migrating for {$website->id}: {$website->present()->name}");

            $website->database->setCurrent();

            $this->prepareDatabase($website->database->name);

            // The pretend option can be used for "simulating" the migration and grabbing
            // the SQL queries that would fire if the migration were to be run against
            // a database for real, which is helpful for double checking migrations.
            $pretend = $this->input->getOption('pretend');

            // Next, we will check to see if a path option has been defined. If it has
            // we will use the path relative to the root of this installation folder
            // so that migrations may be run for any path within the applications.
            if (! is_null($path = $this->input->getOption('path'))) {
                $path = $this->laravel->basePath().'/'.$path;
            } else {
                $path = $this->getMigrationPath();
            }

            try {
                $this->migrator->run($path, $pretend);
            } catch (PDOException $e) {
                if (str_contains($e->getMessage(), ['Base table or view already exists'])) {
                    $this->comment("Migration failed for existing table; probably a system migration: {$e->getMessage()}");
                    continue;
                }
            }

            // Once the migrator has run we will grab the note output and send it out to
            // the console screen, since the migrator itself functions without having
            // any instances of the OutputInterface contract passed into the class.
            foreach ($this->migrator->getNotes() as $note) {
                $this->output->writeln($note);
            }
        }

        // Finally, if the "seed" option has been given, we will re-run the database
        // seed task to re-populate the database, which is convenient when adding
        // a migration and a seed at the same time, as it is only this command.
        if ($this->input->getOption('seed')) {
            $this->call('db:seed', ['--force' => true, '--tenant' => $this->option('tenant')]);
        }
    }

    /**
     * Prepare the migration database for running.
     *
     * @return void
     */
    protected function prepareDatabase($connection = null)
    {
        if (! $connection) {
            $connection = $this->option('database');
        }

        $this->migrator->setConnection($connection);

        if (! $this->migrator->repositoryExists()) {
            $options = ['--database' => $connection];

            $this->call('migrate:install', $options);
        }
    }

    /**
     * @return array
     */
    protected function getOptions()
    {
        return array_merge(
            parent::getOptions(),
            $this->getTenantOption()
        );
    }
}

If you have any questions to solve this issue, let me know. 如果您有任何疑问要解决此问题,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM