zhortein/multi-tenant-bundle 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

zhortein/multi-tenant-bundle

Composer 安装命令:

composer require zhortein/multi-tenant-bundle

包简介

A comprehensive Symfony 7+ bundle for building multi-tenant applications with PostgreSQL 16 support, featuring multiple resolution strategies, tenant-aware services, and automatic database filtering.

README 文档

README

A comprehensive Symfony 7+ bundle for building multi-tenant applications with PostgreSQL 16 support.

PHP Version Symfony Version PostgreSQL Version

Features

  • 🏢 Multiple Tenant Resolution Strategies: Subdomain, path-based, header-based, domain-based, DNS TXT, hybrid, or custom resolvers
  • 🗄️ Database Strategies: Shared database with filtering or separate databases per tenant
  • Performance Optimized: Built-in caching for tenant settings and configurations
  • 🔧 Doctrine Integration: Automatic tenant filtering with Doctrine ORM
  • 📧 Tenant-Aware Services: Mailer with automatic tenant propagation, Messenger with context preservation, and file storage integration
  • 🎯 Event-Driven: Database switching events and automatic tenant context resolution
  • 🛠️ Advanced Commands: Schema management, migrations, and fixtures for tenants
  • 🧪 Comprehensive Test Kit: First-class testing utilities to prove tenant isolation works
  • 🔒 RLS Integration: PostgreSQL Row-Level Security for defense-in-depth
  • 📊 PHPStan Level Max: Static analysis at maximum level

Installation

Install the bundle via Composer:

composer require zhortein/multi-tenant-bundle

Enable the bundle in your config/bundles.php:

<?php

return [
    // ...
    Zhortein\MultiTenantBundle\ZhorteinMultiTenantBundle::class => ['all' => true],
];

Quick Start

1. Create Your Tenant Entity

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Zhortein\MultiTenantBundle\Entity\TenantInterface;

#[ORM\Entity]
#[ORM\Table(name: 'tenants')]
class Tenant implements TenantInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\Column(type: 'string', length: 255, unique: true)]
    private string $slug;

    #[ORM\Column(type: 'string', length: 255)]
    private string $name;

    // Implement TenantInterface methods...
    
    public function getId(): ?int
    {
        return $this->id;
    }

    public function getSlug(): string
    {
        return $this->slug;
    }

    public function setSlug(string $slug): void
    {
        $this->slug = $slug;
    }

    // ... other methods
}

2. Configure the Bundle

Create config/packages/zhortein_multi_tenant.yaml:

zhortein_multi_tenant:
    tenant_entity: 'App\Entity\Tenant'
    resolver:
        type: 'subdomain'
        options:
            base_domain: 'example.com'
    database:
        strategy: 'shared_db'
        enable_filter: true

3. Create Tenant-Aware Entities

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Zhortein\MultiTenantBundle\Attribute\AsTenantAware;
use Zhortein\MultiTenantBundle\Entity\TenantAwareEntityTrait;

#[ORM\Entity]
#[AsTenantAware]
class Product
{
    use TenantAwareEntityTrait;

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\Column(type: 'string', length: 255)]
    private string $name;

    // ... other properties and methods
}

4. Use in Controllers

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Zhortein\MultiTenantBundle\Context\TenantContextInterface;

class DashboardController extends AbstractController
{
    public function index(TenantContextInterface $tenantContext): Response
    {
        $tenant = $tenantContext->getTenant();
        
        // All database queries are automatically filtered by tenant
        $products = $this->entityManager
            ->getRepository(Product::class)
            ->findAll(); // Only returns current tenant's products
        
        return $this->render('dashboard/index.html.twig', [
            'tenant' => $tenant,
            'products' => $products,
        ]);
    }
}

📚 Documentation

🚀 Getting Started

🏗️ Core Concepts

🔧 Service Integration

  • Mailer - Tenant-aware email with templated support
  • Messenger - Tenant-aware queues with automatic context propagation
  • Storage - File storage isolation

🗄️ Database Management

🛠️ Development Tools

📖 Examples

Testing with the Bundle

The bundle includes a comprehensive Test Kit to make testing multi-tenant applications easy and reliable:

Test Kit Features

  • WithTenantTrait: Execute code within specific tenant contexts
  • TestData: Lightweight builders for tenant-aware test entities
  • Base Test Classes: Pre-configured for HTTP, CLI, and Messenger testing
  • RLS Isolation Tests: Prove PostgreSQL Row-Level Security works as defense-in-depth

Quick Example

<?php

use Zhortein\MultiTenantBundle\Tests\Toolkit\TenantWebTestCase;

class ProductControllerTest extends TenantWebTestCase
{
    public function testTenantIsolation(): void
    {
        // Seed test data
        $this->getTestData()->seedProducts('tenant-a', 2);
        $this->getTestData()->seedProducts('tenant-b', 1);
        
        // Test tenant A sees only its data
        $this->withTenant('tenant-a', function () {
            $products = $this->repository->findAll();
            $this->assertCount(2, $products);
        });
        
        // Test RLS isolation (critical test)
        $this->withTenant('tenant-a', function () {
            $this->withoutDoctrineTenantFilter(function () {
                $products = $this->repository->findAll();
                // Should still see only 2 products due to RLS
                $this->assertCount(2, $products);
            });
        });
    }
}

Running Tests

# Run all tests
make test

# Run unit tests only
make test-unit

# Run integration tests only
make test-integration

# Run Test Kit RLS isolation tests
vendor/bin/phpunit tests/Integration/RlsIsolationTest.php

# Run with coverage
make test-coverage

See the Testing Documentation for complete Test Kit usage.

Code Quality

# PHPStan at maximum level
make phpstan

# PHP-CS-Fixer code style check
make csfixer-check

# Fix code style
make csfixer

# Run all quality checks
make dev-check

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for your changes
  4. Ensure all tests pass and code meets quality standards
  5. Submit a pull request

See CONTRIBUTING.md for detailed guidelines.

License

This bundle is released under the MIT License. See the LICENSE file for details.

Support

Changelog

See CHANGELOG.md for version history and upgrade instructions.

统计信息

  • 总下载量: 30
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 3
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 3
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-08-04