CakePHP 对连接表进行分页条件

问题描述 投票:0回答:4

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

NewsArticle HMBTM NewsCategory
NewsCategory HMBTM NewsArticle 

在我的新闻文章控制器函数 index() 中,我试图获取新闻类别 id 为 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。

任何人都可以帮忙吗,这肯定很简单吗?我缺少什么?预先感谢。

php cakephp
4个回答
2
投票

适用于 CakePHP 2.3.4(2013 年 6 月)

问题出在Controller/Component/PaginatorComponent.php

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

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

要解决此问题:

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

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);

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

重写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 );
    }
}

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

这让您可以在 JOINED 餐桌上点餐。


0
投票
'conditions' => array('newsArticle.news_category_id = 2')

应该是:

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

这与错误并不完全匹配,但没有其他真正突出的地方。

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

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

0
投票

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


0
投票

我花了 2 天的时间寻找 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'));

}
© www.soinside.com 2019 - 2024. All rights reserved.