0

私は 2 日前に andConditions について質問するために書きましたが、その考えを理解していないように見えましたが、実際には 2 日間、CakeDC を使用して次のステップに行き詰まっています。

CakeDC 検索プラグインの「クエリ」メソッドで複雑な HABTM 条件を実装するにはどうすればよいですか?

私はオファーHABTM機能(テーブル:オファー、機能、features_offers)を持っており、コントローラーで使用すると以下がうまく機能します:

debug($this->Offer->find('all', array('contain' => array(
                'Feature' => array(
                    'conditions' => array(                                
                            'Feature.id in (8, 10)',
                        )
                )
            )
                )
        )
);

検索で同​​じ条件を使用したい場合に問題が発生します。

public $filterArgs = array(
    array('name' => 'feature_id', 'type' => 'query', 'method' => 'findByFeatures'),
);


........

public function findByFeatures($data = array()) {
    $conditions = '';
    $featureID = $data['feature_id'];

    if (isset($data['feature_id'])) {
        $conditions = array('contain' => array(
                'Feature' => array(
                    'conditions' => array(
                        'Feature.id' => $data['feature_id'],
                                        )
                                    )
                                )
                            );
    }

    return $conditions;        
}

エラーが発生します:

エラー: SQLSTATE[42S22]: 列が見つかりません: 1054 不明な列 'where 句' の 'contain'

これにより、この検索を実行したり、検索で包含可能な動作をまったく使用したりできないと思います。

この分野でより多くの経験を積んだ人が、何か不足している場合は教えてください。または、その解決策を正確に見つける場所を教えてください。おそらくクックブックのセクションですか?

編集:結合も試しました。これはコントローラーで完全に機能し、必要なすべてのデータを返します。

$options['joins'] = array(
    array('table' => 'features_offers',
        'alias' => 'FeaturesOffers',
        'type' => 'inner',
        'conditions' => array(
            'Offer.id = FeaturesOffers.offer_id'
        ),
        array('table' => 'features',
            'alias' => 'F',
            'type' => 'inner',
            'conditions' => array(
                'F.id = FeaturesOffers.feature_id'
            ),
        )
    ),
);

$options['conditions'] = array(
    'feature_id in (13)' //. $data['feature_id']
);

debug($this->Offer->find('all', $options));

...そして、検索メソッドを入れようとすると、返された条件は SQL の where 句でのみ取得されます

WHERE ((joins = (Array)) AND (conditions = ('feature_id in Array')))

...エラーになります:

SQLSTATE [42S22]: 列が見つかりません: 1054 不明な列 'where 句' の列 '結合'

編集: 多分私は愚かで、申し訳ありませんが、プラグインのドキュメントはひどいものです。

私は 2 重、3 重、4 重にチェックしました (ちなみに、検索フォームfacepalmの少なくとも 1 つのフィールドですでに 30 時間を失っています)、ドキュメントの愚かな findByTags はまだ意味がありません。

public function findByTags($data = array()) {
    $this->Tagged->Behaviors->attach('Containable', array('autoFields' => false));
    $this->Tagged->Behaviors->attach('Search.Searchable');
    $query = $this->Tagged->getQuery('all', array(
        'conditions' => array('Tag.name'  => $data['tags']),
        'fields' => array('foreign_key'),
        'contain' => array('Tag')
    ));
    return $query;
}

私が理解しているように

$this->Tagged

は、HABTM 協会のモデルの名前であるはずです。

ただし、これはCakePHPの標準からはかなりかけ離れています。

ここで説明されている方法では、別のモデルは必要なく、以下に示すように Recipe を Ingredient に関連付けることを示しています。

class Recipe extends AppModel {
    public $hasAndBelongsToMany = array(
        'Ingredient' =>
            array(
                'className'              => 'Ingredient',
                'joinTable'              => 'ingredients_recipes',
                'foreignKey'             => 'recipe_id',
                'associationForeignKey'  => 'ingredient_id',
                'unique'                 => true,
                'conditions'             => '',
                'fields'                 => '',
                'order'                  => '',
                'limit'                  => '',
                'offset'                 => '',
                'finderQuery'            => '',
                'deleteQuery'            => '',
                'insertQuery'            => ''
            )
    );
}

つまり、モデル「IngredientRecipe」を定義する必要なく、Recipe から HABTM 関連テーブル データにアクセスできます。

そして、cakeDC のドキュメントによると、必要なモデルは IngredientRecipe であり、cakePHP のドキュメントでは必須のものとして示されていません。このモデルを作成しても、HABTM アソシエーションが正しく動作しません - 私もこれを試しました。

そして今、検索機能を自分のやり方で書き直す必要があります。すでに 30 時間も費やしていたにもかかわらず、cakePHP だけを使用して...とても残念です。:(

4

3 に答える 3

1

プロジェクトでこれを行うたびに、CakeDC の検索動作を使用してそれを行う方法を理解するのにいつも何時間も費やしているので、これを書いて、自分が何をする必要があるかを簡単な言葉で思い出させようとしました. また、関連付けられたモデルで CakeDC 検索プラグインを使用することは一般的に正しいですが、独自のプロジェクトに変更することをより困難にする説明がないことにも気付きました。

「所有し、多くに属する」関係があり、結合テーブル、つまり、多対多の関係で両側のテーブルを結合する2つのフィールドを持つテーブルを検索したい場合は、リレーションシップ内のテーブルの 1 つから ID のリストを使用してサブクエリを作成したいと考えています。リレーションシップの反対側のテーブルの ID がチェックされ、それらがそのレコードに含まれているかどうかが確認されます。含まれている場合は、メイン テーブルのレコードが選択されます。

この次の例では

SELECT Handover.id, Handover.title, Handover.description
FROM handovers AS Handover 
WHERE Handover.id in 
(SELECT ArosHandover.handover_id
FROM aros_handovers AS ArosHandover 
WHERE ArosHandover.aro_id IN (3) AND ArosHandover.deleted != '1') 
LIMIT 20 

aro_id が 3 の場合、ArosHandover のすべてのレコードが選択され、Handover.id を使用して選択するハンドオーバー レコードが決定されます。

CakeDC の検索動作でこれを行う方法について説明します。

まず、フィールドを検索フォームに配置します。

echo $this->Form->create('Handover', array('class' => 'form-horizontal'));?>
echo $this->Form->input('aro_id', array('options' => $roles, 'multiple' => true, 'label' => __('For', true), 'div' => false,  true));

等...

フォーム要素を ArosHandover データ スペースに配置していないことに注意してください。別の言い方をすれば、フォーム リクエストが送信されると、フィールド aro_id が Handover という配列の下に配置されるということです。

変数 $filterArgs の下のモデル:

'aro_id' => array('name' => 'aro_id', 'type' => 'subquery', 'method' => 'findByAros', 'field' => 'Handover.id')

上記のように、タイプが「サブクエリ」であることに注意してください。適切なレコードを見つけるためにサブクエリを作成する必要があり、タイプをサブクエリに設定することで、SQL のサブクエリ スニペットを作成するよう CakeDC に指示しています。method は、コードを記述する関数名です。field 要素は、上記のサンプル クエリのこの部分に表示されるフィールドの名前です。

WHERE Handover.id in 

次に、サブクエリを返す関数を記述します。

    function findByAros($data = array()) 
    {
    $ids = ''; //you need to make a comma separated list of the aro_ids that are going to be checked
    foreach($data['aro_id'] as $k => $v)
    {
      $ids .= $v . ', ';
    }
    if($ids != '')
    {
      $ids = rtrim($ids, ', ');
    }
  //you only need to have these two lines in if you have not already attached the behaviours in the ArosHandover model file
    $this->ArosHandover->Behaviors->attach('Containable', array('autoFields' => false));
    $this->ArosHandover->Behaviors->attach('Search.Searchable');

    $query = $this->ArosHandover->getQuery('all',
       array(
         'conditions' => array('ArosHandover.aro_id IN (' . $ids . ')'),
         'fields' => array('handover_id'),  //the other field that you need to check against, it's the other side of the many-to-many relationship 
         'contain' => false //place this in if you just want to have the ArosHandover table data included
       )
    );
    return $query;
  }

ハンドオーバー コントローラーで:

public $components = array('Search.Prg', 'Paginator'); //you can also place this into AppController
public $presetVars = true; //using $filterArgs in the model configuration 
public $paginate = array(); //declare this so that you can change it

// this is the snippet of the search form processing
public function admin_find()
  {
    $this->set('title_for_layout','Find handovers');
    $this->Prg->commonProcess();
    if(isset($this->passedArgs) && !empty($this->passedArgs))
    {//the following line passes the conditions into the Paginator component
      $this->Paginator->settings = array('conditions' => $this->Handover->parseCriteria($this->passedArgs));
      $handovers = $this->Paginator->paginate(); // this gets the data
      $this->set('handovers', $handovers); // this passes it to the template

なぜ私が何かをしたのかについてさらに説明が必要な場合は、尋ねてください。あなたが尋ねたことを伝える電子メールを受け取った場合は、できる限り答えます.

于 2014-02-26T14:03:08.587 に答える
0

プラグインを使用して HABTM 検索を操作するための解決策がここにあることを皆さんと共有したいと思います:関連するモデルでの CakeDC 検索プラグインの使用

@burzum、ドキュメントは大丈夫とはほど遠いです。'type' => 'checkbox' の使用と、それが型であることがどこにも言及されていないことに気付きましたか? 文法の完全な欠如、多くのタイプミスや前置詞の欠落は言うまでもありません。作者が何を考えていたのかを把握し、そこに言葉を結び付けるだけで2日を失いました. それについてはノーコメント。

5日間の上り坂の仕事を終えて、私はそれを成し遂げたことをうれしく思います. とにかく役に立ってくれてありがとう。

于 2013-07-07T14:41:03.750 に答える