Założenie: Mamy dwie tabele, jedna z produktami, druga z typami produktów, które są w relacji productTypeId należy do typeId.
Product
productId
productName
productTypeId
Type
typeId
typeName
Szbkie przypomnienie, jak używać filtrów na modelach w cgridview.
Tworzymy model:
class Product extends CActiveRecord
{
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return 'Product';
}
public function rules()
{
return array(
array('productId, , productName, productTypeId', 'required'),
array('productId, , productName', 'safe', 'on'=>'search'),
);
}
public function attributeLabels()
{
return array(
'productName' => 'Nazwa Produktu',
'productType' => 'Typ'
);
}
public function relations()
{
return array
(
'type' => array(self::BELONGS_TO, 'Type', 'productTypeId')
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('productId',$this->productId);
$criteria->compare('productName',$this->productName,true);
$criteria->compare('productTypeId',$this->productTypeId,true);
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria,
));
}
}
Teraz nasz kontroller, którego zadaniem jest przyjąć dane z geta, wysyłane z CGridView, nakarmić nimi model, i wyrenderować widok:
public function actionShowProducts()
{
$model=new Product('search');
$model->unsetAttributes();
if(isset($_GET['Product']))
{
$model->attributes=$_GET['Product'];
}
$this->render('showproduct', array('model'=>$model));
}
Następnie nasz widok:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'product-grid',
'dataProvider'=>$model->search(),
'itemsCssClass'=>'gridview',
'filter'=>$model,
'columns'=>array(
'productName',
'productTypeId',
)
));
?>
Sortowanie działa nam na modelu więc możemy filtrować po typeId wpisując cyfry, ale co jeśli chcemy szukać po jego nazwie? I tu właśnie wkracza mój szalony umysł ]:->
Potrzebujemy modyfikacji w modelu i w widoku, a więc do dzieła !
Najpier w modelu deklarujemy pulbliczne własności klasy, odpowiadające nazwie pola po którym chcemy szukać, będzie to abstrakcyjne pole klasy Produkt.
class Product extends CActiveRecord
{
public $typeName;
public static function model($className=__CLASS__)
{
return parent::model($className);
}
.....
Następnie dopisujemy to pole do rules modelu:
...
public function rules()
{
return array(
array('productId, , productName, productTypeId', 'required'),
array('typeName','length','max'=>50)
array('productId, , productName', 'safe', 'on'=>'search'),
);
}
...
Teraz modyfikujemy metodę search:
...
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('productId',$this->productId);
$criteria->compare('productName',$this->productName,true);
$criteria->compare('productTypeId',$this->productTypeId,true);
$criteria->join = 'JOIN Type ON Type.typeId=productTypeId';
$criteria->compare('Type.name',$this->typeName,true);
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria,
));
}
...
Dodałem dwie linijki
$criteria->join = 'JOIN Type ON Type.typeId=productTypeId';
$criteria->compare('Type.name',$this->typeName,true);
Pierwsza dołącza do zapytania tabele Type, druga sprawdza czy wprowadzony przez nas ciąg jest podobny do tego w bazie, parametr true na końcu. Ustawiony na false szuka dokładnego wyniku.
Modyfikacja nr 2 to widok, musimy napisać customowy filtr.
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'product-grid',
'dataProvider'=>$model->search(),
'itemsCssClass'=>'gridview',
'filter'=>$model,
'columns'=>array(
'productName',
array(
'type'=>'raw',
'header'=>'Nazwa Typu',
'name'=>'typeName',
'value'=>'(empty($data->type->typeName) ? "brak" : $data->type->typeName)',
'filter'=>'<input name="Product[typeName]" value="'.$model->typeName.'"/>',
)
)
));
Zamiast pola productTypeId, wstawiłem array, header wiadomo nagłówek, name, podajemy nazwe naszej virtualnej właściwości tabeli Product. To działa tak samo jak opisany przeze mnie wcześniej model do logowania Login By Form Model
Więcej na mojej stronie log-this.com