Yii Search With Multiple Condition, Please Help!

Dear all,

I have a friendship table to record users’ friends.

I have the following columns : sender, receiver, accept.

E.g., If user 1 and user 10 are friends.

The table may be:


sender(1) receiver(10) accept(1)

Or

sender(10) receiver(1) accept(1)


I want to achieve the following effect, so the user can search all his friends, they may be in either sender or receiver field…

Here is what I have now


	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


                $criteria->with = array('senderx'); //my relations to the User model.

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


                $criteria->condition = '(receiver=:uId) OR (sender=:uId)';

                $criteria->params = array(    

                     ':uId' => Yii::app()->user->id,  

               );  




		return new CActiveDataProvider($this, array(

    'criteria'=>$criteria,

    'pagination'=>array(

        'pageSize'=>10,

    ),

		));

	}


<?php echo CHtml::link('Search Friends','#',array('class'=>'search-button btn btn-primary')); ?>

<div class="search-form" style="display:none">

<?php $form=$this->beginWidget('CActiveForm', array(

	'action'=>Yii::app()->createUrl($this->route),

	'method'=>'get',

)); ?>


	<div class="row">

		<?php echo $form->textField($search,'friend'); ?>

	</div>


	<div class="row buttons">

		<?php echo CHtml::submitButton('Search',array('class'=>'btn btn-success')); ?>

	</div>


<?php $this->endWidget(); ?>

All I want is … a default page display user’s friends(either in sender/receiver fields).

You can search the username of the sender/receiver and update the dataprovider…

Any ideas? Big thanks!

Right now it displays all the friends correctly, but the search function is totally useless…

now u r rendering with the


'criteria'=>$criteria 

what u actually want?

Hi jiaming

the search() seems correct in general way.

Why didn’t use the CGridView widget to test your issue? (or use in general way)

I tried but doesn’t work…the search is not working at all : (

But if I delete the whole condition part, it works(through not my purpose)

I am not sure I understand your point…?Shouldn’t I use


'criteria'=>$criteria 

?

Thanks


$criteria->condition = '(receiver=:uId) OR (sender=:uId)';

overwrites all conditions previously set by $criteria->compare(). Use CDbCriteria::addCondition() instead.

Thanks for your help…Now the list is displaying properly. But the serach function is still not working…

I want the user search username of either receiver/sender and get the list…

Is there a way to do so?


	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


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

                $criteria->addCondition('username', $this->friend,true);


                $criteria->addCondition('receiver=:uId','OR');

                $criteria->addCondition('sender=:uId','OR');


                $criteria->params = array(    

                     ':uId' => Yii::app()->user->id,  

               );  


		return new CActiveDataProvider($this, array(

    'criteria'=>$criteria,

    'pagination'=>array(

        'pageSize'=>10,

    ),


		));

	}


<?php 

echo CHtml::link('Search Friends','#',array('class'=>'search-button btn btn-primary')); ?>

<div class="search-form" style="display:none">

<?php $form=$this->beginWidget('CActiveForm', array(

	'action'=>Yii::app()->createUrl($this->route),

	'method'=>'get',

)); ?>


	<div class="row">

		<?php echo $form->textField($search,'friend'); ?>

	</div>


	<div class="row buttons">

		<?php echo CHtml::submitButton('Search',array('class'=>'btn btn-success')); ?>

	</div>


<?php $this->endWidget(); 

?>



‘friend’ is only a property I initialized, not a column in database.

THank you!

Hi, thanks for your help…I just modified my code… Would you please have a look at it?

Even if I replace condition with addcondition, it still not works…




                $criteria->addCondition('receiver=:uId OR sender=:uId2','AND');

                $criteria->params = array(    

                     ':uId' => Yii::app()->user->id,  

                     ':uId2' => Yii::app()->user->id,  

               );  



You have to use a different place holder for each condition, even if it is the same thing.

And I thought the following is not what you want:




                $criteria->addCondition('username', $this->friend,true);

                $criteria->addCondition('receiver=:uId','OR');

                $criteria->addCondition('sender=:uId2','OR');



This means:




(('username' = $this->friend) OR 'receiver' = user) or 'sender' = user



What you want should be:




('username' = $this->friend) AND ('receiver' = user or 'sender' = user)



Thanks for your help…I revised my code like the following now:


	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


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

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


/*******this are codes in my relationships**********

          'senderx' => array(self::BELONGS_TO, 'Users', 'sender'),  

           'receiverx' => array(self::BELONGS_TO, 'Users', 'receiver'),

****************************************************/


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


                $criteria->addCondition('receiver=:uId1','OR');

                $criteria->addCondition('sender=:uId2','OR');


                $criteria->params = array(    

                     ':uId1' => Yii::app()->user->id,  

                     ':uId2' => Yii::app()->user->id,  

               );  


		return new CActiveDataProvider($this, array(

    'criteria'=>$criteria,

    'pagination'=>array(

        'pageSize'=>10,

    ),


		));

	}

In the view:


<?php echo CHtml::link('Search Friends','#',array('class'=>'search-button btn btn-primary')); ?>

<div class="search-form" style="display:none">

<?php $form=$this->beginWidget('CActiveForm', array(

	'action'=>Yii::app()->createUrl($this->route),

	'method'=>'get',

)); ?>


	<div class="row">

		<?php echo $form->textField($search,'friend'); ?>

	</div>


	<div class="row buttons">

		<?php echo CHtml::submitButton('Search',array('class'=>'btn btn-success')); ?>

	</div>


<?php $this->endWidget(); ?>

However, The search function is not working at all. No matter what I Input ,the dataprovider will not be updated AFTER I ADD ANY CONDITIONS in search();

Any ideas?

Thank you very much for your help!! I really appreciate it!!

Ah, I’m very sorry. I was wrong.

Would you please try this one?




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


                $criteria->addCondition('receiver=:uId1','OR');

                $criteria->addCondition('sender=:uId2','OR');


                $criteria->params[':uId1'] = Yii::app()->user->id,  

                $criteria->params[':uId2'] = Yii::app()->user->id,  



‘$criteria->compare()’ will set an item in $criteria->params for it, and we should not overwrite it.

Hi, thanks so much for your help!

I tried but still, the list is still not updating at all. no matter what i input in the search field. I want the user input the username so it updated the list…

[b]I believe the problem is the "friend" property… Can I really get username from either receiverx or senders(my 2 relations) in this way?

[/b]

Here is my complete code now.


		$criteria=new CDbCriteria;


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

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


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


                $criteria->addCondition('receiver=:uId1','OR');

                $criteria->addCondition('sender=:uId2','OR');


                $criteria->params[':uId1'] = Yii::app()->user->id;  

                $criteria->params[':uId2'] = Yii::app()->user->id;  


	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(

               'senderx' => array(self::BELONGS_TO, 'Users', 'sender'),

               'receiverx' => array(self::BELONGS_TO, 'Users', 'receiver'),

		);

	}

Thanks !!

It might be because you are combining the conditions with ‘OR’.

Your current code means:




(('username' = $this->friend) OR 'receiver' = user) or 'sender' = user



So I guess this is what you want.




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

                $criteria->addCondition('receiver=:uId1 OR sender=:uId2','AND');

                $criteria->params[':uId1'] = Yii::app()->user->id;  

                $criteria->params[':uId2'] = Yii::app()->user->id;



This means:




('username' = $this->friend) AND ('receiver' = user or 'sender' = user)



I revised the code to




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

                $criteria->addCondition('receiver=:uId1 OR sender=:uId2','AND');

                $criteria->params[':uId1'] = Yii::app()->user->id;  

                $criteria->params[':uId2'] = Yii::app()->user->id;



[b]However, if i use


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

, and "friend" property in the view page, the list is still not updating.

If I change “friend” to “sender”, it works, but of course it’s not going to achieve my goal (because the user may type in the receiver too. since receiver is also your friends)…[/b]

THANK YOU!

I don’t understand what $this->friend is for … do you want to search friends by their name?




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



What the above means is that you are comparing “friend” with the user’s own name … It’s very natural that you get no results (zero records) when you input some name other than the user’s own name.

I want the user input either sender or receiver’s name in the field, basically, the user input a name in the field, I determine that among all friends of the users,(receiver/sender = :uid), whose username is the user’s input.

For example, in my database:

[b]sender:1 receiver:2

sender:5 receiver:1

For user1, his friends are 2 and 5. I want him enter a name and find 2 or 5…[/b]

I can’t have 2 fields and let user input your friend is receiver or sender…I want the server to decide…

friend is simply a property i declared in my model, its not a column of my table… And now i get ALL results no matter what i input for the friends field. not zero…

Thanks so much again for your help! I really appreciate it.

I see.

Then you have to compare $this->friend with ‘senderx.username’ or ‘receiverx.username’, assuming that ‘senderx’ and ‘receiverx’ has an attribute of ‘username’.

It’s a little complicated …




$criteria = new CDbCriteria();

$criteria->with = array('senderx', 'receiverx');

$criteria->compare('t.sender', Yii::app()->user->id);

$criteria->compare('t.receiver', Yii::app()->user->id, false, 'OR');

if ($this->friend != '')

{

	$criteria2 = new CDbCriteria();

	$criteria2->compare('senderx.username', $this->friend, true);

	$criteria2->compare('receiverx.username', $this->friend, true, 'OR');

	$criteria->mergeWith($criteria2);

}



By using ‘compare’, you can forget the params of the criteria. Of course you can use addCondition method instead.

Sometimes you have to merge multiple criteria when your conditions involve complicated 'AND’s and 'OR’s.

Please look up ‘compare’, ‘mergeWith’ in the reference for details.

Thank you very much…It works like a charm now… : ]

Thanks again for your help! I really appreciate this!