diff --git a/lib/Cake/Controller/Component/PaginatorComponent.php b/lib/Cake/Controller/Component/PaginatorComponent.php index d7743b401..fdb0eeeab 100644 --- a/lib/Cake/Controller/Component/PaginatorComponent.php +++ b/lib/Cake/Controller/Component/PaginatorComponent.php @@ -353,7 +353,7 @@ class PaginatorComponent extends Component { $order[$alias . '.' . $field] = $value; } elseif ($object->hasField($key, true)) { $order[$field] = $value; - } elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field)) { + } elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field, true)) { $order[$alias . '.' . $field] = $value; } } diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index 0546690ea..7d777d44e 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -2590,6 +2590,10 @@ class DboSource extends DataSource { if (is_object($model) && $model->isVirtualField($key)) { $key = '(' . $this->_quoteFields($model->getVirtualField($key)) . ')'; } + list($alias, $field) = pluginSplit($key); + if (is_object($model) && $alias !== $model->alias && is_object($model->{$alias}) && $model->{$alias}->isVirtualField($key)) { + $key = '(' . $this->_quoteFields($model->{$alias}->getVirtualField($key)) . ')'; + } if (strpos($key, '.')) { $key = preg_replace_callback('/([a-zA-Z0-9_-]{1,})\\.([a-zA-Z0-9_-]{1,})/', array(&$this, '_quoteMatchedField'), $key); diff --git a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php index d19d868c3..5a381b878 100644 --- a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php @@ -87,6 +87,13 @@ class PaginatorControllerPost extends CakeTestModel { */ public $lastQueries = array(); +/** + * belongsTo property + * + * @var array + */ + public $belongsTo = array('PaginatorAuthor' => array('foreignKey' => 'author_id')); + /** * beforeFind method * @@ -183,6 +190,45 @@ class PaginatorControllerComment extends CakeTestModel { public $alias = 'PaginatorControllerComment'; } +/** + * PaginatorAuthorclass + * + * @package Cake.Test.Case.Controller.Component + */ +class PaginatorAuthor extends CakeTestModel { + +/** + * name property + * + * @var string 'PaginatorAuthor' + */ + public $name = 'PaginatorAuthor'; + +/** + * useTable property + * + * @var string 'authors' + */ + public $useTable = 'authors'; + +/** + * alias property + * + * @var string 'PaginatorAuthor' + */ + public $alias = 'PaginatorAuthor'; + +/** + * alias property + * + * @var string 'PaginatorAuthor' + */ + public $virtualFields = array( + 'joined_offset' => 'PaginatorAuthor.id + 1' + ); + +} + class PaginatorComponentTest extends CakeTestCase { /** @@ -190,7 +236,7 @@ class PaginatorComponentTest extends CakeTestCase { * * @var array */ - public $fixtures = array('core.post', 'core.comment'); + public $fixtures = array('core.post', 'core.comment', 'core.author'); /** * setup @@ -490,6 +536,30 @@ class PaginatorComponentTest extends CakeTestCase { $this->assertEqual(Set::extract($result, '{n}.PaginatorControllerPost.offset_test'), array(2, 3, 4)); } +/** + * test paginate() and virtualField on joined model + * + * @return void + */ + public function testPaginateOrderVirtualFieldJoinedModel() { + $Controller = new PaginatorTestController($this->request); + $Controller->uses = array('PaginatorControllerPost'); + $Controller->params['url'] = array(); + $Controller->constructClasses(); + $Controller->PaginatorControllerPost->recursive = 0; + $Controller->Paginator->settings = array( + 'order' => array('PaginatorAuthor.joined_offset' => 'DESC'), + 'maxLimit' => 10, + 'paramType' => 'named' + ); + $result = $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertEqual(Set::extract($result, '{n}.PaginatorAuthor.joined_offset'), array(4, 2, 2)); + + $Controller->request->params['named'] = array('sort' => 'PaginatorAuthor.joined_offset', 'direction' => 'asc'); + $result = $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertEqual(Set::extract($result, '{n}.PaginatorAuthor.joined_offset'), array(2, 2, 4)); + } + /** * Tests for missing models * diff --git a/lib/Cake/Test/Case/Model/ModelReadTest.php b/lib/Cake/Test/Case/Model/ModelReadTest.php index 3af3fde7f..8f2c2388c 100644 --- a/lib/Cake/Test/Case/Model/ModelReadTest.php +++ b/lib/Cake/Test/Case/Model/ModelReadTest.php @@ -7543,6 +7543,50 @@ class ModelReadTest extends BaseModelTest { $this->assertEqual($result, 4); } +/** + * testVirtualFieldsOrder() + * + * Test correct order on virtual fields + * + * @return void + */ + public function testVirtualFieldsOrder() { + $this->loadFixtures('Post', 'Author'); + $Post = ClassRegistry::init('Post'); + $Post->virtualFields = array('other_field' => '10 - Post.id'); + $result = $Post->find('list', array('order' => array('Post.other_field' => 'ASC'))); + $expected = array( + '3' => 'Third Post', + '2' => 'Second Post', + '1' => 'First Post' + ); + $this->assertEqual($result, $expected); + + $result = $Post->find('list', array('order' => array('Post.other_field' => 'DESC'))); + $expected = array( + '1' => 'First Post', + '2' => 'Second Post', + '3' => 'Third Post' + ); + $this->assertEqual($result, $expected); + + $Post->Author->virtualFields = array('joined' => 'Post.id * Author.id'); + $result = $Post->find('all'); + $result = Set::extract('{n}.Author.joined', $result); + $expected = array(1, 6, 3); + $this->assertEqual($result, $expected); + + $result = $Post->find('all', array('order' => array('Author.joined' => 'ASC'))); + $result = Set::extract('{n}.Author.joined', $result); + $expected = array(1, 3, 6); + $this->assertEqual($result, $expected); + + $result = $Post->find('all', array('order' => array('Author.joined' => 'DESC'))); + $result = Set::extract('{n}.Author.joined', $result); + $expected = array(6, 3, 1); + $this->assertEqual($result, $expected); + } + /** * testVirtualFieldsMysql() *