funkymed/tenant-aware-bundle

适用于多租户应用的 Symfony 扩展包

安装: 8

依赖: 0

建议者: 0

安全性: 0

星标: 16

关注者: 3

分支: 0

公开问题: 2

类型:symfony-bundle

v0.1 2024-06-03 19:32 UTC

This package is not auto-updated.

Last update: 2024-09-22 15:54:24 UTC


README

Tenant Aware Bundle 帮助您管理应用程序的多个配置。

配置来自数据库。

安装

composer require funkymed/tenant-aware-bundle

创建配置文件 config/packages/tenant_aware.yaml

tenant_aware:
    processors:
        - Funkymed\TenantAwareBundle\DependencyInjection\Compiler\Processor\DummyProcessor
        - Funkymed\TenantAwareBundle\DependencyInjection\Compiler\Processor\DatabaseProcessor

修改 Kernel.php 以使用按租户缓存的配置

<?php

// src/Kernel.php

namespace App;

use Funkymed\TenantAwareBundle\TenantAwareKernel;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel
{
    use MicroKernelTrait;
    private ?string $hostname;

    public function __construct(
        string $environment,
        bool $debug,
        string $hostname
    ) {
        parent::__construct($environment, $debug);
        $this->hostname = $hostname;
    }

    public function getCacheDir(): string
    {
        if ($this->getHostname()) {
            return $this->getProjectDir().'/var/cache/'.$this->environment.'/'.$this->getHostname();
        }
        return $this->getProjectDir().'/var/cache/'.$this->environment;
    }

    public function getLogDir(): string
    {
        if ($this->getHostname()) {
            return $this->getProjectDir().'/var/log/'.$this->getHostname();
        }
        return $this->getProjectDir().'/var/log';
    }

    public function getName()
    {
        return str_replace('-', '_', $this->getHostname());
    }

    public function getKernelParameters(): array
    {
        $parameters = parent::getKernelParameters();
        $parameters['kernel.hostname'] = $this->getHostname();

        return $parameters;
    }
    public function getHostname()
    {
        $hostname = $this->getHost();
        return $hostname ? $hostname : $this->hostname;

    }
    public function getHost()
    {
        $possibleHostSources = array('HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR');
        $sourceTransformations = array(
            "HTTP_X_FORWARDED_HOST" => function ($value) {
                $elements = explode(',', $value);
                return trim(end($elements));
            }
        );
        $host = '';
        foreach ($possibleHostSources as $source) {
            if (!empty($host)) {
                break;
            }
            if (empty($_SERVER[$source])) {
                continue;
            }
            $host = $_SERVER[$source];
            if (array_key_exists($source, $sourceTransformations)) {
                $host = $sourceTransformations[$source]($host);
            }
        }

        // Remove port number from host
        $host = preg_replace('/:\d+$/', '', $host);

        return trim($host);
    }
}

然后将 bin/console 替换为以下代码以实现兼容性

#!/usr/bin/env php
<?php

// bin/console

use App\Kernel;
use Funkymed\TenantAwareBundle\Command\TenantAwareApplication;
use Symfony\Component\Console\Input\ArgvInput;

if (!is_dir(dirname(__DIR__).'/vendor')) {
    throw new LogicException('Dependencies are missing. Try running "composer install".');
}

if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
    throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}

require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

return function (array $context) {
    $input = new ArgvInput();
    $env = $input->getParameterOption(['--env', '-e'], getenv('APP_ENV') ?: 'dev');
    $debug = getenv('APP_DEBUG') !== '0' && $env !== 'prod';

    // Added support for tenant
    $hostname = $input->getParameterOption('--tenant');

    $kernel = new Kernel($env, $debug, $hostname);
    $kernel->boot();

    return new TenantAwareApplication($kernel);

};

现在您可以使用 symfony 的默认命令,但带有租户配置

bin/console d:d:c --tenant=localhost

租户参数是您要获取配置的主机名

配置

.envconfig/packages/doctrine.yaml 中添加您的数据库配置

# .env
DATABASE_HOST="localhost"
DATABASE_USER="root"
DATABASE_PASSWORD=""
DATABASE_NAME="tenant"
doctrine:
    dbal:
        driver: 'pdo_mysql'
        server_version: '8'
        use_savepoints: true
        host: '%env(resolve:DATABASE_HOST)%'
        port: 3306
        user: '%env(resolve:DATABASE_USER)%'
        password: '%env(resolve:DATABASE_URL)%'
        dbname: '%env(resolve:DATABASE_PASSWORD)%'

创建租户数据库

bin/console d:d:c --if-not-exist
bin/console d:s:u -f

向您的数据库添加内容以管理不同的主机名(参见租户实体)

添加您的处理器

添加更多服务

您还可以处理数据库以外的其他服务。您可能希望根据主机名更改 AWS S3、Redis 或 RabbitMQ。

只需复制 TenantAwareBundle/DependencyInjection/Compiler/Processor/DummyProcessor.php

并将其放入您的 DependencyInjection/Compiler/Processor 命名空间

在处理器中添加您想要替换的内容

<?php

// src/DependencyInjection/DependencyInjection/Compiler/Processor/DummyProcessor.php

namespace App\DependencyInjection\Compiler\Processor;

// use this as an exemple to create your own replacement configuration
class MyProcessor extends ProcessorAbstract
{
    public function process()
    {
        // get current definition
        $definition = $this->container->getDefinition('doctrine.dbal.default_connection');
        $configuration = $definition->getArguments();

        // update it from the tenant information
        $configuration[0]["host"] = $this->tenant->getDatabaseHost();
        $configuration[0]["dbname"] = $this->tenant->getDatabaseName();
        $configuration[0]["user"] = $this->tenant->getDatabaseUser();
        $configuration[0]["password"] = $this->tenant->getDatabasePassword();

        // replace the current configuration everything is in the cache now
        $definition->replaceArgument(0, $configuration[0]);
    }
}

更新配置

tenant_aware:
    processors:
        - App\DependencyInjection\Compiler\Processor\MyProcessor

您可以添加您想要的任何处理器。

您还可以替换实体租户以添加您需要管理租户的字段。