[英]Yii saving many MANY_MANY relationships
保存具有许多MANY_MANY关系的模型时遇到一些问题。 我有一个页面,您可以在其中添加产品属性以及产品属性级别。 我现在想做的是在产品的更新页面上添加对此的支持。 因此,当我进入更新页面时,我将看到所有产品属性,对于每个产品属性,将有一个下拉列表,其中包含该特定产品属性的相关产品属性级别。
产品
产品属性
ProductAttributeLevel
ProductProductAttributeLevel-这是数据透视表
产品:
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'),
);
}
}
ProductAttributeLevel:
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)'),
);
}
}
ProductProductAttributeLevel:
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语句:SQLSTATE [23000]:完整性约束违规:1452不能添加或更新子行,外键约束失败(
product_product_attribute_level
,约束product_product_attribute_level_ibfk_2
外键(product_attribute_level_id
)参考product_attribute_level
(id
)ON DELE)。 执行的SQL语句是:插入到product_product_attribute_level(product_id,product_attribute_level_id)值('5','0')
问题是,虽然ID为“ 0”的product_attribute_level不存在,但ID的开头为“ 1”。 我将如何更改它以便插入正确的ID号?
假设我有2个产品属性; 属性1和属性2。 Attribute1具有产品属性级别Attribute1_Level1和Attribute1_Level2。 Attribute2具有产品属性级别Attribute2_Level1,Attribute2_Level2和Attribute2_Level3。
当我转到“产品”编辑//更新页面时,我想看到以下内容: 属性http://img201.imageshack.us/img201/9252/screenshot20130207at103.png Attribute2下拉菜单http://img405.imageshack.us/img405/9252/screenshot20130207at103.png
该产品属于调查。 产品属性也属于调查,因此获取产品可以具有的所有产品属性很容易:
$attributes = ProductAttribute::model()->findAllByAttributes(array('survey_id' => $product->survey_id));
之后,我需要获取属于每个属性的所有产品属性级别,这也很容易:
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”存储。
当然,您是从下拉菜单中选择的? 因为如果没有,您确实发送的是“ 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的prompt
或dropDownList的empty
属性:
提示:字符串,指定显示为第一个列表选项的提示文本。 其值为空。 请注意,提示文字将不会进行HTML编码。
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));
}
免责声明:复制/粘贴可能无效,但您明白了
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.