我的 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。
任何人都可以帮忙吗,这肯定很简单吗?我缺少什么?预先感谢。
适用于 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 餐桌上点餐。
'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);
您还可以将函数切换到 NewsCategory 控制器,使用 containsable 并以这种方式对结果进行分页。此链接提供了一个关于如何使其工作的好示例http://www.24100.net/2012/07/cakephp-hasandbelongstomany-relationship-queries-demystified/
我花了 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'));
}