[ANSWERED] Strange behavior of CPagination and CSort

Hello again,

In my model I have this:



<?php


class Client extends CActiveRecord


{


   //...


   public function relations()


   {


      return array(


         'contacts'=>array(self::HAS_MANY,'Contact','idClient')


      );


    }


   //...


And in ClientController…



<?php


   //...


   public function actionShow()


   {


      $client = $this->loadClient();


   


      $criteria=new CDbCriteria;


      $criteria->condition = 'idClient = '.$client->id;


   


      $pages=new CPagination(Contact::model()->count($criteria)); // Just the contacts for that client


      $pages->pageSize=self::PAGE_SIZE;


      $pages->applyLimit($criteria);


      $sort=new CSort('Contact');


      $sort->applyOrder($criteria);


      


      $contactList = $client->contacts;  // Pay attention to this line


      	


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


			'client'=>$client,


			'contactList'=>$contactList, 


			'pages'=>$pages,


			'sort'=>$sort


		));


		


	}








I do that to have in mi show view the info about that client, and all the contacts of that client.

What I want is to paginate the contacts…

But neither pagination nor order works.(sorry about my very poor english)

But if I change that line (the one to pay attention) for that



<?php


   //...


   $contactList = Contact::model()->findAll($criteria); // I change the other line with than one....





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


			'client'=>$client,


			'contactList'=>$contactList, 


			'pages'=>$pages,


			'sort'=>$sort


		));


   //...


The pagination and sort works perfectly…

This is the right way to do that?

In your second code fragment, shouldn't it be Contact::model() instead of Client::model()?

Yes sorry, I should write Contact::model()…

But the error is just in the post…

I mean… the problem remains in real life… where I have wrote Contact::model()

Hope you understand me!

What is the problem? The paging and sorting do not work? Did you check the generated SQL?

The pagination and sorting works if I put

$contactList = Contact::model()->findAll($criteria);

But doesn't work y I put

$contactList = $client->contacts;

That is the problem…

What do you mean not work? It doesn't sort, or paginate? or is there any error? What is the SQL?

Oh, sorry…

The sorting does not work, If I click on some column header to order by that one, the page refresh but no sort is aplied…

The pagination does not work: suposse that I have 15 contacts, the 15 appears… and my PAGE_SIZE is 10… and the links to paginate appears, actually:

Go to page: < Previous 1 2 Next >

But if I click on 2, the page refres, but to the same page, where the 15  appears…

I will post my show view file too, just wait me a second

Please check the generated SQL. That's more important.



<h2>Client <?php echo $client->name; ?></h2>





<div class="actionBar">


[<?php echo CHtml::link('Client List',array('list')); ?>]


[<?php echo CHtml::link('New Client',array('create')); ?>]


[<?php echo CHtml::link('Update Client',array('update','id'=>$client->id)); ?>]


[<?php echo CHtml::linkButton('Delete Client',array('submit'=>array('delete','id'=>$client->id),'confirm'=>'sure?')); ?>]


[<?php echo CHtml::link('Manage Client',array('admin')); ?>]


</div>





<table class="dataGrid">


<tr>


	<th class="label"><?php echo CHtml::encode($client->getAttributeLabel('name')); ?>


</th>


    <td><?php echo CHtml::encode($cliente->cliente_nombre); ?>


</td>


</tr>


<tr>


	<th class="label"><?php echo CHtml::encode($client->getAttributeLabel('address')); ?>


</th>


    <td><?php echo CHtml::encode($cliente->address); ?>


</td>


</tr>





</table>








<h3>Contacts</h3>


<table class="dataGrid">


  <tr>


    <th><?php echo $sort->link('lastname'); ?></th>


    <th><?php echo $sort->link('name'); ?></th>


    <th><?php echo $sort->link('phone'); ?></th>


    <th><?php echo $sort->link('email'); ?></th>    


	<th>Acciones</th>


  </tr>


<?php foreach($contactList as $n=>$model): ?>


  <tr class="<?php echo $n%2?'even':'odd';?>">    


    <td><?php echo CHtml::encode($model->lastname); ?></td>


    <td><?php echo CHtml::encode($model->name); ?></td>


    <td><?php echo CHtml::encode($model->phone); ?></td>


    <td><?php echo CHtml::encode($model->email); ?></td>    


    <td>


      <?php echo CHtml::link('update',array('contact/update','id'=>$model->id)); ?>


      <?php echo CHtml::linkButton('delete',array(


      	  'submit'=>'',


      	  'params'=>array('command'=>'delete','id'=>$model->id),


      	  'confirm'=>"Are you sure to delete #{$model->contacto_id}?")); ?>


	</td>


  </tr>


<?php endforeach; ?>


</table>


<br/>


<?php $this->widget('CLinkPager',array('pages'=>$pages)); ?>








If I use Contac::model()->findAll($criteria); all works perfect and the sql is the following:

SELECT * FROM Contact WHERE idClient = 1 ORDER BY name DESC LIMIT 1

BUT if I use $client->contacts: the sorting and pagination does not work properly, and the sql is the following:

SELECT COUNT(*) FROM Contact WHERE idClient = 1

Sorry sorry no the las sql, the sql is this

SELECT Client.id AS t0_c0,

            t3.id AS t3_c0,

            t3.idClient AS t3_c1,

            t3.lastname AS t3_c2,

            t3.name AS t3_c3,

            t3.phone AS t3_c4,

            t3.email AS t3_c5,

            FROM Client LEFT OUTER JOIN Contact t3 ON t3.idClient=Client.id WHERE Cliente.id=1

To put it more clear:

When I use Contact::model()->findAll($criteria):

2009/03/31 13:30:52 [trace] [system.db.CDbCommand] query with SQL: SELECT Client.id AS t0_c0, t3.id AS t3_c0, t3.idClient AS t3_c1, t3.lastname AS t3_c2, t3.name AS t3_c3, t3.phone AS t3_c4, t3.email AS t3_c5 FROM Client LEFT OUTER JOIN Contact t3 ON t3.idClient=Client.id WHERE Cliente.id=1

2009/03/31 13:30:52 [trace] [system.db.CDbCommand] query with SQL: SELECT COUNT(*) FROM Contact WHERE idClient = 1

2009/03/31 13:30:52 [trace] [system.db.CDbCommand] query with SQL: SELECT * FROM Contact WHERE idClient = 1 ORDER BY name DESC, lastname DESC, phone LIMIT 1

When I use $client->contacts;

2009/03/31 13:43:08 [trace] [system.db.CDbCommand] query with SQL: SQL: SELECT Client.id AS t0_c0, t3.id AS t3_c0, t3.idClient AS t3_c1, t3.lastname AS t3_c2, t3.name AS t3_c3, t3.phone AS t3_c4, t3.email AS t3_c5 FROM Client LEFT OUTER JOIN Contact t3 ON t3.idClient=Client.id WHERE Cliente.id=1

2009/03/31 13:43:08 [trace] [system.db.CDbCommand] query with SQL: SELECT COUNT(*) FROM Contact WHERE idClient = 1

Note that the last line not appears…

Just a little idea, have you tried it with using eager loading?

Something like:

$withOption['contacts']['condition']='??.idClient=:id';


$withOption['contacts']['params'][':id']=$client->id;     


$count=Client::model()->with($withOption)->count($criteria);


$pages=new CPagination($count);

Don't know. But i had nearly the same trouble but on a many:many relation…

thaks yoshi but that does not help… the problem (I think) is other…

Keep in mind that:

With Contact::model()->findAll($criteria) WORKS perfectly…

BUT

with $client->contacts does NOT works properly (the sorting and pagination)

$client->contacts; is not working because it has no chance to use the criteria at all (there is a ticket about specifying dynamic criteria for such lazy loading queries).

So you should use Contact::model() to query contacts with the criteria. Make sure you only fetch those contacts belonging to the current user.

ok… let me see if I understand:

I must use Contact::model()->findAll($criteria). Here $criteria the only thing that do is filter just the contacts of the current client. (Actullay I'm doing this and works perfect as I post above)

But if I use $client->contacts, it will not work… right?

But, then, I have one more question:

What is the diference between

$criteria=new CDbCriteria;

$criteria->condition = 'idClient = '.$client->id;

$contactList = Contact::model()->findAll($criteria);

and

$contactList = $client->contacts.

(Remember that in my Client model I have a relation declared as:

'contacts'=>array(self::HAS_MANY,'Contact','idClient')

)

???

You have the following lines in the first case:



     $pages->pageSize=self::PAGE_SIZE;


      $pages->applyLimit($criteria);


      $sort=new CSort('Contact');


      $sort->applyOrder($criteria);


Yeah… but here the $criteria is applied to CSort and CPagination objects…

My $criteria just filters the contacts for the actual client.

So

$contactList1 = Contact::model()->findAll($criteria) // Just the contacts for a client.

and

$contactList2 = $cliente->contacts;

both $contactList1, and $contactList2 have all the contacts for a given client right?

Nope, CSort and CPagination modify the criteria (adding sort and order clause)

AAAhhhhhhhhhhhhh!!!

Ok… that a good answer…

I hope that in a near future I can use $client->contacts (it's more natural)…

But the other solution (the actual I'm using is perfect for me)…

Thaks for the answers…  apologize for wasting your time…