paamayim wrote:Quello che vorrei fare quindi nel controller è poter scrivere:
$this->Item->query("SELECT ....... WHERE .... GROUP BY ... etc etc");
e poi configurare il $paginator da usare nella view, è possibile secondo voi? Senza passare da ->paginate() ?
Grazie.
No, direi che è arduo.
Se dai un occhio al metodo paginate() di Controller (/libs/controller/controller.php) ti accorgi che grosso modo esegue queste operazioni:
- estrae le opzioni passate nella URL (la pagina corrent, il limit, l'ordine di sorting)
- le aggiunge alla $conditions del metodo find() del Model
- *conta* i risultati
Un metodo generico che sia in grado di aggiungere alla tua generica query le condizioni LIMIT e ORDER BY sarebbe difficile da realizzare perché presupporrebbe un'analisi molto dettagliata della query: se ad esempio la query che fornisci avesse già un ORDER BY, ci sarebbe certamente il rischio di un errore SQL.
Mi sembra anche molto difficile, data una query generica, scrivere un metodo che restituisca il numero totale dei risultati, a meno di estrarli tutti e contarli (il che significa annullare quasi totalmente l'utilità della paginazione!).
Una possibile soluzione è questa:
crea un file app_controller sotto app/ con il contenuto:
<?php
class AppController extends Controller
{
function customPaginate($query)
{
$model = $this->{$this->modelClass};
$options = $this->params['named'];
if(!empty($options['page']))
$page = $options['page'];
else
$page = 1;
if(!empty($options['sort']))
{
$query .= " ORDER BY {$options['sort']}";
if(!empty($options['direction']))
$query .= " {$options['direction']}";
}
if(empty($options['limit']))
$options['limit']=$this->paginate['limit'];
$limit = $options['limit'];
$results = $model->query($query);
$count = count($results);
$frompage = $limit* ($page-1);
$query .= " LIMIT {$frompage},{$limit}";
$results = $model->query($query);
$pageCount = intval(ceil($count / $limit));
echo "Page count={$pageCount}";
if ($page == 'last' || $page >= $pageCount) {
$options['page'] = $page = $pageCount;
} elseif (intval($page) < 1) {
$options['page'] = $page = 1;
}
//$results = $object->find($type, array_merge($parameters,
$extra));
$paging = array(
'page' => $page,
'current' => $count,
'count' => $count,
'prevPage' => ($page > 1),
'nextPage' => ($count > ($page * $limit)),
'pageCount' => $pageCount,
'defaults' => array_merge(array('limit' => 20, 'step' =>
1), $options),
'options' => $options
);
$this->params['paging']['Category'] = $paging;
if (!in_array('Paginator', $this->helpers) &&
!array_key_exists('Paginator', $this->helpers)) {
$this->helpers[] = 'Paginator';
}
return $results;
}
}
?>
Dopo di che usi la paginazione come da te richiesto:
class UsersController extends AppController {
function index()
{
$this->set('users', $this->customPaginate('LA TUA QUERY CUSTOM'));
}
}
Personalmente io NON lo userei nemmeno sotto tortura, per tre motivi:
1. E' un codice che ti ho scritto al volo, non l'ho mai utilizzato, è molto meno versatile dell'originale e probabilmente ha dei bug. Ha uno stile che definire ridicolo è poco. Andrebbe ottimizzato. E' poco performante.
2. Se sei costretto ad usare query custom, ripensa decisamente all'architettura della tua applicazione: l'ORM di Cake è decisamente più affidabile, comodo, versatile di un approccio più manuale
3. Ci sono dei limiti evidenti: quel codice si pianta se nella query è presente una clausola LIMIT o una ORDER BY.
Quindi, prendi quanto ti ho scritto solo come spunto.
Ma, davvero: perché mai dovresti usare delle query custom? Ti perdi il vantaggio delle relazioni, delle validazioni, della gestione delle condizioni con gli array.. tanto vale programmare in plain PHP ;)
Last edited by arialdomartini (28-10-2008 16:07:59)