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 に触れていないことがわかります。

誰でも助けることができますか?確かにこれはかなり簡単です? 私は何が欠けていますか?前もって感謝します。

4

4 に答える 4

2

CakePHP 2.3.4 で動作 (2013 年 6 月)

問題は Controller/Component/PaginatorComponent.php にあります

関数 validateSort() は、同じモデル内の属性の注文のみを返すように設定されているため、間違った注文行を返します。ドキュメントがvalidateSortで言うように

フィールドまたは virtualFields のみをソートできます。

これを回避するには:

コントローラーコード (例としてユーザーコントローラーを使用):

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 関数の 3 番目のパラメーターはホワイト リストで、通常は現在のオブジェクトのアイテムのみですが、すべてのホワイト リスト オブジェクトを追加しました。

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 関数もオーバーライドします。

これにより、結合されたテーブルで注文できます。

于 2013-05-28T10:32:11.450 に答える
0

関数を NewsCategory コントローラーに切り替え、containable を使用して結果をページ分割することもできます。このリンクは、それを機能させる方法の良い例を提供します http://www.24100.net/2012/07/cakephp-hasandbelongstomany-relationship-queries-demystified/

于 2012-11-30T16:01:34.943 に答える
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);
于 2012-11-30T12:42:11.930 に答える
0

ページネーションを使用した CakePHP の複数の結合条件の解決策を探すのに 2 日間を費やしました。解決策が見つからなかったので、私の解決策を複数の結合と条件でページネーションに投稿することを考えました。これが誰かに役立つことを願っています。

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

}
于 2015-11-10T00:33:10.157 に答える