【问题标题】:Yii2 Relations to get a field using two foreign keysYii2关系使用两个外键获取字段
【发布时间】:2016-08-09 02:27:15
【问题描述】:

我在使用两个外键从表中获取字段时遇到问题。

解释下面使用表的关系。

  • 用户表 hasMany Companies(company_id)。
  • 公司表有 company_id。
  • 设施hasOne Company_id(基于用户实例)。
  • 区域 hasMany 设施(facility_id)。

登录用户将拥有与 facility_id 相关的区域,而该区域又与 company_id 相关。

我现在有一个

  • 产品线 hasMany 产品(product_id)。

用户应该展示与区域相关的产品。

  • 产品线 hasMany 区域(area_id)。
  • 产品线有一个名为 internal_code 的字段。

产品型号与产品线的关系是基于products_id。

我想根据属于特定区域的product_id显示这个内部代码。

到目前为止,我的代码不起作用:

在我的产品模型中。

    public function getFacility()
{
    return $this->hasMany(Facility::className(),['facility_id' => 'facility_id'])->viaTable('sim_users',['company_id'=> Yii::$app->user->identity->company_id]);
}

 public function getArea()
{

    return $this->hasMany(Area::className(),['area_id'=>'area_id'])->viaTable('sim_facility',['facility_id'=> 'facility_id' ]);
}

public function getProductlines()
{

    return $this->hasMany(Productlines::className(), ['product_id' => 'product_id'])->viaTable('sim_productlines',['product_id' => 'product_id']);
}

在我的视图文件中:

  [
        'label' => 'Internal Code',
        'format' => 'raw',

        'value' => function ($data) {
            foreach ($data->productlines as $intCode)
           return $intCode->internal_code;
        } 

我不明白如何链接这些关系。寻求帮助。谢谢

表格列表:

  • 用户(primaryKey - users_id, foreign_key- comapny_id)
  • 公司(primaryKey - company_id)
  • Facility(primaryKey - facility_id, foreignKey- company_id)
  • 区域(primaryKey - area_id, foreignKey- facility_id)
  • Productlines(primaryKey - productlines_id, foreignKey - product_id 和 area_id)
  • 产品(primaryKey - product_id)。

我的预期结果:

在上表中您可以看到 area_id 47 有两个 product_id(1 和 3)。并且它们的内部代码是不同的。我希望他们返回两个内部代码,目前我只能得到一个内部代码。

【问题讨论】:

  • 不清楚您有哪些实体以及它们如何链接。您能否提供带有主键和外键的完整表列表(仅名称就足够了)?并显示一个预期结果的例子
  • @MaximKorshunov 我已经添加了表名和关系..

标签: yii2 yii2-model


【解决方案1】:

所以你有以下层次结构

  • 公司有很多用户
  • 公司有很多设施
  • 设施有很多区域
  • 区域 hasMany 产品线
  • 产品 hasMany 产品线

产品以 ma​​nyToMany via productLines 关系链接到区域

您可以为您的 AR 类使用以下代码(但您应该修改名称,因为我对类和表名使用了单数形式):

public class User extends ActiveRecord
{
    public function getCompany()
    {  
        retrun $this->hasOne(Company::className(), ['company_id' => 'company_id']);
    }
}

public class Company extends ActiveRecord
{
    public function getUsers()
    {  
        retrun $this->hasMany(User::className(), ['company_id' => 'company_id']);
    }    

    public function getFacilities()
    {  
        retrun $this->hasMany(Facility::className(), ['company_id' => 'company_id']);
    }    
}

public class Facility extends ActiveRecord
{
    public function getCompany()
    {  
        retrun $this->hasOne(Company::className(), ['company_id' => 'company_id']);
    }

    public function getAreas()
    {  
        retrun $this->hasMany(Area::className(), ['facility_id' => 'facility_id']);
    }    
}

public class Area extends ActiveRecord
{
    public function getFacility()
    {  
        retrun $this->hasOne(Facility::className(), ['facility_id' => 'facility_id']);
    }

    public function getProductLines()
    {  
        retrun $this->hasMany(ProductLine::className(), ['area_id' => 'area_id']);
    }    

    public function getProducts()
    {  
        retrun $this->hasMany(Product::className(), ['product_id' => 'product_id'])
            ->via('productLines');
    }    
}

/**
 * @property $internal_code
 */
public class ProductLine extends ActiveRecord
{
    public function getArea()
    {  
        retrun $this->hasOne(Area::className(), ['area_id' => 'area_id']);
    }

    public function getProducts()
    {  
        retrun $this->hasMany(Product::className(), ['product_id' => 'product_id']);
    }
}

public class Product extends ActiveRecord
{
    public function getProductLines()
    {  
        retrun $this->hasMany(ProductLine::className(), ['product_id' => 'product_id']);
    }       

    public function getAreas()
    {  
        retrun $this->hasMany(Area::className(), ['area_id' => 'area_id'])
            ->via('productLines');
    }    

    public function getFacilites()
    {  
        retrun $this->hasMany(Facility::className(), ['facility_id' => 'facility_id'])
            ->via('areas');
    }
}

获取给定产品的所有内部代码:

$productLines = $product->productLines;

$internalCodesAsArray = array_map(function(ProductLine $productLine) {
    return $productLine->internal_code;
}, $productLines);

$internalCodesAsString = join(', ', $internalCodesAsArray);

获取给定区域的所有内部代码:

$productLines = $product->productLines;

$internalCodesAsArray = array_map(function(ProductLine $productLine) {
    return $productLine->internal_code;
}, $productLines);

$internalCodesAsString = join(', ', $internalCodesAsArray);

如果您想列出给定区域的产品,也一样——使用$area->products 关系。如果您想获取给定区域的产品数量,请致电$area->getProducts()->count();

获取特定区域产品的内部代码在产品类中添加以下函数:

public function getInternalCodes(Area $area = null)
{
    $query = $this->getProductLines();
    if (!empty($area)) {
        $query->where(['area_id' => $area->area_id]);
    }
    return array_map(function (ProductLine $productLine) {
        return $productLine->internal_code;
    }, $query->all());
}

并在你的控制器中使用它作为$currentProduct->getInternalCodes($currentArea)

不要将自定义过滤器添加到定义关系的函数中。如果您想获取给定产品的设施列表并按当前用户的公司过滤它们,那么最好将其作为附加功能实现:

public class Product 
{
    ...

    public function getFacilitiesByCompany(Company $company)
    {
        return $product->getFacilities()
            ->where(['company_id' => $company->company_id]);
    }
}

按如下方式使用

$product->getFacilitiesByCompany(Yii::$app->user->identity->company)->all();

希望这会有所帮助。

【讨论】:

  • @MohanPrasad 那么我可能没有得到你的问题。
  • 你所有的关系都完好无损。它只是获取内部代码的视图页面代码。我有不同的区域。基于这些区域,我在我的产品页面中获得了产品。不同的地区可以有相同的产品。在这里,相同的产品具有不同的内部代码。我想根据区域显示正确的内部代码。
  • @MohanPrasad 我明白了。答案更新:添加了获取指定区域产品内部代码的示例函数
猜你喜欢
  • 1970-01-01
  • 2018-02-24
  • 1970-01-01
  • 2015-11-11
  • 1970-01-01
  • 1970-01-01
  • 2020-12-23
  • 1970-01-01
  • 2019-10-26
相关资源
最近更新 更多