2013-07-04 32 views
0

我寫了2天前詢問和條件,它似乎我不明白的想法,但事實是,兩天後,我堅持下一步使用CakeDC:CakeDC搜索插件在與HABTM查詢中使用複雜條件

如何在CakeQuery搜索插件的「查詢」方法中實現複雜的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;   
} 

我得到一個錯誤:

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

這使得我認爲我無法在搜索中執行此搜索和/或使用可容忍的行爲。

如果有人在該領域有更多的經驗,請告訴我,如果我錯過了某些東西或指向我到哪裏找到解決方案 - 也許是食譜中的一個部分?

編輯:也試過連接。該控制器工作完全正常,返回我需要的所有數據:

$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]: Column not found: 1054 Unknown column 'joins' in 'where clause'

編輯:也許我是愚蠢的,抱歉地說,但該插件的文檔吸一噸。

我雙人,三人和四人檢查(順便說一句,已經失去了至少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的標準,但:http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm

它是這裏所描述的樣子,說,你並不需要另一種模式,而是你,如下圖所示副食譜與成分:

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

這意味着您可以從配方中訪問HABTM關聯表數據,而無需定義模型「IngredientRecipe」。

而且根據cakeDC文檔,你需要的型號是IngredientRecipe和未表示爲CakePHP的文檔中的一些強制性的。即使這個模型被創建,HABTM assoc也無法正常工作 - 我也試過這個。

現在我需要重新寫在我的方式搜索功能,只使用CakePHP的,即使我已經花了30個小時就......如此不開心。 :(

+0

IngredientRecipe錯誤的連接模型名稱應該是IngredientsRecipe,注意複數的成分。這本書也描述了這一點。 HABTM數組中有「with」鍵,可讓您指定模型。這本書在你粘貼在這裏的書的示例代碼之後。此外,這仍然不是插件或文檔的問題,您只需構建您的關聯和查詢錯誤。插件本身只是實現了PRG模式。歡迎您提交顯示插件中問題的單元測試。 – burzum

回答

0

這不是插件的問題,而是你如何建立關聯。您需要正確地加入他們跨越這三個表的搜索。檢查CakePHP的是如何在默認情況下取出由HABTM ASSOCS數據。

http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables

Suppose a Book hasAndBelongsToMany Tag association. This relation uses a books_tags table as join table, so you need to join the books table to the books_tags table, and this with the tags table:

$options['joins'] = array(
    array('table' => 'books_tags', 
     'alias' => 'BooksTag', 
     'type' => 'inner', 
     'conditions' => array(
      'Books.id = BooksTag.books_id' 
     ) 
    ), 
    array('table' => 'tags', 
     'alias' => 'Tag', 
     'type' => 'inner', 
     'conditions' => array(
      'BooksTag.tag_id = Tag.id' 
     ) 
    ) 
); 

$options['conditions'] = array(
    'Tag.tag' => 'Novel' 
); 

$books = $Book->find('all', $options); Using joins allows you to have a maximum flexibility in how CakePHP handles associations and fetch the data, however in most cases you can use other tools to achieve the same results such as correctly defining associations, binding models on the fly and using the Containable behavior. This feature should be used with care because it could lead, in a few cases, into bad formed SQL queries if combined with any of the former techniques described for associating models.

而且你的代碼是錯誤的地方。

Column not found: 1054 Unknown column 'contain' in 'where clause' 

這意味着$型號 - >包括()以某種方式調用。我在這裏粘貼的代碼中看不到這樣的調用,因此它必須位於其他位置。如果找不到模型方法,則通常會出現該字段名稱爲列的錯誤。

+0

包含被調用以使用可容納的行爲。它在上面的兩個例子「debug($ this-> Offer-> find('all',array('contains'=> array(」&「$ conditions = array('contains'=> array(」。Thanks for這個我會稍微檢查一下,會讓你知道的 我真的好奇,爲什麼同樣的東西在插件外工作得很好 – paradox

+0

剛試過這種方法,雖然我在控制器中工作,但它仍然沒有對搜索插件沒有任何作用,但我注意到,無論我的搜索方法返回什麼,它只會附加到WHERE子句中的SQL查詢中,並且不可能有任何聯接。:(((我很厭煩有連續第三天掙扎着做這個工作,真的無法得到爲什麼在控制器中完美工作的代碼無法與插件一起工作。 – paradox

0

我想和大家一起分享,解決與插件HABTM搜索工作就在這裏:Using the CakeDC search plugin with associated models

@burzum,文檔是遠遠好男人。你注意到'type'=>'checkbox'的用法,並且它在任何地方都沒有提及它是一種類型嗎? 更不用說完全缺乏語法和大量的錯別字和缺失的介詞。爲了掌握作者的想法並將其中的詞彙綁定,我失去了2天時間。對此沒有評論。

我很高興,經過上坡路上正常工作5天,我做到了。無論如何感謝您的幫助。

1

我每次做這個項目中,我總是花時間搞清楚如何使用CakeDC搜索行爲,所以我寫了這個嘗試,並提醒自己用簡單的語言是什麼,我需要做的去做。我也注意到,雖然Using the CakeDC search plugin with associated models這通常是正確的,但沒有任何解釋讓它更難以修改爲自己的項目。

當你有一個「擁有並且屬於許多」關係,並且你想要搜索連接表時,也就是具有兩個字段的表格,它將兩邊的表格以多對多的方式連接在一起-many關係你想創建一個帶有關係表中某個表的ID列表的子查詢。來自關係另一側表中的ID將被檢查以查看它們是否在該記錄中,並且如果它們是那麼主表中的記錄將被選擇。如果它們具有爲3的aro_id則Handover.id用於決定要選擇的切換記錄

在下面的例子從ArosHandover

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 

所有記錄將被選中。

在如何與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的數組下。

在根據變量$的filterExpr模型:

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

通知該類型是「子查詢」,因爲我上面提到你需要創建一個子查詢,以便能夠找到相應的記錄和將類型設置爲子查詢,您告訴CakeDC創建SQL的子查詢片段。該方法是將要編寫代碼的函數名稱。本場元件是要出現在例如查詢的該部分上面的字段的名稱

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 

如果您想進一步的解釋,爲什麼我做了什麼,問,如果我收到一封電子郵件,告訴我,你問我,我會給出一個答案 能夠。