2012-08-16 17 views
3

我在CakePHP(最新版本)中编码标记搜索,但我所做的解决方案似乎过于复杂,而CakePHP的其余部分有多容易。希望有人能指出我正确的方向或帮助我改进我现有的解决方案。CakePHP复杂的查找/查询 - 改进当前的解决方案

我的应用程序中的每个用户都可以标记自己的标签,例如:php,objective-c,javascript,jquery。不同类型的用户可以搜索具有特定标签的用户。他们可能搜索:php,objective-c,ios。我需要按照它们匹配的标签的顺序返回一组用户,具有全部3个标签的用户将出现在数组的顶部。

下面是一个数据库示例和我的解决方案。我很感激任何帮助改善这一点。

[数据库]

enter image description here

[解决方法]

   //Search Array 
      //Format: array('objective-c', 'javascript', 'jquery', 'php') 
      $tag_array = explode(",", $this->request->data["User"]["search"]); 

      //Get Tag IDs - array([id] => [id]) 
      //Format: array([1] => '1', [2] => '2', [4] => '4', [15] => '15') 
      $result_tag_ids = $this->User->TagsUser->Tag->find('list', array(
       'conditions' => array(
        "Tag.name" => $tag_array 
       ), 
       'fields' => array('Tag.id')  
      )); 

      //Get User IDs - array([id] => [id]) 
      //Format: array([24] => '24', [24] => '24', [26] => 26, [27] => '27') 
      $result_user_ids = $this->User->TagsUser->find('list', array(
       'conditions' => array(
        "TagsUser.tag_id" => $result_tag_ids 
       ), 
       'fields' => array('TagsUser.user_id')  
      )); 


      //Remove Duplicate user ids and add a count of how many tags matched & sort the array in that order 
      //Format: array([26] => 1, [24] => 2, [27] => 3) 
      $counted_user_ids = array_count_values($result_user_ids); 
      asort($counted_user_ids); 


      //Get the keys (user_ids) 
      $list_user_ids = array_keys($counted_user_ids); 

      //Get these users in the order of the sorted array 
      $search_result = $this->User->find('all', array(
       'conditions' => array(
        "User.id" => $list_user_ids 
       ), 
       'order' => 'FIELD(User.id,' . implode(" ,", $list_user_ids) . ')' 

      )); 
+1

我想这就好了。查询HABTM并按行数排序肯定会很复杂。但是你已经把它归结为可管理/易于理解的东西。 (也就是说,总是有一种“更好”的方式 - 希望有人用一些光滑的方式来改善它) – Dave 2012-08-16 13:27:02

回答

2

请试试这个:

$tag_array = explode(",", $this->request->data["User"]["search"]); 
//arrays expanded for better readability, 
//you should be able to compress in fewer lines if desired 

$options = array(); 
$options['contain'] = ''; 
//or recursive=-1, depends of what you are using to avoid extra models/fields 

$options['joins'][0]['table'] = 'tags_users'; 
$options['joins'][0]['conditions'] = 'User.id = user_id'; 
$options['joins'][1]['alias'] = 'Tag'; 
$options['joins'][1]['table'] = 'tags'; 
$options['joins'][1]['conditions']= 'Tag.id = tag_id'; 
$options['fields'] = array('User.id', 'COUNT(*) as tag_counter'); 
$options['group'] = 'User.id'; 
$options['order'] = 'tag_counter DESC'; 
$options['conditions']['Tag.name'] = $tag_array; 
$search_result = $this->User->find('all', $options); 

print_r($search_result)应该给:

Array 
    (
     [0] => Array 
      (
       [User] => Array 
        (
         [id] => (user id) 
        ) 
       [0] => Array 
        (
         [tag_counter] => (how many tags) 
        ) 
      ) 
     [...] 
    ) 

我希望它适合你。 如果你想知道每个用户对同一个查询有什么标签,只需调整包含或递归值即可。