拉拉维尔雄辩ORM中的多租户关系


Relationships in multi tenancy in Laravel Eloquent ORM

再一次,这是一个后续问题:

拉维尔雄辩ORM的多租户

这一次,我有关于在多租户环境中使用关系来制作雄辩模型的问题。

给定产品型号:

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

这是确保关系方法 accessories() 使用正确的数据库连接的简单方法吗?现在,当我执行这样的附加方法时:

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

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

如果你看到我对你关于模型事件和观察者的原始问题的回答,这本质上也应该解决这个问题: 拉拉维尔的多租户 雄辩的ORM

所有雄辩的关系方法:附加、关联等...都触发了相应的模型事件,详见下文: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

希望这有帮助

使用

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();
}

前提是附件类还扩展了基本模型。这样,您可以在运行时随意更改数据库连接。