Using pagination with CakePHP’s finderQuery SQL
Update February 2009: this article is now about a year old and deals with an early beta versions of CakePHP 1.2. In the mean time, CakePHP 1.2 has been released with many improvements and great documentation. Please don’t use this patch, use this instead. I’ll leave the article below for reference.
Cakephp lets you define various kinds of associations between models. The principle is really simple, just define arrays like $hasMany
in your main model, where associations with other models are defined.
For most purposes this does the trick, most associations are made by convention, but you can override these as well for e.g. database (foreign-) keys.
From there on, you can use all cake built-in functionality to retrieve model data. One such feature is auto pagination, where the page size is set through the value of the limit
field in the model’s definition.
If you’re crafting something really complex, you can define your own SQL query in the finderQuery
field. This is very nice, but the trade-of is that the other fields are ignored in the query. And if fields limit
and offset
are ignored, you no longer get auto pagination.
The patch below fixes this for the current development tree of CakePHP 1.2 (revision 6461).
This patch inspects the finderQuery
SQL and applies the values of the relevant model fields if the SQL does not contain a value for LIMIT
and ORDER BY
, respectively.
So now you have:
limit
value from model applied, unless LIMIT is defined infinderQuery
order
value from model or application query applied, unless ORDER BY is defined infinderQuery
offset
value from model or application query applied, unless LIMIT is defined infinderQuery
Patch for /cake/libs/model/datasources/dbo_source.php
-
Index: dbo_source.php
-
===================================================================
-
— dbo_source.php (revision 6461)
-
+++ dbo_source.php (working copy)
-
@@ -1046,7 +1046,19 @@
-
if ($external && isset($assocData[‘finderQuery’])) {
-
if (!empty($assocData[‘finderQuery’])) {
-
– return $assocData[‘finderQuery’];
-
+ $qry = $assocData[‘finderQuery’];
-
+ // if no ORDER is specified in finderquery, use model definition
-
+ if (!preg_match(‘/\sORDER\s+BY\s/i’, $qry)) {
-
+ $orderData = (empty($queryData[‘order’])) ? $assocData[‘order’] : $queryData[‘order’];
-
+ $qry .= ‘ ‘ . $this->order($orderData);
-
+ }
-
+ // if no LIMIT/OFFSET is specified in finderquery, use model definition
-
+ if (!preg_match(‘/\sLIMIT\s/i’, $qry)) {
-
+ $limitData = (empty($queryData[‘limit’])) ? @$assocData[‘limit’] : $queryData[‘limit’];
-
+ $offsetData = (empty($queryData[‘offset’])) ? @$assocData[‘offset’] : $queryData[‘offset’];
-
+ $qry .= ‘ ‘ . $this->limit($limitData, $offsetData);
-
+ }
-
+ return $qry;
-
}
-
}
[ratings]