基于关系的CGridView列显示不正确的数据

时间:2015-12-10 09:52:49

标签: php yii gridview-sorting

我目前正在开发一个Web应用程序(用PHP编写,基于Yii),除其他外,它允许您连接产品的不同价格值。每个产品可以有多个价格,但系统的构建方式我可以轻松(并且正确)确定价格字段的类型 - 因此,虽然每个产品可以有多个价格字段,但它只能有一种类型的价格领域。

我卡住的部分是当我必须在列表中显示这些字段的存储值,并按顺序排列列表视图时 - 我可以正确显示它们并按一列排序,但是一旦我尝试要使列表可以被所有列排序(当然不是在同一时间),行开始显示错误的值。

以下是相关的代码:

在模型中,关系:

'productPriceConnects' => array(Product::HAS_MANY, 'ProductPriceConnect', 'product_id'),
'price1' => array(Product::HAS_ONE, 'ProductPriceConnect', 'product_id',
    'joinType' => 'LEFT JOIN',
    'on' => 'priceBeszerzesi.product_price_field_id=:product_price_field_id AND priceBeszerzesi.active = 1',
    'params' => array(':product_price_field_id' =>ProductPriceField::model()->findByAttributes(array('active' => 1, 'type' => 1, 'category' => 6))->id),
    'alias' => 'priceBeszerzesi',
),
'price2' => array(Product::HAS_ONE, 'ProductPriceConnect', 'product_id',
    'joinType' => 'LEFT JOIN',
    'on' => 'priceEladasi.product_price_field_id=:product_price_field_id AND priceEladasi.active = 1',
    'params' => array(':product_price_field_id' => ProductPriceField::model()->findByAttributes(array('active' => 1, 'type' => 1, 'category' => 1))->id),
    'alias' => 'priceEladasi'
),
'price3' => array(Product::HAS_ONE, 'ProductPriceConnect', 'product_id',
    'joinType' => 'LEFT JOIN',
    'on' => 'priceAkcios.product_price_field_id=:product_price_field_id AND priceAkcios.active = 1',
    'params' => array(':product_price_field_id' => ProductPriceField::model()->findByAttributes(array('active' => 1, 'type' => 1, 'category' => 5))->id),
    'alias' => 'priceAkcios'
),

在模型中,搜索:

...
$criteria->with('price1', 'price2', 'price3);

...

$criteria->compare('price1.price', $this->beszerzesi, true);
$criteria->compare('price2.price', $this->eladasi, true);
$criteria->compare('price3.price', $this->akcios, true);

...
$sort->attributes = array(
    'price1' =>array(
        'asc' => 'priceBeszerzesi.price ASC',
        'desc' => 'priceBeszerzesi.price DESC',
    ),
    'price2' =>array(
        'asc' => 'priceEladasi.price ASC',
        'desc' => 'priceEladasi.price DESC',
    ),
    'priceAkcios' =>array(
        'asc' => 'price3.price ASC',
        'desc' => 'price3.price DESC',
    ),
    '*'
);

...

return new CActiveDataProvider($this, array(
        'criteria' => $criteria,
        'sort' => $sort,
        'pagination' => array(
            'pageSize' => 10,
        ),
    )
);

gridview中列的数据:

'eladasi' => array(
    'name' => 'price2',
    'header' => 'Eladási ár',
    'type' => 'raw',
    'headerHtmlOptions' => array('class' => 'auto-width text-center'),
    'value' => '!empty($data->price2->price) ? $data->price2->price == "" ? "-" : $data->price2->price : "-"',
    'htmlOptions' => array('class' => 'border-right auto-width text-center'),
),
'akcios' => array(
    'name' => 'priceAkcios',
    'header' => 'Akciós',
    'value' => '!empty($data->price3->price) ? $data->price3->price == "" ? "-" : $data->price3->price : "-"',
    'headerHtmlOptions' => array('class' => 'auto-width text-center'),
    'htmlOptions' => array('class' => 'border-right auto-width text-center'),
),
    'beszerzesi' => array(
    'name' => 'price1',
    'header' => 'Beszerzési ár',
    'type' => 'raw',
    'value' => '!empty($data->price1->price) ? $data->price1->price == "" ? "-" : $data->price1->price : "-"',
    'headerHtmlOptions' => array('class' => 'auto-width text-center'),
    'htmlOptions' => array('class' => 'border-right auto-width text-center'),
),

此代码可以通过所有三个与关系相关的列对列表进行排序,但每列显示相同的值 - with数组中最后一个关系的值。如果数组中的最后一个元素是price3,则列显示price3关系的值。 当我从with数组中删除所有关系名称时,我可以按该列排序,而不是其他列。

我的问题是: 有什么办法吗? 1)确实向模型添加任意数量的关系,连接到同一个db字段,但根据条件, 2)并显示这些值,同时根据它们进行排序?

1 个答案:

答案 0 :(得分:2)

查找以下解决方案:

我在我的系统中创建了这些表,并使用了您的关系和gridview代码。我对该代码进行了一些更改,现在在下面的代码中,搜索和排序工作正常。

我在模型类中定义了三个变量,即

public $beszerzesi;
public $eladasi;
public $akcios;

然后我改变了与左连接一起使用的关系数组中的参数名称。这是代码中的主要问题。您为参数使用相同的名称,即:product_price_field_id我为每个参数指定了不同的名称。当yii准备sql查询时,它将替换分配给查询的参数。在您的情况下,它替换了所有三个参数的相同值。

我还对CActiveDataProvider中传递的排序和比较属性进行了一些更改。您可以在下面的模型文件中找到所有更改。

<强> Product.php

<?php

/**
 * This is the model class for table "product".
 *
 * The followings are the available columns in table 'product':
 * @property integer $id
 * @property string $name
 */
class Product extends CActiveRecord
{
    public $beszerzesi;
    public $eladasi;
    public $akcios;

    /**
     * @return string the associated database table name
     */
    public function tableName()
    {
        return 'product';
    }

    /**
     * @return array validation rules for model attributes.
     */
    public function rules()
    {
        // NOTE: you should only define rules for those attributes that
        // will receive user inputs.
        return array(
            array('name', 'required'),
            array('name', 'length', 'max' => 100),
            // The following rule is used by search().
            // @todo Please remove those attributes that should not be searched.
            array('id, name, beszerzesi, eladasi,akcios', 'safe', 'on' => 'search'),
        );
    }

    /**
     * @return array relational rules.
     */
    public function relations()
    {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array(
            'productPriceConnects' => array(Product::HAS_MANY, 'ProductPriceConnect', 'product_id'),
            'price1' => array(Product::HAS_ONE, 'ProductPriceConnect', 'product_id',
                'joinType' => 'LEFT JOIN',
                'on' => 'priceBeszerzesi.product_price_field_id=:product_price_field_id1 AND priceBeszerzesi.active = 1',
                'params' => array(':product_price_field_id1' => ProductPriceField::model()->findByAttributes(array('active' => 1, 'type' => 1, 'category' => 6))->id),
                'alias' => 'priceBeszerzesi',
            ),
            'price2' => array(Product::HAS_ONE, 'ProductPriceConnect', 'product_id',
                'joinType' => 'LEFT JOIN',
                'on' => 'priceEladasi.product_price_field_id=:product_price_field_id2 AND priceEladasi.active = 1',
                'params' => array(':product_price_field_id2' => ProductPriceField::model()->findByAttributes(array('active' => 1, 'type' => 1, 'category' => 1))->id),
                'alias' => 'priceEladasi'
            ),
            'price3' => array(Product::HAS_ONE, 'ProductPriceConnect', 'product_id',
                'joinType' => 'LEFT JOIN',
                'on' => 'priceAkcios.product_price_field_id=:product_price_field_id3 AND priceAkcios.active = 1',
                'params' => array(':product_price_field_id3' => ProductPriceField::model()->findByAttributes(array('active' => 1, 'type' => 1, 'category' => 5))->id),
                'alias' => 'priceAkcios'
            ),
        );
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels()
    {
        return array(
            'id' => 'ID',
            'name' => 'Name',
        );
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     *
     * Typical usecase:
     * - Initialize the model fields with values from filter form.
     * - Execute this method to get CActiveDataProvider instance which will filter
     * models according to data in model fields.
     * - Pass data provider to CGridView, CListView or any similar widget.
     *
     * @return CActiveDataProvider the data provider that can return the models
     * based on the search/filter conditions.
     */
    public function search()
    {
        // @todo Please modify the following code to remove attributes that should not be searched.

        $criteria = new CDbCriteria;

        $criteria->with = array('price1', 'price2', 'price3');

        $criteria->compare('id', $this->id);
        $criteria->compare('name', $this->name, true);

        $criteria->compare('priceBeszerzesi.price', $this->beszerzesi, true);
        $criteria->compare('priceEladasi.price', $this->eladasi, true);
        $criteria->compare('priceAkcios.price', $this->akcios, true);

//        $criteria->attributes = ;

        return new CActiveDataProvider($this, array(
                'criteria' => $criteria,
                'sort' => array(
                    'attributes' => array(
                        'beszerzesi' => array(
                            'asc' => 'priceBeszerzesi.price',
                            'desc' => 'priceBeszerzesi.price DESC',
                        ),
                        'eladasi' => array(
                            'asc' => 'priceEladasi.price',
                            'desc' => 'priceEladasi.price DESC',
                        ),
                        'akcios' => array(
                            'asc' => 'priceAkcios.price',
                            'desc' => 'priceAkcios.price DESC',
                        ),
                        '*'
                    )
                ),
                'pagination' => array(
                    'pageSize' => 10,
                ),
            )
        );
    }

    /**
     * Returns the static model of the specified AR class.
     * Please note that you should have this exact method in all your CActiveRecord descendants!
     * @param string $className active record class name.
     * @return Product the static model class
     */
    public static function model($className = __CLASS__)
    {
        return parent::model($className);
    }
}

gridview代码

<?php $this->widget('zii.widgets.grid.CGridView', array(
    'id' => 'product-grid',
    'dataProvider' => $model->search(),
    'filter' => $model,
    'columns' => array(
        'id',
        'name',
        'eladasi' => array(
            'name' => 'eladasi',
            'header' => 'Eladási ár',
            'type' => 'raw',
            'headerHtmlOptions' => array('class' => 'auto-width text-center'),
            'value' => '!empty($data->price2->price) ? $data->price2->price == "" ? "-" : $data->price2->price : "-"',
            'htmlOptions' => array('class' => 'border-right auto-width text-center'),
        ),
        'akcios' => array(
            'name' => 'akcios',
            'header' => 'Akciós',
            'value' => '!empty($data->price3->price) ? $data->price3->price == "" ? "-" : $data->price3->price : "-"',
            'headerHtmlOptions' => array('class' => 'auto-width text-center'),
            'htmlOptions' => array('class' => 'border-right auto-width text-center'),
        ),
        'beszerzesi' => array(
            'name' => 'beszerzesi',
            'header' => 'Beszerzési ár',
            'type' => 'raw',
            'value' => '!empty($data->price1->price) ? $data->price1->price == "" ? "-" : $data->price1->price : "-"',
            'headerHtmlOptions' => array('class' => 'auto-width text-center'),
            'htmlOptions' => array('class' => 'border-right auto-width text-center'),
        ),
        array(
            'class' => 'CButtonColumn',
        ),
    ),
)); ?>

您可以在Searching and sorting by related model in CGridView | Wiki | Yii PHP Framework

找到有关关系数据的搜索和排序的分步指南