globecode/laravel-multitenant

Laravel 多租户

v0.2.0 2015-02-02 01:17 UTC

This package is not auto-updated.

Last update: 2024-09-24 03:08:08 UTC


README

2014年9月29日:作为L4包发布的WIP。

安装

  1. 在您的 composer.json 文件中的 "require" 块中要求此包。

    "globecode/laravel-multitenant": "dev-master"
  2. 将服务提供者添加到 app/config/app.php 文件中的 providers 数组。这仅用于下面两步中的 "发布 config" 命令

    'GlobeCode\LaravelMultiTenant\LaravelMultiTenantServiceProvider'
  3. 进入您的项目目录,并通过 Composer 进行更新

    composer update
  4. config 发布到您的应用程序中。这允许您更改您模式中 租户 列的名称。一个 config 文件将被安装到 app/config/packages/globecode/laravel-multitenant/,您可以编辑它

    php artisan config:publish globecode/laravel-multitenant
  5. 创建并运行新的 migrations 以设置必要的模式。示例迁移在包 migrations 文件夹中提供。

  6. getTenantId() 方法添加到您的 User(以及任何其他 "受限" 模型)或只添加到一次 BaseModel(推荐)

    /**
     * Get the value to scope the "tenant id" with.
     *
     * @return string
     */
    public function getTenantId()
    {
        return (isset($this->tenant_id)) ? $this->tenant_id : null;
    }
  7. 可选的 全局覆盖。如果您想全局覆盖范围,例如对 管理员,则将 isAdmin() 方法添加到您的 User 模型中。如果此方法返回 true,则 ScopedByTenant 特性将查找此方法并自动覆盖所有查询的范围

    /**
     * Does the current user have an 'admin' role?
     *
     * @return bool
     */
    public function isAdmin()
    {
        // Change to return true using whatever
        // roles/permissions you use in your app.
        return $this->hasRole('admin');
    }

用法

  1. 使用 ScopedByTenant 特性对模型进行范围限定,使该模型上的所有查询全局限定于一个租户。永远不用担心意外查询到租户数据之外的数据!

    <?php namespace Acme;
    
    use GlobeCode\LaravelMultiTenant\ScopedByTenant;
    
    class Example {
    
        /**
         * Only this line is required. The extra below is just
         * for example on what a relation might look like.
         */
        use ScopedByTenant;
    
        protected $table = 'example';
    
        /**
         * Query the Tenant the Example belongs to.
         *
         * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
         */
        public function tenant()
        {
            return $this->belongsTo('Acme\Tenant');
        }
    }
  2. 全局移除范围

    A:全局 移除控制器(例如在 管理员 情况下)的范围

    <?php
    
    use GlobeCode\LaravelMultiTenant\ScopedByTenant;
    
    class AdminExamplesController {
    
        /**
         * @var Acme\Repositories\ExampleRepository
         */
        protected $exampleRepo;
    
        public function __construct(ExampleRepository $exampleRepo)
        {
            $this->exampleRepo = $exampleRepo;
    
            // All queries in this controller on 'exampleRepo'
            // will be 'global' and not scoped.
            $this->exampleRepo->removeTenant();
        }
    
        /**
         * Display a listing of all Examples.
         *
         * @return Response
         */
        public function index()
        {
            // Global, will *not* be scoped.
            $leads = $this->exampleRepo->getAll();
    
            $this->view('examples.index', compact('examples'));
        }
    }

    或者

    B:通过在 ScopedByTenant 特性的 bootTenantId() 方法中使用 Auth 检查来全局 移除 范围。请参阅上面 设置 -> 可选全局覆盖 部分的说明。

注意:您可以在模型和控制器中使用 ScopedByTenant 特性的任何 public 方法。

存储库

如果您使用存储库,则需要使用 TenantScope 类而不是 ScopedByTenant 特性来构建查询。如果您查看 TenantScope 类,您会看到有对 \Illuminate\Database\Query\Builder 的扩展,这些是您的存储库可用的方法;特性在存储库中不起作用。

以下是一个包含所有必要方法的示例 Eloquent 存储库。这些方法应放在一个 EloquentBaseRepository 类中,以保持代码的DRY。

<?php namespace Acme\Repositories;

use Illuminate\Database\Eloquent\Model;

use Acme\Example;
use Acme\Repositories\ExampleRepository

class EloquentExampleRepository extends ExampleRepository {

    /**
     * @var Example
     */
    protected $model;

    /**
     * Method extensions from TenantScope class
     */
    protected $whereTenant;
    protected $applyTenant;
    protected $removeTenant;

    public function __construct(Example $model)
    {
        $this->model = $model;

        $this->whereTenant = null;
        $this->applyTenant = null;
        $this->removeTenant = false;
    }

    /**
     * Example get all using scope.
     */
    public function getAll()
    {
        return $this->getQueryBuilder()->get();
    }

    /**
     * Example get by id using scope.
     */
    public function getById($id)
    {
        return $this->getQueryBuilder()->find((int) $id);
    }

    /**
     * Limit scope to specific Tenant
     * Local method on repo, not on TenantScope.
     *
     * @param  integer  $id
     */
    public function whereTenant($id)
    {
        $this->whereTenant = $id;

        return $this;
    }

    /**
     * Remove Tenant scope.
     */
    public function removeTenant()
    {
        $this->removeTenant = true;

        return $this;
    }

    /**
     * Limit scope to specific Tenant(s)
     *
     * @param  int|array $arg
     */
    public function applyTenant($arg)
    {
        $this->applyTenant = $arg;

        return $this;
    }

    /**
     * Expand scope to all Tenants.
     */
    public function allTenants()
    {
        return $this->removeTenant();
    }

    protected function getQualifiedTenantColumn()
    {
        $tenantColumn = Config::get('laravel-multitenant::tenant_column');

        return $this->model->getTable() .'.'. $tenantColumn;
    }

    /**
     * Returns a Builder instance for use in constructing
     * a query, honoring the current filters. Resets the
     * filters, ready for the next query.
     *
     * Example usage:
     * $result = $this->getQueryBuilder()->find($id);
     *
     * @return \Illuminate\Database\Query\Builder
     */
    protected function getQueryBuilder()
    {
        $modelClass = $this->model;

        $builder = with(new $modelClass)->newQuery();

        if ( ! is_null($this->whereTenant))
            $builder->where($this->getQualifiedTenantColumn(), $this->whereTenant);

        if ($this->applyTenant)
            $builder->applyTenant($this->applyTenant);

        if ($this->removeTenant)
            $builder->removeTenant();

        $this->whereTenant = null;
        $this->applyTenant = null;
        $this->removeTenant = null;

        return $builder;
    }
}

播种

您可以在播种文件中手动覆盖范围,以避免难以查找关系,通过手动设置 覆盖

<?php

use Acme\User;

use GlobeCode\LaravelMultiTenant\TenantScope;

class UsersTableSeeder extends DatabaseSeeder {

    public function run()
    {
        // Manually override tenant scoping.
        TenantScope::setOverride();

        User::create([
            'id' => 1,
            'tenant_id' => null, // an admin
            'email' => 'admin@us.com',
            'password' => 'secret',

            'created_at' => time(),
            'updated_at' => time()
        ]);

        User::create([
            'id' => 2,
            'tenant_id' => 1000, // a tenant
            'email' => 'user@tenant.com',
            'password' => 'secret',

            'created_at' => time(),
            'updated_at' => time()
        ]);

        ...
    }
}

注意:将 tenant_id 字段(或您选择的任何范围列名称)设置为 null 以避免任何内部人员/管理员。

关于

概念:从 AuraEQ Laravel Multi Tenant 中硬分叉。非常感谢他的初始工作。

Packagist: globecode/laravel-multitenant

标签: #laravel-multitenant

推特: @jhaurawachsman

版权(c)2014 Jhaura Wachsman

在MIT许可下。