【问题标题】:Yii2: Populating model field with value from many-to-many relationYii2:用多对多关系的值填充模型字段
【发布时间】:2018-02-07 21:46:26
【问题描述】:

我们正在尝试以用户只能检索与其帐户相关的数据的方式设置我们的 REST API。到现在为止,我们只有一个公共 API,它的工作就像一个魅力。 公共 API 仍然会被使用,所以我们从头开始。

我们有一个User 模型,扩展了ActiveRecord 并实现了IdentityInterface。用户将与Customer 模型有关系(Many:Many,但至少有一个)。用户将拥有only one MASTER 客户。 以上使用 3 个表 app_customer_usersapp_customerslink_customer_users_customers 保存在数据库中。连接表包含一个布尔字段master

在用户模型中:

public function getCustomers() {
    return $this->hasMany(Customer::className(), ['id' => 'customer_id'])
        ->viaTable('link_customer_users_customers', ['user_id' => 'id']);
}

在客户模型中:

public function getUsers() {
    return $this->hasMany(User::className(), ['id' => 'user_id'])
        ->viaTable('link_customer_users_customers', ['customer_id' => 'id']);
}

如果我们请求所有客户,这将非常有用,他们将填充“用户”(如果我们将其添加到 extraFields 等...)

新的API使用Basic user:pass进行身份验证,我们可以通过调用Yii::$app->user->getIdentity()获取当前用户对象/身份。

现在的问题

我们希望能够在用户连接时包含客户 ID,我们可以通过调用 Yii::$app->user->getIdentity()->customer_idYii::$app->user->getIdentity()->getCustomerId() 来获取客户 ID。客户 ID 应该是连接表中 master 所在的 ID == true.

我们尝试将它添加到 fields,就像我们之前对 hasOne 关系所做的那样,但在这种情况下它似乎不起作用:

$fields['customer_id'] = function($model) {
    return $model->getCustomers()->where('link_customer_users_customers.master', true)->one()->customer_id;
}; // probably the where part is our porblem?

我们已经尝试过创建这样的自定义 getter:

public function getCustomerId() {
    return $this->getCustomers()->andFilterWhere(['link_customer_users_customers.master' => true])->one()->customer_id;
}

最后一次尝试导致错误

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'link_customer_users_customers.master' in 'where clause'\nThe SQL being executed was: SELECT * FROM `app_customers` WHERE (`link_customer_users_customers`.`master`=TRUE) AND (`id`='93')

我们一直在文档和 Google 上进行搜索,但没有找到有关如何执行此操作的示例。

解决方案

根据接受的答案,我们添加了一些代码。

User 模型中:

// Include customer always with user
public static function findIdentity($id) {
    return static::findOne($id)->with('customer');
}

// Next to `getCustomers()`, added this `hasOne` relation to get only the customer from
// which the current user is the master user
public function getCustomer() {
    return $this->hasOne(Customer::className(), ['id' => 'customer_id'])
        ->viaTable('link_customer_users_customers', ['user_id' => 'id'], function ($query) {
            $query->andWhere(['master' => 1]);
        });
}

// Getter, just because
public function getCustomerId() {
    return $this->customer->id;
}

现在我们可以通过在项目中调用Yii::$app->user->getIdentity()->customer->idYii::$app->user->identity->customer->id等来获取客户的ID..

【问题讨论】:

  • 我想了解的是,用户本身也可以是客户?
  • 一个客户至少有一个主用户。主用户是用来连接API的用户。但是(我们客户的)其他员工可能有用户。一个用户可以链接到多个客户帐户。但一位用户只能是一个客户帐户的主用户。因此,如果主用户在 API 上登录,我们想知道我们需要为哪个客户帐户选择数据。
  • 您能否将以下关系 public function getMasterCustomerId() { return $this->hasOne(Customer::className(), ['id' => 'customer_id']) ->viaTable('link_customer_users_customers', ['user_id' => 'id']); ->andOnCondition(['=','{{%link_customer_users_customers}}.master',true]); } 添加到 User 模型并尝试使用 Yii::$app->user->identity->masterCustomerId,如果我理解正确,master 字段位于 link_customer_users_customers 中。
  • 是的,您可以将该条件移到 viaTable 中,作为另一个更好、更正确的方法,我添加了一个额外的 andOnCondition()
  • 检查我更新的问题:)

标签: rest yii2 many-to-many


【解决方案1】:

您应该添加如下所示的关系并使用anonymous 函数作为viaTable 的第三个参数来添加另一个条件以检查master 字段是否为真。

public function getMasterCustomerId() {
    return $this->hasOne(Customer::className(), ['id' => 'customer_id'])
    ->viaTable('link_customer_users_customers', ['user_id' => 'id'],function($query){
       $query->andWhere(['master' => 1]);
   });
}

然后您可以将其用于登录用户,如下所示。

Yii::$app->user->identity->masterCustomerId->id;

【讨论】:

  • 你是我们今天的英雄! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-10
  • 1970-01-01
  • 2018-10-08
  • 1970-01-01
  • 2020-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多