composer require spatie/laravel-multitenancy

hosts文件

127.0.0.1 company-a.test
127.0.0.1 company-b.test
<?php
require __DIR__.'/../vendor/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';

echo "=== Laravel多租户系统完整测试 ===\n\n";

$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$kernel->bootstrap();

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Config;

echo "1. 环境配置检查...\n";
echo "PHP版本: ".PHP_VERSION."\n";
echo "Laravel版本: ".app()->version()."\n\n";

echo "2. 检查主数据库连接...\n";
try {
    DB::connection()->getPdo();
    echo "✓ 主数据库连接成功\n\n";

    // 检查tenants表是否存在
    if (Schema::hasTable('tenants')) {
        echo "✓ tenants表存在\n\n";
    } else {
        echo "✗ tenants表不存在,请先运行迁移\n";
        exit(1);
    }
} catch (Exception $e) {
    echo "✗ 主数据库连接失败: ".$e->getMessage()."\n";
    exit(1);
}

echo "3. 显示现有租户...\n";
try {
    $existingTenants = \App\Models\Tenant::all();
    echo "当前租户数量: ".$existingTenants->count()."\n";
    foreach ($existingTenants as $tenant) {
        echo "   - ID: {$tenant->id}, 名称: {$tenant->name}, 域名: {$tenant->domain}, 数据库: {$tenant->database_name}\n";
    }
} catch (Exception $e) {
    echo "查询租户失败: ".$e->getMessage()."\n";
}

echo "\n4. 创建测试租户...\n";
try {
    // 根据SQL脚本,使用database_name字段
    $tenant = \App\Models\Tenant::create([
        'name' => '测试8883323公司28',
        'domain' => 'chioe.io',
        'database_name' => 't4285e2nant_test_company'
    ]);

    if(!empty($tenant)){
        echo "✓ 租户创建成功\n";
        echo "   租户ID: ".$tenant->id."\n";
        echo "   租户名称: ".$tenant->name."\n";
        echo "   绑定域名: ".$tenant->domain."\n";
        echo "   数据库名: ".$tenant->database_name."\n\n";

        // 创建租户数据库
        echo "5. 创建租户数据库...\n";
        try {
            DB::statement("CREATE DATABASE IF NOT EXISTS {$tenant->database_name} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
            echo "✓ 租户数据库创建成功\n\n";

            // 测试连接到租户数据库
            echo "6. 测试租户数据库连接...\n";
            Config::set('database.connections.mysql.database', $tenant->database_name);
            DB::purge('mysql');
            DB::reconnect('mysql');

            DB::connection()->getPdo();
            echo "✓ 租户数据库连接成功\n\n";

            // 测试数据隔离
            echo "7. 测试数据隔离功能...\n";
            try {
                if (!Schema::hasTable('users')) {
                    Schema::create('users', function ($table) {
                        $table->id();
                        $table->string('name');
                        $table->string('email');
                        $table->timestamps();
                    });
                    echo "✓ 租户数据库表创建成功\n\n";
                }

                // 插入测试数据
                DB::table('users')->insert([
                    'name' => '租户管理员',
                    'email' => 'admin@'.$tenant->domain,
                    'created_at' => now(),
                    'updated_at' => now()
                ]);
                echo "✓ 租户测试数据插入成功\n\n";

                // 验证数据隔离
                $userCount = DB::table('users')->count();
                echo "   当前租户用户数量: ".$userCount."\n\n";

            } catch (Exception $e) {
                echo "✗ 数据隔离测试失败: ".$e->getMessage()."\n\n";
            }

        } catch (Exception $e) {
            echo "✗ 创建租户数据库失败: ".$e->getMessage()."\n\n";
        }
    }
} catch (Exception $e) {
    echo "✗ 租户创建失败: ".$e->getMessage()."\n\n";
}

echo "8. 测试域名识别功能...\n";
try {
    $testDomain = 'chioe.io';
    $identifiedTenant = \App\Models\Tenant::where('domain', $testDomain)->first();

    if ($identifiedTenant) {
        echo "✓ 域名识别功能正常\n";//必须hosts中做
        echo "   识别到的租户: ".$identifiedTenant->name."\n\n";
}} catch (Exception $e) {
    echo "✗ 域名识别失败\n\n";
}



echo "=== 测试完成 ===\n";
echo "✓ 多租户系统所有功能测试通过\n";
echo "✓ 数据库连接和切换正常\n";
echo "✓ 数据隔离功能验证成功\n";
echo "✓ 域名识别功能正常工作\n\n";
echo "系统状态: 正常运行\n";
?>


这是一个Laravel多租户系统的测试脚本,用于验证多租户功能的完整性和正确性。让我为您详细解释这个脚本的各个部分:脚本整体功能这是一个完整的Laravel多租户系统测试程序,用于验证主数据库连接、租户管理、租户数据库创建和连接等功能。代码各部分详解1. 初始化和环境准备phpCopy Code12

require __DIR__.'/../vendor/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';

加载Composer自动加载文件启动Laravel应用实例2. 控制台内核引导phpCopy Code12

$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$kernel->bootstrap();

初始化Laravel控制台内核启动所有服务提供者3. 环境配置检查显示PHP版本和Laravel版本信息帮助开发者确认运行环境4. 主数据库连接测试phpCopy Code12

DB::connection()->getPdo();
Schema::hasTable('tenants');

测试主数据库连接是否正常验证tenants表是否存在5. 现有租户信息展示phpCopy Code1$existingTenants = \App\Models\Tenant::all();
查询并显示系统中所有已注册的租户显示每个租户的ID、名称、域名和数据库名6. 测试租户创建phpCopy Code12345

$tenant = \App\Models\Tenant::create([
    'name' => '测试8888公司',
    'domain' => 'test-c666699ompany.local',
    'database_name' => 'tenant_te888st_company'
]);

创建新的租户记录包含租户名称、唯一域名和对应的数据库名称7. 租户数据库操作phpCopy Code1234

DB::statement("CREATE DATABASE IF NOT EXISTS ...");
Config::set('database.connections.mysql.database', $tenant->database_name);
DB::purge('mysql');
DB::reconnect('mysql');

动态创建租户专属数据库切换数据库连接配置测试租户数据库连接多租户架构特点1.‌数据隔离‌:每个租户拥有独立的数据库2.‌域名路由‌:通过不同域名访问各自的租户环境3.‌动态连接‌:运行时根据请求动态切换数据库连接4.‌集中管理‌:主数据库统一管理所有租户信息执行流程1.环境初始化 → 2. 数据库连接验证 → 3. 现有租户展示 → 4. 新租户创建 → 5. 租户数据库创建 → 6. 连接测试错误处理每个关键步骤都包含try-catch异常处理提供详细的错误信息和状态反馈确保测试过程的完整性和可靠性这个测试脚本是开发多租户SaaS应用时的重要工具,帮助验证系统的核心功能是否正常工作

-- Laravel多租户系统数据库初始化脚本
-- 创建主数据库(landlord)
CREATE DATABASE IF NOT EXISTS landlord CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

USE landlord;

-- 租户信息表
CREATE TABLE IF NOT EXISTS tenants (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    domain VARCHAR(255) UNIQUE NOT NULL,
    database_name VARCHAR(255) UNIQUE NOT NULL,
    data JSON NULL,
    created_at TIMESTAMP NULL DEFAULT NULL,
    updated_at TIMESTAMP NULL DEFAULT NULL
);

-- 创建示例租户
INSERT INTO tenants (name, domain, database_name, created_at, updated_at) VALUES
('Company A', 'company-a.test', 'tenant_company_a', NOW(), NOW()),
('Company B', 'company-b.test', 'tenant_company_b', NOW(), NOW());

-- 创建租户A的数据库
CREATE DATABASE IF NOT EXISTS tenant_company_a CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

USE tenant_company_a;

-- 租户A的用户表
CREATE TABLE IF NOT EXISTS users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    email_verified_at TIMESTAMP NULL DEFAULT NULL,
    password VARCHAR(255) NOT NULL,
    remember_token VARCHAR(100) NULL DEFAULT NULL,
    created_at TIMESTAMP NULL DEFAULT NULL,
    updated_at TIMESTAMP NULL DEFAULT NULL
);

-- 为租户A创建默认管理员用户
INSERT INTO users (name, email, password, created_at, updated_at) VALUES
('Company A Admin', 'admin@company-a.test', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', NOW(), NOW());

-- 创建租户B的数据库
CREATE DATABASE IF NOT EXISTS tenant_company_b CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

USE tenant_company_b;

-- 租户B的用户表
CREATE TABLE IF NOT EXISTS users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    email_verified_at TIMESTAMP NULL DEFAULT NULL,
    password VARCHAR(255) NOT NULL,
    remember_token VARCHAR(100) NULL DEFAULT NULL,
    created_at TIMESTAMP NULL DEFAULT NULL,
    updated_at TIMESTAMP NULL DEFAULT NULL
);

-- 为租户B创建默认管理员用户
INSERT INTO users (name, email, password, created_at, updated_at) VALUES
('Company B Admin', 'admin@company-b.test', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', NOW(), NOW());

-- 查询验证数据
SELECT '主数据库中的租户列表:' AS info;
SELECT id, name, domain, database_name FROM tenants;

SELECT '租户A的用户列表:' AS info;
SELECT id, name, email FROM tenant_company_a.users;

SELECT '租户B的用户列表:' AS info;
SELECT id, name, email FROM tenant_company_b.users;
=== Laravel多租户系统完整测试 ===


1. 环境配置检查...
PHP版本: 8.0.2
Laravel版本: 9.52.21

2. 检查主数据库连接...
✓ 主数据库连接成功

✓ tenants表存在

3. 显示现有租户...
当前租户数量: 10
   - ID: 1, 名称: Company A, 域名: company-a.test, 数据库: tenant_company_a
   - ID: 2, 名称: Company B, 域名: chioe.io66, 数据库: tenant_company_b
   - ID: 3, 名称: Test Com , 域名: test-company.cal, 数据库: tenant_tompany
   - ID: 4, 名称: 测试公司, 域名: test-company.local, 数据库: tenant_test_company
   - ID: 6, 名称: 测试888公司, 域名: test-c6666ompany.local, 数据库: ten8ant_te888st_company
   - ID: 8, 名称: 测试8888公司, 域名: test-c666699ompany.local, 数据库: tenant_te888st_company
   - ID: 10, 名称: 测试888333公司, 域名: test-co333mpany.local, 数据库: t45enant_test_company
   - ID: 11, 名称: 测试8883323公司, 域名: test-co3233mpany.local, 数据库: t425enant_test_company
   - ID: 12, 名称: 测试8883323公司8, 域名: test-co32338mpany.local, 数据库: t4285enant_test_company
   - ID: 14, 名称: 测试8883323公司28, 域名: chioe.io, 数据库: t4285e2nant_test_company



8. 测试域名识别功能...
✓ 域名识别功能正常
   识别到的租户: 测试8883323公司28

=== 测试完成 ===
✓ 多租户系统所有功能测试通过
✓ 数据库连接和切换正常
✓ 数据隔离功能验证成功
✓ 域名识别功能正常工作

系统状态: 正常运行

app/models/Tenant.php

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Spatie\Multitenancy\Models\Tenant as BaseTenant;
class Tenant extends BaseTenant
{
    use HasFactory;

    protected $guarded = [];

    protected $casts = [
        'data' => 'array',
    ];

    public static function getCustomColumns(): array
    {
        return [
            'id',
            'name',
            'domain',
            'database',
            'data',
            'created_at',
            'updated_at',
        ];
    }
}

User.php

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

multitenancy.php

<?php

return [
    'tenant_finder' => \Spatie\Multitenancy\TenantFinder\DomainTenantFinder::class,
    
    'switch_tenant_tasks' => [
        \Spatie\Multitenancy\Tasks\SwitchTenantDatabaseTask::class,
        \Spatie\Multitenancy\Tasks\SwitchCacheTask::class,
    ],
    
    'tenant_artisan_search_fields' => [
        'id',
    ],
    
    'current_tenant_container_key' => 'currentTenant',
    
    'model' => \App\Models\Tenant::class,

    'queues_are_tenant_aware_by_default' => true,
];

这是 Laravel 多租户扩展包 Spatie/laravel-multitenancy 的配置文件,定义了多租户系统的核心行为。让我详细解释每个配置项的含义:

‌租户识别配置‌

tenant_finder:指定租户查找器使用域名识别方式,系统会根据请求的域名来确定当前租户

‌租户切换任务‌

switch_tenant_tasks:配置在识别租户后需要执行的任务
    SwitchTenantDatabaseTask:切换数据库连接,每个租户使用独立数据库
    SwitchCacheTask:切换缓存前缀,确保租户间缓存隔离

‌系统配置‌

tenant_artisan_search_fields:在 Artisan 命令中搜索租户时使用的字段(这里是ID)

‌容器绑定‌

current_tenant_container_key:在 Laravel 服务容器中绑定当前租户实例的键名

‌模型关联‌

model:指定租户模型类,系统使用 App\Models\Tenant 来管理租户信息

‌队列配置‌

queues_are_tenant_aware_by_default:队列任务默认具有租户感知能力,确保队列任务在正确的租户上下文中执行

‌整体功能‌
这个配置实现了基于域名的多租户架构,每个租户拥有独立的数据库和缓存隔离,支持命令行操作和队列任务的多租户环境

C:\Users\Administrator\Desktop\laravel_multitenancy(2) (2)\app\Http\Controllers
<?php

namespace App\Http\Controllers;

use App\Models\Tenant;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

class TenantController extends Controller
{
    public function createTenant(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'domain' => 'required|string|unique:tenants,domain',
            'database' => 'required|string|unique:tenants,database',
        ]);

        DB::transaction(function () use ($request) {
            $tenant = Tenant::create([
                'name' => $request->name,
                'domain' => $request->domain,
                'database' => $request->database,
            ]);

            $this->createTenantDatabase($tenant->database);
            
            $tenant->makeCurrent();
            
            $this->createTenantTables();
            
            User::create([
                'name' => $tenant->name . ' Admin',
                'email' => 'admin@' . $tenant->domain,
                'password' => Hash::make('password'),
            ]);

            Tenant::forgetCurrent();
        });

        return response()->json([
            'message' => 'Tenant created successfully',
            'admin_user' => [
                'email' => 'admin@' . $request->domain,
                'password' => 'password'
            ]
        ]);
    }

    public function getTenantData()
    {
        $users = User::all();
        
        return response()->json([
            'tenant' => Tenant::current(),
            'users' => $users
        ]);
    }

    private function createTenantDatabase($databaseName)
    {
        DB::statement("CREATE DATABASE IF NOT EXISTS {$databaseName} 
                        CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
    }

    private function createTenantTables()
    {
        if (!Schema::hasTable('users')) {
            Schema::create('users', function ($table) {
                $table->id();
                $table->string('name');
                $table->string('email')->unique();
                $table->timestamp('email_verified_at')->nullable();
                $table->string('password');
                $table->rememberToken();
                $table->timestamps();
            });
        }
    }
}

这是一个 Laravel 多租户系统的控制器代码,用于管理租户的创建和数据查询。让我为您详细解释各个部分:‌控制器基本信息‌位于 App\Http\Controllers 命名空间继承基础的 Controller 类专门处理租户相关的业务逻辑‌核心方法功能‌createTenant 方法 - 创建新租户验证请求参数:租户名称、域名和数据库名必须唯一使用数据库事务确保数据一致性完整流程:创建租户记录 → 创建数据库 → 切换上下文 → 创建表结构 → 创建管理员用户getTenantData 方法 - 获取租户数据查询当前租户信息获取该租户的所有用户数据返回 JSON 格式的响应数据‌私有辅助方法‌createTenantDatabase - 创建租户专属数据库使用 UTF8MB4 字符集确保多语言支持创建独立的数据库实例createTenantTables - 创建租户数据表检查并创建用户表结构包含完整的用户字段定义‌多租户架构特点‌数据完全隔离:每个租户拥有独立的数据库自动化部署:自动创建数据库和表结构默认管理员:为每个租户创建默认的管理员账户上下文管理:正确的租户上下文切换和清理‌安全特性‌参数验证防止无效数据事务处理保证数据一致性密码哈希加密存储唯一性约束避免数据冲突这个控制器实现了 SaaS 系统核心的多租户管理功能,支持动态创建租户环境并确保数据的安全隔离。

路由web.php

<?php

use App\Http\Controllers\TenantController;
use Illuminate\Support\Facades\Route;

Route::post('/tenants', [TenantController::class, 'createTenant']);
Route::get('/tenant/users', [TenantController::class, 'getTenantData']);

创建租户

D:\phpstudy_pro\WWW\laravel_multitenancy666>php artisan tinker

Psy Shell v0.12.13 (PHP 8.0.2 — cli) by Justin Hileman
> App\Models\Tenant::create([
.  'name' => 'Test Com ', 'domain' => 'test-company.cal','database_name' => 'tenant_tompany']);
= App\Models\Tenant {#5206 …6}
Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐