Laravel Eloquent ORM中多租户的关系

时间:2015-03-16 10:33:11

标签: php database laravel eloquent relationship

这又是一个跟进问题:

Multi tenancy in Laravel Eloquent 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实体不同的另一个数据库。我相信这是因为在实例化关系时,Accessory模型连接不会更改。

2 个答案:

答案 0 :(得分:2)

如果您看到我对模型事件&amp ;;的原始问题的答案观察者,这应该固有地解决这个问题:Multi tenancy in Laravel Eloquent ORM

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

如果你设置一个模型观察者来操纵使用中的连接pre&保存特定模型后,所有关系调用都将自动适当地设置数据库连接。

希望这有帮助

- 编辑以回应评论

嗨yulun,

抱歉,我把你的配件误认为是员工。 (挽救关系)

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

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

希望这有帮助

答案 1 :(得分:0)

使用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。这样,您可以在运行时随意更改数据库连接。