Skip to content
This repository
Browse code

Paginating now work well with custom find methods.

 _findCount() will now pass $query['operation'] = 'count' for more flexibility.
Custom finders can distinguish the operation and return other $query if needed.
  • Loading branch information...
commit bbfaa9e94734bfc7c01bdad0eb80c1d0aa4e14ff 1 parent 4b3d861
ceeram authored February 29, 2012
9  lib/Cake/Model/Model.php
@@ -2727,11 +2727,20 @@ protected function _findFirst($state, $query, $results = array()) {
2727 2727
  */
2728 2728
 	protected function _findCount($state, $query, $results = array()) {
2729 2729
 		if ($state === 'before') {
  2730
+			if (!empty($query['type']) && isset($this->findMethods[$query['type']]) && $query['type'] !== 'count' ) {
  2731
+				$query['operation'] = 'count';
  2732
+				$query = $this->{'_find' . ucfirst($query['type'])}('before', $query);
  2733
+			}
2730 2734
 			$db = $this->getDataSource();
2731 2735
 			$query['order'] = false;
2732 2736
 			if (!method_exists($db, 'calculate') || !method_exists($db, 'expression')) {
2733 2737
 				return $query;
2734 2738
 			}
  2739
+			if (!empty($query['fields']) && is_array($query['fields'])) {
  2740
+				if (!preg_match('/^count/i', current($query['fields']))) {
  2741
+					unset($query['fields']);
  2742
+				}
  2743
+			}
2735 2744
 			if (empty($query['fields'])) {
2736 2745
 				$query['fields'] = $db->calculate($this, 'count');
2737 2746
 			} elseif (is_string($query['fields']) && !preg_match('/count/i', $query['fields'])) {
273  lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php
@@ -229,6 +229,94 @@ class PaginatorAuthor extends CakeTestModel {
229 229
 
230 230
 }
231 231
 
  232
+/**
  233
+ * PaginatorCustomPost class
  234
+ *
  235
+ * @package       Cake.Test.Case.Controller.Component
  236
+ */
  237
+class PaginatorCustomPost extends CakeTestModel {
  238
+/**
  239
+ * useTable property
  240
+ *
  241
+ * @var string
  242
+ */
  243
+	public $useTable = 'posts';
  244
+
  245
+/**
  246
+ * belongsTo property
  247
+ *
  248
+ * @var string
  249
+ */
  250
+	public $belongsTo = array('Author');
  251
+
  252
+/**
  253
+ * findMethods property
  254
+ *
  255
+ * @var array
  256
+ */
  257
+	public $findMethods = array(
  258
+		'published' => true,
  259
+		'totals' => true,
  260
+		'totalsOperation' => true
  261
+	);
  262
+
  263
+/**
  264
+ * _findPublished custom find
  265
+ *
  266
+ * @return array
  267
+ */
  268
+	public function _findPublished($state, $query, $results = array()) {
  269
+        if ($state === 'before') {
  270
+            $query['conditions']['published'] = 'Y';
  271
+            return $query;
  272
+        }
  273
+        return $results;
  274
+	}
  275
+
  276
+/**
  277
+ * _findTotals custom find
  278
+ *
  279
+ * @return array
  280
+ */
  281
+	public function _findTotals($state, $query, $results = array()) {
  282
+		if ($state == 'before') {
  283
+			$query['fields'] = array('author_id');
  284
+			$this->virtualFields['total_posts'] = "COUNT({$this->alias}.id)";
  285
+			$query['fields'][] = 'total_posts';
  286
+			$query['group'] = array($this->alias . '.author_id');
  287
+			return $query;
  288
+		}
  289
+		$this->virtualFields = array();
  290
+		return $results;
  291
+	}
  292
+
  293
+/**
  294
+ * _findTotalsOperation custom find
  295
+ *
  296
+ * @return array
  297
+ */
  298
+	public function _findTotalsOperation($state, $query, $results = array()) {
  299
+		if ($state == 'before') {
  300
+			if (!empty($query['operation']) && $query['operation'] === 'count') {
  301
+				unset($query['limit']);
  302
+				$query['recursive'] = -1;
  303
+				$query['fields'] = array('COUNT(DISTINCT author_id) AS count');
  304
+				return $query;
  305
+			}
  306
+			$query['recursive'] = 0;
  307
+			$query['callbacks'] = 'before';
  308
+			$query['fields'] = array('author_id', 'Author.user');
  309
+			$this->virtualFields['total_posts'] = "COUNT({$this->alias}.id)";
  310
+			$query['fields'][] = 'total_posts';
  311
+			$query['group'] = array('Author.user');
  312
+			return $query;
  313
+		}
  314
+		$this->virtualFields = array();
  315
+		return $results;
  316
+	}
  317
+
  318
+}
  319
+
232 320
 class PaginatorComponentTest extends CakeTestCase {
233 321
 
234 322
 /**
@@ -885,4 +973,189 @@ public function testPaginateOrderVirtualFieldSharedWithRealField() {
885 973
 		$this->assertEquals(Set::extract($result, '{n}.PaginatorControllerComment.id'), array(1, 2, 3, 4, 5, 6));
886 974
 	}
887 975
 
  976
+/**
  977
+ * test paginate() and custom find, to make sure the correct count is returned.
  978
+ *
  979
+ * @return void
  980
+ */
  981
+	public function testPaginateCustomFind() {
  982
+		$Controller =& new Controller($this->request);
  983
+		$Controller->uses = array('PaginatorCustomPost');
  984
+		$Controller->constructClasses();
  985
+		$data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
  986
+		$Controller->PaginatorCustomPost->create($data);
  987
+		$result = $Controller->PaginatorCustomPost->save();
  988
+		$this->assertTrue(!empty($result));
  989
+
  990
+		$result = $Controller->paginate();
  991
+		$this->assertEquals(Set::extract($result, '{n}.PaginatorCustomPost.id'), array(1, 2, 3, 4));
  992
+
  993
+		$result = $Controller->params['paging']['PaginatorCustomPost'];
  994
+		$this->assertEquals(4, $result['current']);
  995
+		$this->assertEquals(4, $result['count']);
  996
+
  997
+		$Controller->paginate = array('published');
  998
+		$result = $Controller->paginate();
  999
+		$this->assertEquals(Set::extract($result, '{n}.PaginatorCustomPost.id'), array(1, 2, 3));
  1000
+
  1001
+		$result = $Controller->params['paging']['PaginatorCustomPost'];
  1002
+		$this->assertEquals(3, $result['current']);
  1003
+		$this->assertEquals(3, $result['count']);
  1004
+
  1005
+		$Controller->paginate = array('published', 'limit' => 2);
  1006
+		$result = $Controller->paginate();
  1007
+		$this->assertEquals(Set::extract($result, '{n}.PaginatorCustomPost.id'), array(1, 2));
  1008
+
  1009
+		$result = $Controller->params['paging']['PaginatorCustomPost'];
  1010
+		$this->assertEquals(2, $result['current']);
  1011
+		$this->assertEquals(3, $result['count']);
  1012
+		$this->assertEquals(2, $result['pageCount']);
  1013
+		$this->assertTrue($result['nextPage']);
  1014
+		$this->assertFalse($result['prevPage']);
  1015
+	}
  1016
+/**
  1017
+ * test paginate() and custom find with fields array, to make sure the correct count is returned.
  1018
+ *
  1019
+ * @return void
  1020
+ */
  1021
+	public function testPaginateCustomFindFieldsArray() {
  1022
+		$Controller =& new Controller($this->request);
  1023
+		$Controller->uses = array('PaginatorCustomPost');
  1024
+		$Controller->constructClasses();
  1025
+		$data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
  1026
+		$Controller->PaginatorCustomPost->create($data);
  1027
+		$result = $Controller->PaginatorCustomPost->save();
  1028
+		$this->assertTrue(!empty($result));
  1029
+
  1030
+		$Controller->paginate = array(
  1031
+			'list',
  1032
+			'conditions' => array('PaginatorCustomPost.published' => 'Y'),
  1033
+			'limit' => 2
  1034
+		);
  1035
+		$result = $Controller->paginate();
  1036
+		$expected = array(
  1037
+			1 => 'First Post',
  1038
+			2 => 'Second Post',
  1039
+		);
  1040
+		$this->assertEquals($expected, $result);
  1041
+		$result = $Controller->params['paging']['PaginatorCustomPost'];
  1042
+		$this->assertEquals(2, $result['current']);
  1043
+		$this->assertEquals(3, $result['count']);
  1044
+		$this->assertEquals(2, $result['pageCount']);
  1045
+		$this->assertTrue($result['nextPage']);
  1046
+		$this->assertFalse($result['prevPage']);
  1047
+	}
  1048
+
  1049
+/**
  1050
+ * test paginate() and custom find with fields array, to make sure the correct count is returned.
  1051
+ *
  1052
+ * @return void
  1053
+ */
  1054
+	public function testPaginateCustomFindGroupBy() {
  1055
+		$Controller =& new Controller($this->request);
  1056
+		$Controller->uses = array('PaginatorCustomPost');
  1057
+		$Controller->constructClasses();
  1058
+		$data = array('author_id' => 2, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
  1059
+		$Controller->PaginatorCustomPost->create($data);
  1060
+		$result = $Controller->PaginatorCustomPost->save();
  1061
+		$this->assertTrue(!empty($result));
  1062
+
  1063
+		$Controller->paginate = array(
  1064
+			'totals',
  1065
+			'limit' => 2
  1066
+		);
  1067
+		$result = $Controller->paginate();
  1068
+		$expected = array(
  1069
+			array(
  1070
+				'PaginatorCustomPost' => array(
  1071
+					'author_id' => '1',
  1072
+					'total_posts' => '2'
  1073
+				)
  1074
+			),
  1075
+			array(
  1076
+				'PaginatorCustomPost' => array(
  1077
+					'author_id' => '2',
  1078
+					'total_posts' => '1'
  1079
+				)
  1080
+			)
  1081
+		);
  1082
+		$this->assertEquals($expected, $result);
  1083
+		$result = $Controller->params['paging']['PaginatorCustomPost'];
  1084
+		$this->assertEquals(2, $result['current']);
  1085
+		$this->assertEquals(3, $result['count']);
  1086
+		$this->assertEquals(2, $result['pageCount']);
  1087
+		$this->assertTrue($result['nextPage']);
  1088
+		$this->assertFalse($result['prevPage']);
  1089
+
  1090
+		$Controller->paginate = array(
  1091
+			'totals',
  1092
+			'limit' => 2,
  1093
+			'page' => 2
  1094
+		);
  1095
+		$result = $Controller->paginate();
  1096
+		$expected = array(
  1097
+			array(
  1098
+				'PaginatorCustomPost' => array(
  1099
+					'author_id' => '3',
  1100
+					'total_posts' => '1'
  1101
+				)
  1102
+			),
  1103
+		);
  1104
+		$this->assertEquals($expected, $result);
  1105
+		$result = $Controller->params['paging']['PaginatorCustomPost'];
  1106
+		$this->assertEquals(1, $result['current']);
  1107
+		$this->assertEquals(3, $result['count']);
  1108
+		$this->assertEquals(2, $result['pageCount']);
  1109
+		$this->assertFalse($result['nextPage']);
  1110
+		$this->assertTrue($result['prevPage']);
  1111
+	}
  1112
+
  1113
+/**
  1114
+ * test paginate() and custom find with returning otehr query on count operation,
  1115
+ * to make sure the correct count is returned.
  1116
+ *
  1117
+ * @return void
  1118
+ */
  1119
+	public function testPaginateCustomFindCount() {
  1120
+		$Controller =& new Controller($this->request);
  1121
+		$Controller->uses = array('PaginatorCustomPost');
  1122
+		$Controller->constructClasses();
  1123
+		$data = array('author_id' => 2, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
  1124
+		$Controller->PaginatorCustomPost->create($data);
  1125
+		$result = $Controller->PaginatorCustomPost->save();
  1126
+		$this->assertTrue(!empty($result));
  1127
+
  1128
+		$Controller->paginate = array(
  1129
+			'totalsOperation',
  1130
+			'limit' => 2
  1131
+		);
  1132
+		$result = $Controller->paginate();
  1133
+		$expected = array(
  1134
+			array(
  1135
+				'PaginatorCustomPost' => array(
  1136
+					'author_id' => '3',
  1137
+					'total_posts' => '1'
  1138
+				),
  1139
+				'Author' => array(
  1140
+					'user' => 'larry',
  1141
+				)
  1142
+			),
  1143
+			array(
  1144
+				'PaginatorCustomPost' => array(
  1145
+					'author_id' => '1',
  1146
+					'total_posts' => '2'
  1147
+				),
  1148
+				'Author' => array(
  1149
+					'user' => 'mariano'
  1150
+				)
  1151
+			)
  1152
+		);
  1153
+		$this->assertEquals($expected, $result);
  1154
+		$result = $Controller->params['paging']['PaginatorCustomPost'];
  1155
+		$this->assertEquals(2, $result['current']);
  1156
+		$this->assertEquals(3, $result['count']);
  1157
+		$this->assertEquals(2, $result['pageCount']);
  1158
+		$this->assertTrue($result['nextPage']);
  1159
+		$this->assertFalse($result['prevPage']);
  1160
+	}
888 1161
 }

0 notes on commit bbfaa9e

sitedyno

Shouldn't this check for $query['operation'] !== 'count' as well to prevent recursion?

ceeram

If query type is count it wont set operation count, this is only needed if custom finders are paginated. The code you link to, is 1.x code which needed this workaround.

Please sign in to comment.
Something went wrong with that request. Please try again.