Yii保存许多MANY_MANY关系

yqlxgs2m  于 2022-11-09  发布在  其他
关注(0)|答案(1)|浏览(131)

信息

我在保存具有许多MANY_MANY关系的模型时遇到了一些问题。我有一个页面,您可以在其中添加产品属性以及产品属性级别。我现在要做的是在产品的更新页面上添加对此的支持。因此,当我进入更新页面时,我将看到所有产品属性,并且对于每个产品属性,将出现一个下拉列表,其中包含该特定产品属性的相关产品属性级别。

数据库

产品名称

  • 标识符
  • 等等
    产品属性
  • 标识符
  • 等等
    产品属性级别
  • 标识符
  • 产品属性标识## FK
  • 等等
    产品产品属性级别-这是数据透视表
  • 产品标识## FK PK
  • 产品属性级别标识## FK主键

个有效记录

产品名称:

class Product extends S360ActiveRecord {

    public function behaviors() {
        return array('CAdvancedArBehavior' => array(
            'class' => 'application.extensions.CAdvancedArBehavior')
        );
    }

    public function rules() {
        return array(
            array('attributeLevels', 'safe'),
        );
    }

    public function relations() {
        return array(
            'attributeLevels' => array(self::MANY_MANY,
                'ProductAttributeLevel',
                'product_product_attribute_level(product_id,product_attribute_level_id)'
            ),
        );
    }

}

产品属性:

class ProductAttribute extends S360ActiveRecord {

    public function relations() {
        return array(
            'levels' => array(self::HAS_MANY, 'ProductAttributeLevel', 'product_attribute_id'),
        );
    }

}

产品属性级别:

class ProductAttributeLevel extends S360ActiveRecord {

    public function relations() {
        return array(
            'productAttribute' => array(self::BELONGS_TO, 'ProductAttribute', 'product_attribute_id'),
            'products' => array(self::MANY_MANY, 'Product', 'product_product_attribute_level(product_attribute_level_id,product_id)'),
        );
    }
}

产品产品属性级别:

class ProductProductAttributeLevel extends S360ActiveRecord {

    public function relations()
    {
        return array(
            'productAttributeLevel' => array(self::BELONGS_TO, 'ProductAttributeLevel', 'product_attribute_level_id'),
            'product' => array(self::BELONGS_TO, 'Product', 'product_id'),
        );
    }

}

更新产品的ProductController方法如下所示:

public function actionUpdate($id) {

    $model = $this->loadModel($id);
    $this->performAjaxValidation($model);

    if (isset($_POST['Product'])) {
        $model->attributes = $_POST['Product'];

        if ($model->save()) {
            $this->redirect(array('index'));
        }
    }

  $this->render('update', array('model' => $model));

}

我的表单视图中的相关部分:

<?php 
    $form=$this->beginWidget('S360ActiveForm', array(
        'id' => 'product-form',
        'enableAjaxValidation' => true,
    )); 
?>

<?php $attributes = ProductAttribute::model()->findAllByAttributes(array('survey_id' => $model->parent_id)); if ($attributes): ?>
<div class="span6">
    <?php foreach ($attributes as $attribute) {
        echo $form->dropDownListRow($model, 'attributeLevels',
            CMap::mergeArray(
                array('0' => Yii::t('backend','No attribute level')),
                CHtml::listData($attribute->levels, 'id', 'label')
            ),
            array('class' => 'span5')
        );
    }?>
</div>
<?php endif; ?>

问题

我得到这个CDBException:
CDbCommand无法执行SQL语句:数据库状态[23000]:完整性约束冲突:1452无法新增或更新子列:外键约束条件失败(product_product_attribute_level,CONSTRAINT product_product_attribute_level_ibfk_2外键(product_attribute_level_id)引用product_attribute_levelid)ON DELE)。执行的SQL语句为:插入到产品属性级别(产品标识,产品属性级别标识)值('5','0')中
问题是,虽然ID为“0”的product_attribute_level不存在,但ID从“1”开始。我如何更改它,以便它插入正确的ID编号?

我想要的例子

假设我有2个产品属性;属性1和属性2。属性1具有产品属性层Attribute1_Level1和Attribute1_Level2。属性2具有产品属性层Attribute2_Level1、Attribute2_Level2和Attribute2_Level3。
当我转到产品编辑/更新页面时,我希望看到以下内容:第一个
产品属于调查。产品属性也属于调查,因此提取产品 * 可以 * 具有的所有产品属性非常容易:

$attributes = ProductAttribute::model()->findAllByAttributes(array('survey_id' => $product->survey_id));

在此之后,我需要获取属于每个属性的所有Product Attribute Levels,这也非常简单:

foreach ($attributes as $attribute) {

    echo $form->dropDownList($attribute, 'label',
        CHtml::listData($attribute->levels, 'id', 'label'),
        $htmlOptions
    );

}

问题是如何将它与产品连接起来,并根据我从不同下拉列表中选择的内容相应地更新它的“$product-〉attributeLevels”关系。$product-〉attributeLevels应该是ProductAttributeLevel的列表,并应该通过表“product_product_attribute_level”存储。

af7jpaap

af7jpaap1#

当然,您是从下拉列表中选择的,因为如果不是这样,您实际上发送的是“0”

<?php foreach ($attributes as $attribute) {
        echo $form->dropDownListRow($model, 'attributeLevels',
            CMap::mergeArray(
                //**HERE**
                array('0' => Yii::t('backend','No attribute level')),
                CHtml::listData($attribute->levels, 'id', 'label')
            ),
            array('class' => 'span5')
        );
    }?>

如果您希望第一个选项不代表记录,则有两个选项,使用docs中dropDownList的promptempty属性:

  • prompt:string,指定显示为第一个列表选项的提示文本。其值为空。注意,提示文本将不会是HTML编码的。
  • empty:string,指定与空选择对应的文本。它的值为空。“empty”选项也可以是值标签对的数组。每一对将用于在开始处呈现列表选项。注意,文本标签将不会是HTML编码的。

现在,您需要一个attributeLevels的下拉列表,但您希望将它们保存在产品上。因此,遍历属性,获取其级别,但将它们保存在产品上,如下所示:

<?php foreach ($attributes as $i => $attribute) {
        echo $form->dropDownListRow($product, "[$i]attributeLevels",
            CHtml::listData($attribute->levels, 'id', 'label'),
            array('class' => 'span5', 'prompt' => 'No attribute level')
        );
    }?>

现在,要将它们保存在产品上,请在控制器中执行以下操作:

public function actionUpdate($id) {

  $model = $this->loadModel($id);
  $this->performAjaxValidation($model);

  if (isset($_POST['Product'])) {
    $attrLevels = $_POST['Product']['attributeLevels'];
    unset($_POST['Product']['attributeLevels']);
    $model->attributes = $_POST['Product'];

    if( $model->save() ) {
      $valid=true;
      foreach($attrLevels as $i=>$attrLevel)
      {
        $pivot = new ProductProductAttributeLevel;
        $pivot->product_id = $model->id;
        $pivot->product_attribute_level_id = $attrLevel;
        $valid=$item->save() && $valid;
      }
      if($valid){
        $this->redirect(array('index'));
      }
    }
  }

  $this->render('update', array('model' => $model));

}
  • 免责声明:复制/粘贴可能不起作用,但您可以理解 *

相关问题