CakePHP分页条件加入表 [英] CakePHP Paginate conditions on Join Table

查看:95
本文介绍了CakePHP分页条件加入表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  NewsArticle HMBTM新闻类别
新闻类别HMBTM新闻稿$ b

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



我的代码(错误):

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

);
$ this-> set('newsArticles',$ this-> paginate());

有人能告诉我我会出错吗?我猜这是与连接表。



遇到我得到的错误:

 错误:SQLSTATE [42S22]:未找到列:1054'where子句'中的未知列'newsArticle.news_category_id'

它生成的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```````````````````````````````tokenhash`从`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。



任何人都可以帮助,肯定这是相当简单的事情吗?我缺少什么?提前感谢。

解决方案

适用于CakePHP 2.3.4(2013年6月)



麻烦的是在Controller / Component / PaginatorComponent.php



函数validateSort()返回错误的订单行,因为它设置为只返回order在同一模型中的属性。正如文档在validateSort上说的


只能对字段或virtualField进行排序。


要解决此问题:



在控制器代码中(使用User Controller作为示例):

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

在功能中:

  $ this-> paginate = array(
'recursive'=> -1,//应与joins一起使用
'joins'=& $ b array(
'table'=>'groups',
'type'=>'inner',
'alias'=>'Group',
'conditions'=> array('User.group_id = Group.id')




$ fields = array ','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);
}
//更改订单字段列表,以包括连接表中的项
if(isset($ object-> {$ alias})&& $ object-> {$ alias} - > hasField($ field,true)){
$ order [$ alias。 '。'。 $ field] = $ value;
} else if(in_array($ alias。'。'。$ field,$ whitelist)){
//添加一个白名单,包括白名单中的项目
$ 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);
}
}

如您所见,设置不会发送到新的p / p>

这样就可以在JOINED表上进行排序。


My cakephp app (2.2) app has the following:

NewsArticle HMBTM NewsCategory
NewsCategory HMBTM NewsArticle 

In my News article controller function index() I'm trying to get a paginated list of news articles that have the news category id 2.

Heres my code (which is wrong):

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

Could someone tell me where I'm going wrong? I'm guessing this is to do with the join table.

Heres the error I'm getting:

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

Heres the SQL its producing:

SQL Query: 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 

I can see from this it's not even touching the join table news_articles_news_categories.

Can anyone help, surely this is fairly simple to do? What am I missing? Thanks in advance.

解决方案

Works for CakePHP 2.3.4 (June 2013)

The trouble is in Controller/Component/PaginatorComponent.php

The function validateSort(), return the wrong order line, as it is set to only return order on attributes in the same Model. As the documentation says on validateSort

Only fields or virtualFields can be sorted on.

To work around this:

In the Controller code (using User Controller as example):

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

In the function:

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

The third parameter in the paginate function is a white list, normally only items in the current object, but we added all white listed objects.

Overriding Paginator, making the 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 );
    }
}

As you see the settings is not sent to the new paginate object, so I override the paginate function as well, just to collect the settings.

This let you order on JOINED tables.

这篇关于CakePHP分页条件加入表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆