2011-05-16 18 views
6

que tenía un problema ordenar una lista paginada cuando se utiliza un campo calculado como Count() en cakephp 1.3Cakephp paginación ordenar por campo calculado (COUNT)

Digamos que tengo dos modelos: el artículo y Comentarios (1 artículo x N comentarios) y quiero mostrar una lista paginada de los artículos que incluyen la cantidad de comentarios para cada uno. Tendría algo como esto:

controlador:

$this->paginate = array('limit'=>80, 
         'recursive'=>-1, 
         'fields'=>array("Article.*","COUNT(Comment.id) as nbr_comments"), 
         'joins'=>array(array( 'table' => 'comments', 
                'alias' => 'Comment', 
                'type' => 'LEFT', 
                'conditions' => array('Comment.article_id = Article.id')) 
              ), 
         'group'=>"Article.id" 
         ); 

(tuve que sobreescribir el método findCount() con el fin de utilizar paginate grupo por)

El problema es que en la vista , el método no funcionará sort():

<th><?php echo $this->Paginator->sort('nbr_comments');?></th> //life is not that easy 

yo era capaz de crear una solución de "trampa" del p agination y ordenar:

controlador

$order = "Article.title"; 
$direction = "asc"; 
if(isset($this->passedArgs['sort']) && $this->passedArgs['sort']=="nbr_comments") 
    $order = $this->passedArgs['sort']; 
    $direction = $this->passedArgs['direction']; 
    unset($this->passedArgs['sort']); 
    unset($this->passedArgs['direction']); 
} 
$this->paginate = array(... 'order'=>$order." ".$direction, ...); 
$this->set('articles', $this->paginate()); 
if($order == "clicks"){ 
    $this->passedArgs['sort'] = $order; 
    $this->passedArgs['direction'] = $direction; 
} 

Ver

<?php $direction = (isset($this->passedArgs['direction']) && isset($this->passedArgs['sort']) && $this->passedArgs['sort'] == "nbr_comments" && $this->passedArgs['direction'] == "desc")?"asc":"desc";?> 
<th><?php echo $this->Paginator->sort('Hits','clicks',array('direction'=>$direction));?></th> 

Y funciona .. pero parece que es demasiado código para algo que debería ser transparente para el developper . (Se siente como si estuviera haciendo un trabajo de pastel) Entonces, estoy preguntando si hay otra manera más simple. Tal vez el pastel tiene esta función, pero decidió esconderlo ... o_O ... no hay nada sobre esto en la documentación, y no he encontrado otra buena solución en S.O ... ¿cómo lo haces?

¡Gracias de antemano!

Respuesta

6

quizás su problema se puede resolver usando Virtual fields?

Si crea un campo personalizado para su campo calculado, podrá ordenar usando el método Paginator-> sort() en ese campo personalizado.

Encontré esa solución there en los comentarios (no es necesario personalizar el método de paginación, etc. usando campos personalizados en lugar de en la solución inicial de adnan).

+1

ciertamente ayuda, =) con los campos virtuales no tengo que preocuparme por el agradecimiento '$ this-> passedArgs' ... sin embargo, aún necesita [anular el paginateCount] (http://stackoverflow.com/questions/7120257/cakephp-pagination-count-not-matching-query/7121798#7121798) método si desea paginar los resultados – pleasedontbelong

+0

Otro problema es que a veces tendrá que determinar fields (conditions => fields) para que un campo virtual no sea solicitado/obtenido. Porque de lo contrario, la consulta podría cambiar. Por ejemplo, con el recuento de campo virtual (*): el método de búsqueda siempre devolverá solo 1 fila. – Philipili

+0

No sabía de vitualFields, y ahora lo hago, y hacen exactamente lo que necesitaba. ¡Gracias! – Benjam

2

Lo que puede querer hacer es utilizar la funcionalidad Cake counterCache en la definición de su modelo. En lugar de calcular los recuentos de comentarios en tiempo de lectura, agrega nbr_comments como un campo int en su tabla articles. Cada vez que se inserta o borra Comment, nbr_comments se actualizará automáticamente.

En su modelo Comment:

var $belongsTo = array(
    'Article' => array(
     'counterCache' => 'nbr_comments' 
    ) 
); 

Ahora puedes usar $this->Paginator->sort('Article.nbr_comments'); Usted no necesita hacer nada cobarde en su controlador.

+0

pero me temo que si agrego un campo calculado en una tabla db, el fantasma de Codd me acosará por la noche XD ... en este ejemplo estoy usando solo un COUNT por que ya tuve algunos casos donde tengo un COUNT, un AVG y una fórmula en la misma consulta.si almaceno esa información en el DB corro el riesgo de la integridad de los datos – pleasedontbelong

Cuestiones relacionadas