在Join Table上的CakePHP Paginate条件

时间:2012-11-30 12:29:37

标签: cakephp

我的cakephp应用程序(2.2)应用程序具有以下内容:

NewsArticle HMBTM NewsCategory
NewsCategory HMBTM NewsArticle 

在我的新闻文章中,控制器功能索引()我试图获得一个新闻类别为2的新闻文章的分页列表。

继承我的代码(这是错误的):

$this->paginate = array(
        'conditions' => array('newsArticle.news_category_id = 2'),
        'limit' => 10,
        'order' => array(
            'newsArticle.modified' => 'asc'
        )
    );
    $this->set('newsArticles', $this->paginate());

有人能告诉我哪里出错了吗?我猜这与联接表有关。

这是我得到的错误:

Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'newsArticle.news_category_id' in 'where clause'

这是它产生的SQL:

SQL查询:

SELECT
    `NewsArticle`.`id`,
    `NewsArticle`.`title`,
    `NewsArticle`.`brief`,
    `NewsArticle`.`body`,
    `NewsArticle`.`filename`,
    `NewsArticle`.`dir`,
    `NewsArticle`.`mimetype`,
    `NewsArticle`.`filesize`,
    `NewsArticle`.`live`,
    `NewsArticle`.`user_id`,
    `NewsArticle`.`created`,
    `NewsArticle`.`modified`,
    `User`.`id`,
    `User`.`username`,
    `User`.`password`,
    `User`.`forename`,
    `User`.`surname`,
    `User`.`company`,
    `User`.`position`,
    `User`.`role`,
    `User`.`version_numbers_id`,
    `User`.`support_case_reference`,
    `User`.`support_web_password`,
    `User`.`webforms_email`,
    `User`.`tech_email`,
    `User`.`group_id`,
    `User`.`user_status_id`,
    `User`.`view_uat`,
    `User`.`manuals`,
    `User`.`filename`,
    `User`.`dir`,
    `User`.`mimetype`,
    `User`.`filesize`,
    `User`.`created`,
    `User`.`modified`,
    `User`.`live`,
    `User`.`tokenhash`
FROM `cakeclientarea`.`news_articles` AS `NewsArticle`
LEFT JOIN `cakeclientarea`.`users` AS `User`
    ON (`NewsArticle`.`user_id` = `User`.`id`)
WHERE
    `newsArticle`.`news_category_id` = 2
ORDER BY
    `newsArticle`.`modified` asc
LIMIT 10 

我可以从中看到它甚至没有触及连接表news_articles_news_categories。

任何人都可以提供帮助,当然这很简单吗?我错过了什么?提前谢谢。

4 个答案:

答案 0 :(得分:2)

适用于CakePHP 2。3。4(2013年6月)

麻烦在于Controller / Component / PaginatorComponent.php

函数validateSort()返回错误的订单行,因为它被设置为仅返回同一Model中属性的顺序。正如文档在validateSort上所述

  

只能对字段或虚拟字段进行排序。

解决这个问题:

在Controller代码中(以用户控制器为例):

public $components = array(
    'Paginator' => array(
        'className' => 'JoinedPaginator'),
    );

在功能中:

$this->paginate = array(
    'recursive'=>-1, // should be used with joins
    'joins'=>array(
        array(
            'table'=>'groups',
            'type'=>'inner',
            'alias'=>'Group',
            'conditions'=>array('User.group_id = Group.id')
        )
    )
)

$fields = array('User.name', 'User.id', 'Group.name');

$users = $this->paginate('User', array(), $fields);

paginate函数中的第三个参数是白名单,通常只有当前对象中的项目,但我们添加了所有列出白名单的对象。

重写Paginator,制作Component / JoinedPaginator.php

<?php
App::uses('PaginatorComponent', 'Controller/Component');
class JoinedPaginatorComponent extends PaginatorComponent {

    public $Controller;

    function startup(Controller $controller) {
        $this->Controller = $controller;
    }

    public function validateSort(Model $object, array $options, array $whitelist = array()) {
        if (isset($options['sort'])) {
            $direction = null;
            if (isset($options['direction'])) {
                $direction = strtolower($options['direction']);
            }
            if (!in_array($direction, array('asc', 'desc'))) {
                $direction = 'asc';
            }
            $options['order'] = array($options['sort'] => $direction);
        }

        if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) {
            $field = key($options['order']);
            if (!in_array($field, $whitelist)) {
                $options['order'] = null;
                return $options;
            }
        }

        if (!empty($options['order']) && is_array($options['order'])) {
            $order = array();
            foreach ($options['order'] as $key => $value) {
                $field = $key;
                $alias = $object->alias;
                if (strpos($key, '.') !== false) {
                    list($alias, $field) = explode('.', $key);
                }
                // Changed the order field list, to include items in join tables
                if (isset($object->{$alias}) && $object->{$alias}->hasField($field, true)) {
                    $order[$alias . '.' . $field] = $value;
                } else if(in_array($alias.'.'.$field, $whitelist)){
                    // Adding a white list order, to include items in the white list
                    $order[$alias . '.' . $field] = $value;
                } else if ($object->hasField($field)) {
                    $order[$object->alias . '.' . $field] = $value;
                } elseif ($object->hasField($key, true)) {
                    $order[$field] = $value;
                }
            }
            $options['order'] = $order;
        }

        return $options;
    }

    public function paginate($object = null, $scope = array(), $whitelist = array()) {
        $this->settings = am ($this->Controller->paginate, $this->settings);
        return parent::paginate($object, $scope, $whitelist );
    }
}

如您所见,设置未发送到新的paginate对象,因此我也会覆盖paginate函数,只是为了收集设置。

这可让您在JOINED表上订购。

答案 1 :(得分:0)

'conditions' => array('newsArticle.news_category_id = 2')

shoule be:

'conditions' => array('newsArticle.news_category_id'=>'2')

这与错误并不匹配,但没有其他任何东西真正突出。

您可以尝试以不同的方式接近它,以确保不是您的模型关系导致错误。

$this->paginate('NewsArticle');
$this->paginate['NewsArticle']['conditions'] = array('newsArticle.news_category_id'=>'2');
pr($this->paginate);

答案 2 :(得分:0)

您还可以将您的功能切换到NewsCategory控制器,使用可包含并以这种方式对结果进行分页。此链接提供了有关如何使其正常工作的良好示例http://www.24100.net/2012/07/cakephp-hasandbelongstomany-relationship-queries-demystified/

答案 3 :(得分:0)

我花了两天的时间寻找cakephp多重连接条件和分页的解决方案。无法找到任何解决方案,因此想到将我的解决方案发布到具有多个连接和条件的分页。希望这对某人来说会派上用场。

 public function index(){

        $data = $this->request->data;
        $searchText ='';

        if($this->request->is("post")) {
        $url = array('action'=>'index');
        $filters = array();
        echo("hello hello helloa");

        echo ($this->request->data);
                if(isset($data['Skinauditreport']['searchText']) && $data['Skinauditreport']['searchText']){
                        echo ($data['Skinauditreport']['searchText']);
                        //maybe clean up user input here??? or urlencode??
                        $filters['searchText'] = $data['Skinauditreport']['searchText'];
                }
                //redirect user to the index page including the selected filters
                $this->redirect(array_merge($url,$filters));
        }


        $this->Skinauditreport->recursive = 1;

        //Joining 2 tables, skinauditreports_users and users table
        $options['joins'] = array(
                array('table' =>'skinauditreports_users',
                'alias' => 'SkaUser',
                'type' => 'inner',
                'conditions' => array(
                        'Skinauditreport.id = SkaUser.ska_id'
                        )
                ),
                array('table' => 'users',
                'alias'=> 'User',
                'type' => 'inner',
                'conditions' => array(
                        'SkaUser.user_id = User.id'
                        )
                )
        );
        // Check user is admin user if then dont filter the report.
        if($this->Session->read('Auth.User.group_id') != '3'){
                $options['conditions'] = array(
                        'User.id' => $this->Auth->user('id')
                );
        }
        //Add this condition if there is a search text.
        if(isset($this->passedArgs["searchText"])) {
                 $options['conditions'] =array( array('OR' => array(
                                array('Skinauditreport.name LIKE' => "%".strtoupper($this->passedArgs["searchText"])."%"),
                                array('Skinauditreport.name LIKE' => "%".$this->passedArgs["searchText"]."%")
                        ))
                );

                $searchText = $this->passedArgs["searchText"];
        }

        $this->set('searchText',$searchText);
        //$skaReports = $this->Skinauditreport->find('all',$options);
        //$this->set('skaReports', $skaReports);

        $this->Paginator->settings = $options;
        $this->set('skaReports', $this->paginate('Skinauditreport'));

}