Laravel多租户迁移

时间:2015-05-05 14:40:27

标签: php mysql laravel-5

想知道是否有人知道如何或允许在多个数据库上完成迁移而不在配置文件中有额外连接的包。目前我有两个不同的连接,一个用于默认连接,另一个用于租户。租户连接具有凭证输入,但它没有数据库名称,因为每个租户将具有不同的数据库名称。问题是,当我进行初始设置并需要运行迁移时,它将为默认或租户执行此操作(如果我编辑文件以包含数据库名称)。我找到了一个可以做到这一点的软件包,但它目前与laravel 5不兼容。显然,如果我必须手动完成它就可以完成。这只会是一种痛苦。提前感谢您的建议。

1 个答案:

答案 0 :(得分:0)

在这里查看与租赁相关的问题,我偶然发现了你的问题。

我所做的是覆盖Laravel提供的默认MigrateCommand并添加--tenant选项。这将允许我迁移一个,多个或所有租户。您可以查看constructor options的实施情况。在这里了解行为准则,我还将添加一个示例实现:

<?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()
        );
    }
}

如果您有任何问题要解决此问题,请与我们联系。

相关问题