【问题标题】:Relationships in multi tenancy in Laravel Eloquent ORMLaravel Eloquent ORM 中的多租户关系
【发布时间】:2015-03-16 10:33:10
【问题描述】:

这又是一个后续问题:

Multi tenancy in Laravel Eloquent ORM

这一次,我对在多租户环境中为 eloquent 模型使用关系存有疑问。

给定一个产品模型:

class Product extends Eloquent {

public function accessories()
{
    return $this->belongsToMany('Accessory', 'product_accessory', 'product_id', 'accessory_id')
                ->withPivot('id')
                ->withTimestamps();
}

是否有任何简单的方法可以确保关系方法附件()使用正确的数据库连接?现在,当我执行这样的附加方法时:

$product->accessories()->attach($accessory->id, $attributes);

accessories 方法似乎指向与 $product 实体不同的另一个数据库。我相信这是因为在实例化关系时附件模型连接不会改变。

【问题讨论】:

    标签: php database laravel eloquent relationship


    【解决方案1】:

    如果您看到我对关于模型事件和观察者的原始问题的回答,这也应该从本质上解决这个问题:Multi tenancy in Laravel Eloquent ORM

    所有 Eloquent 关系方法:附加、关联等...都触发相应的模型事件,详见此处:http://laravel.com/docs/5.0/eloquent#model-events

    如果您设置一个模型观察器来操作在保存特定模型之前和之后使用的连接,那么您的所有关系调用都会自动正确设置数据库连接。

    希望对你有帮助

    -- 根据评论进行编辑

    你好,玉伦,

    抱歉,我把你的配件电话误认为是助理。 (保存关系)

    但是,在定义了您的关系时,您应该能够获得类似的结果。见下例:

    class ProductModel extends Eloquent {
    
        protected $table = 'products';
    
        protected $connection;
    
        protected $databases = [
            'default' => 'mysql-key1',
            'products' => 'mysql-key2'
        ];
    
        public function __construct(Connection $connection)
        {
            $this->connection = $connection;
        }
    
        public function accessories()
        {
            $this->connection->reconnect($this->databases['products']);
            $accessories = $this->hasMany('AccessoriesModel');
            $this->connection->reconnect($this->databases['default']);
    
            return $accessories;
        }
    }
    

    然后您可以通过创建一个所有受影响的模型都可以扩展的抽象类来更进一步,例如:

    abstract class DatabaseModel extends Eloquent {
    
         protected $connection;
    
         protected $databases = [
             'default' => 'mysql-key1',
             'products' => 'mysql-key2'
         ];
    
         public function __construct(Connection $connection)
         {
             $this->connection = $connection;
         }
    
        protected function setProductsDatabase()
        {
            $this->connection->reconnect($this->databases['products']);
        }
    
        protected function resetDatabaseConnection()
        {
            $this->connection->reconnect($this->databases['default']);
        }
    }
    
    class ProductModel extends DatabaseModel {
    
        protected $table = 'products';
    
        public function accessories()
        {
            $this->setProductsDatabase();
            $accessories = $this->hasMany('AccessoriesModel');
            $this->resetDatabaseConnection();
    
            return $accessories;
        }
    }
    

    这样,只要您的关系配置正确,一切都会“自然”地运行,无需任何额外的代码。

    一个更简洁但更复杂的解决方案是,您可以触发您自己的“检索”事件,而不是在模型中操作数据库,然后您可以为您的自定义“检索”事件添加一个事件处理程序到模型观察器 -这将是我的偏好,您可以在此处找到有关如何操作的更多信息:http://laravel.io/forum/05-24-2014-how-could-i-create-custom-model-events?page=1

    希望对你有帮助

    【讨论】:

    • 在我的用例中,我认为在调用 $product->accessories() 之前不会有任何模型事件。我没有保存产品,所以查看事件,我认为不会触发重新连接,因为我基本上是在做一个 get()。
    • 编辑答案以反映评论
    【解决方案2】:

    使用 Beevee 的回答中的提示,我们还可以将 Eloquent 类扩展为基本模型,以使用基于会话或基于配置的连接,例如

    class BaseModel extends Eloquent {
    
    public function __construct(array $attributes = array())
    {
        parent::__construct($attributes);
    
        $this->setConnection(\DB::getDefaultConnection());
    }
    

    }

    这样,所有的关系方法都将自动实例化以使用连接。

    class Product extends BaseModel {
    
    public function accessories()
    {
      return $this->belongsToMany('Accessory', 'product_accessory', 'product_id', 'accessory_id')
                ->withPivot('id')
                ->withTimestamps();
    }
    

    如果 Accessory 类也扩展了 BaseModel。这样,你可以在运行时随意更改数据库连接。

    【讨论】:

      猜你喜欢
      • 2015-05-18
      • 1970-01-01
      • 2015-04-16
      • 2015-01-21
      • 1970-01-01
      • 1970-01-01
      • 2015-04-04
      • 1970-01-01
      • 2020-03-25
      相关资源
      最近更新 更多