2012-03-27 12 views
2

現在の投稿と共有されているタグに基づいて関連性の高い順に8つの投稿を表示しようとしています。作成日...CakePHP - メインの投稿と日付と共有されたタグとの関連性によって投稿を注文しようとしています

モデル:

Tag habtm Post 
Post habtm Tag 

DB:コントローラのアクション内

posts(id, slug, ...) 
tags(id, tag, ...) 
posts_tags(post_id, tag_id) 

$post = $this->Post->find('first', array('conditions' => array('slug' => $slug))); 
$this->set('post', $post); 

$tags = $post['Tag']; 

$relOrd = ''; 
foreach($tags as $tag){ 
    $tagId = $tag['id']; 
    $relOrd .= " + (CASE WHEN PostsTag.tag_id = ".$tagId." THEN 1 ELSE 0 END)"; 
} 
$relOrd = '(' . substr($relOrd, 3) . ') AS Relevance'; 

$morePosts = $this->Post->find('all', array(
    'joins' => array(
     array(
      'table' => 'posts_tags', 
      'alias' => 'PostsTag', 
      'type' => 'LEFT', 
      'conditions' => array(
       'PostsTag.post_id = Post.id', 
      ) 
     ) 
    ), 
    'group' => 'Post.id', 
    'fields' => array($relOrd, 'Post.*'), 
    'order' => array('Relevance' => 'DESC', 'Post.created' => 'DESC'), 
    'limit' => 8, 
)); 
$this->log($morePosts); 
$this->set('morePosts', $morePosts); 

関連性の値は、各投稿に1つのタグ(0または1のみ)があるかのように扱われていますが、ほとんど動作しています。したがって、各タグの関連性値は、すべてのタグに基づいて累積されるのではなく、LASTタグの投稿に応じて0または1のいずれかをとっているようです。

答えて

1

まず、すべてのロジックをコントローラから取り除きます。これを考慮してください:

$post = $this->Post->find('first', array('conditions' => array('slug' => $slug))); 
$this->set('post', $post); 
$this->set('morePosts', $this->Post->findRelevant($post)); 

あなたのコントローラは読みやすいですし、それは仕事です。基本的には、想像上のモデル関数に名前を付けることによって、どのデータを記述するかを記述し、その要求を満たすモデルコードを記述します。だからここ

は、モデルコードで刺します:(あなたがしようとしているとして)それは可能な限り速いよう

var $actsAs = array('Containable'); 

function findRelevant($post, $limit = 8) { 

    // create an array of ids of the tags from this post 
    $tags = array(); 
    foreach($post['Tag'] as $num => $tag) { 
    $tags[$tag['id']] = $tag['id']; 
    } 

    // find other posts that have any of those tags 
    $relevant = $this->find('all', array(
    'conditions' => array('Post.id <>' => $post['Post']['id']), 
    'order' => 'Post.created desc', 
    'contain' => array('Tag' => array('conditions' => array(
     'Tag.id' => $tags 
    ))), 
)); 

    // count the number of tags of each post and call it relevance 
    // (this number is essentially the number of tags in common 
    // with the original post because we used contain to get only 
    // the tags from the original post) 
    foreach($relevant as &$p) { 
    $p['Post']['relevance'] = count($p['Tag']); 
    } 

    // sort by relevance 
    $relevant = Set::sort($relevant, '{n}.Post.relevance', 'desc'); 

    // limit the number of posts returned (defaults to 8) 
    return array_splice($relevant, 0, $limit); 
} 

明らかにレコードをフェッチするために、データベースのロジックを使用するように素晴らしいことだとあなたが取得するデータの量を最小限に抑えることができますが、達成しようとしていることに対してどのように行うのかわかりません。

このメソッドは正常に動作するはずであり、データベース固有のものではありません。 :)

関連する問題