Many_Many

Witam, podczas swojej pracy z yii napotkałem na taki o to problem:

Mam w bazie 3 tabele, dla każdej z nich wygenerowałem model za pomocą gii:

Tabele:

kategorie:

  • id

  • nazwa

posty:

  • id

  • nazwa

kategorie_posty:

  • id

  • post_id

  • category_id

Efekt jaki chciałbym osiągnąć, to po kliknięciu w nazwe katogorii chciałbym uzyskać listę przynaleznych postów, chciałbym to zrobić za pomocą CDbCriteria - bo chciałbym sobie tym później ładnie zarządzać poprzez filtry ajaxowe. Nie bardzo wiem jak to rozpracować, kombinowałem coś z witch(), ale efekty nie są zadowalające. Miałby ktos jakąs wskazówkę która pozwoliłaby mi ruszyć z miejsca?

Koniecznie przeczytaj ten rozdział: http://www.yiiframew…en/database.arr

Z tabeli kategorie_posty wywal id, oraz usuń model do tej tabeli. Jak masz ustawione klucze zewnętrzne ? Jeżeli baza danych z której korzystasz obsługuje klucze zewnętrzne, to gii powinien odpowiednio wygenerować modele.

Najważniejsza jest funkcja relations().

Tak na przykład model Posty będzie miał taką funkcję relations:


public function relations(){

 		return array(

 			'kategorie'=>array(self::MANY_MANY, 'Kategorie',

   				'kategorie_posty(post_id, category_id)'),

 		);}

Teraz możesz pobrać posty z kategoriami tak:


$posty=Posty::model()->with('kategorie')->findAll();

CVarDumper::dump($posty[0]);



Jeżeli chcesz używać CDbCriteria, to tak samo ustawiasz sobie właściwość with a obiekt tej klasy przekazujesz do funkcji find() modelu:


$criteria=new CDbCriteria; 

$criteria->with('kategorie');

...

//inne kryteria wyszukiwania

...

$posty=Posty::model()->find($criteria);  

Klucze w bazie danych są ok.

W modelu postów mam taka relację(MANY_MANY)

mam równiez taką metodę:




public function search($id){

   $criteria=new CDbCriteria;

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

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

   $criteria->compare('text',$this->mail,true);

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

   $criteria->with = array('kategorie');

   $criteria->condition = 'kategorie.id = '.$id;

   return new CActiveDataProvider($this, array(

      'criteria'=>$criteria,

   ));

}



W kontrolerze:




public function actionViewPosts($id){

   $model=new Posts();

   $model->search($id);

   $model->unsetAttributes(); 

   if(isset($_GET['Posts']))

     $model->attributes=$_GET['Posts'];

   $this->render('viewPosts',array(

      'posts'=>$model,

      'id'=>$id

   ));

}



W widoku:




<?php 

$this->widget('zii.widgets.grid.CGridView', array(

   'id'=>'posts-grid',

   'dataProvider'=>$posts->search($id),

   'filter'=>$posts,

   'columns'=>array(

	'id',

	'title',

	'text',

	'link',

	array(

	   'class'=>'CButtonColumn'

	),

   ),

),

)); 

?>



I niestety, w prawdzie wyszukuje posty, ale znajduje dla każdej kategorii wszystkie(tzn. nie dzieli na kategorie - zawsze mam wszystie posty :/). W dodatku padła ta światna przeszukiwajka tabeli -> chcąc filtrować sobie ajax’owo po kolumnach system tylko mieli i nic nie zmienia:/

PS.

Gdy utworzyłem model kategorie_posty i w nim zmodyfikowałem funckcje search to działało tylko z koleji zamiast nazw miałem same id :confused:

metoda CDbCriteria::compare modyfikuje zawartosc atrybutu ‘condition’, ktory pozniej nadpisujesz:

$criteria->condition = 'kategorie.id = '.$id;

przenies ta linie przed wszystkie inne wywolania ‘compare’ i powinno byc lepiej. Polecam tez wyrobienie sobie nawyku uzywania wszedzie parametrow - latwiej uniknac SQLInjection…




public function search($id){

   $criteria=new CDbCriteria;

   $criteria->with = array('kategorie');

   $criteria->condition = 'kategorie.id = :kat_id';

   $criteria->params[':kat_id'] = $id;


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

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

   $criteria->compare('text',$this->mail,true);

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

   return new CActiveDataProvider($this, array(

      'criteria'=>$criteria,

   ));

}