【问题标题】:Show a list of records to have a join to another table using CakePHP使用 CakePHP 显示要连接到另一个表的记录列表
【发布时间】:2012-04-19 19:58:13
【问题描述】:

我有一个存储帖子和主题并使用 Topic_Posts 表连接它们的应用程序。

应用的关联如下:

Post.php
class Post extends AppModel
{
    public $name = 'Post';

    public $belongsTo = 'User';

    public $hasMany = array('Answer');

    // Has many topics that belong to topic post join table... jazz
    public $hasAndBelongsToMany = array(
        'Topic' => array('with' => 'TopicPost')
    );
}

Topic.php
class Topic extends AppModel
{
    public $hasMany = array(
        'TopicPost'
    );
}

TopicPost.php
class TopicPost extends AppModel {
    public $belongsTo = array(
        'Topic', 'Post'
    );
}

当用户查看主题时,例如/topics/view/topicname我要显示所有包含该主题的帖子。

到目前为止,我的 TopicsController 中有以下方法用于视图:

public function view ( $slug )
{
    $topic = $this->Topic->find('first', array('conditions'=>array('Topic.slug'=>$slug)));
    $this->set('topic', $topic);
    $this->set('title_for_layout', $topic['Topic']['title'] . ' – Topics');

    $this->paginate = array
    (
        'Post' => array
        (
            'limit'=>15,
            'conditions'=>array
            (
                'Post.status'=>array(1,2),
                'TopicPost.topic_id' => $topic['Topic']['id'],
            ),
            'order'=>array('Post.datetime'=>'desc'),
            'contain'=>array('User'=>'Profile', 'TopicPost')
        )
    );

    $posts = $this->paginate('Post'); // this one

    $this->set('posts', $posts);

}

所以我可以使用我添加的帖子和主题帖子:public $uses = array('Topic','TopicPost','Post'); 到控制器的顶部,并使所有模型都充当可包含的角色。

所以基本上我需要在数据库模型 TopicPosts 中找到与我正在查看的主题的 id 匹配的帖子。

【问题讨论】:

  • 嘿,很高兴你添加了赏金声望,但这真的让我很烦。它应该工作!你能用一些示例数据发布你的数据库结构的粘贴吗?您拥有的更新代码也会很有用。
  • 此 SQL 将构建 DB pastebin.com/qm72Rz6k,并且我已将 OP 中的代码更新为我现在所拥有的!
  • 另外只是为了注意数据库结构和关系工作正常,因为我可以使用 TopicPost 为帖子提取主题,所以我知道这有效,它只是为似乎不工作的主题获取帖子...
  • 我的答案的另一个更新..祝我好运:P
  • 是的! :) 没有错误。谢谢朋友。

标签: php cakephp cakephp-2.1


【解决方案1】:

我只是无法让它以“正确”的方式工作。我不确定这是否是蛋糕中的错误或其他什么,但 paginate 函数只是拒绝让步。. 正确的方法可能是在 Post 模型中编写自己的 paginate 函数,有一些关于如何在食谱中做到这一点。

同时,我为您提供以下解决方法。它不是最佳的(至少在没有缓存的情况下不是),但它可以工作。当/如果您遇到性能问题时,您可以以正确的方式执行此操作,但在那之前,下面的代码应该可以做到。

public function view ( $slug )
{
    $topic = $this->Topic->find('first', array('conditions'=>array('Topic.slug'=>$slug)));
    $this->set('topic', $topic);
    $this->set('title_for_layout', $topic['Topic']['title'] . ' – Topics');

    // step 1: get post IDs related to your topic
    $postIDs = $this->Topic->TopicPost->find
        (
            'list',
            array
            (
                'fields'        => array('TopicPost.post_id'),
                'conditions'    => array('TopicPost.topic_id' => $topic['Topic']['id'])
            )
        );

    $this->paginate = array
    (
        'Post' => array
        (
            'limit'=>15,
            'conditions'=>array
            (
                'Post.status' => array(1,2),
                // step 2: include them in your paginate conditions
                'Post.id' => $postIDs,
            ),
            'order' => array('Post.datetime'=>'desc'),
        )
    );

    $posts = $this->paginate('Post');

    $this->set('posts', $posts);
}

(请注意,我在测试中删除了一些东西,因为我的应用中没有一些东西,所以别忘了放回去)

【讨论】:

  • Boom 似乎已经修复了这个错误 :) 关于如何获取仅显示连接表中的帖子的部分的任何想法?
  • @Cameron:嗯,忘记了……你在第一个查询中得到你的帖子吗?执行 debug($topic) 时的输出是什么如果您的帖子在那里,您可以执行 Set::extract() 来获取所有帖子 ID,然后将它们添加到您的分页条件中。
  • 嗯,看起来很草率...我不能在TopicPosts中找到与主题相关的帖子吗?
  • @Cameron:我已经更新了帖子,可能会回答您的问题。这样的东西就够了吗?
  • 给我这个错误:Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'TopicPost.topic_id' in 'where clause' 我什至在控制器顶部的 uses var 中添加了 TopicPost 模型,所以不知道还能做什么?
【解决方案2】:

我认为你的模型关系有问题,我不明白为什么你在帖子模型上有 HABTM 关系,而你实际上是在 TopicPost 模型本身上模拟这个 (using the Has-many-through method)。如果你不想使用 cake 内置的 HABTM 行为(我不怪你),你应该像这样设置关系:

class PostTopic extends AppModel { // note PostTopic, name should be alphabetical
    public $belongsTo = array('Post', 'Topic');
}

class Post extends AppModel {
    public $hasMany = array('PostTopic');
}

class Topic extends AppModel {
    public $hasMany = array('PostTopic');
}

然后要获取相关帖子或主题的 ID,您只需加载 PostTopic 类并进行搜索:

// ie in Post Controller
$this->paginate($this->Post->PostTopic, array('PostTopic.topic_id' => $post['PostTopic']['topic_id']));

我的网站上有一个类似的设置,用户可以在其中将产品添加到他们的库存中,这是一种 HABTM 关系,但附加了更多数据。更复杂的example,请参阅此处的产品、库存和用户模型。

【讨论】:

  • 最后一段代码是错误的! topic_id 不是当前帖子的 id!
  • @Cameron 好吧,你应该用正确的变量替换它,它可能是 $post['PostTopic']['topic_id'] 或其他东西。
  • 那么我将如何使用分页来做到这一点?
  • 更新了答案。一旦您了解了蛋糕中的多重关系,这很简单。
  • 好吧,该方法在 TopicsController 而不是 PostsController 中,因为我正在获取我正在查看的主题的帖子,这就是问题所在,因为好像 Cake 甚至无法理解关联尽管它们是正确的。
【解决方案3】:

来自问题评论:

还要注意数据库结构和关系工作正常,因为我 可以使用 TopicPost 拉出帖子的主题,所以我知道 有效,它只是为似乎不是的主题获取帖子 工作...

正确,因为您为 Post->Topic 设置了 HABTM,但没有为 Topic->Post 设置。 2.0 书定义了一个与您的示例类似的示例(但使用配方和成分)来描述用例。

hasMany 和 HABTM 之间的主要区别在于 HABTM 中的模型不是唯一的。例如,我们即将加入 我们的配方模型和成分模型使用了 HABTM。使用西红柿 作为我奶奶意大利面食谱的配料不会“用完” 成分。我也可以用它来做沙拉食谱。

对于使用Topic(标签/类别的名称)的Post 也可以这样说。就像他们的例子一样:

请记住在成分模型中定义一个 HABTM 关联,​​如果 您希望在使用成分模型时获取配方数据。

或者,在您的情况下,主题模型。

以下是您应该使用的模型:

class Post extends AppModel
{
    public $name = 'Post';

    public $belongsTo = 'User';

    public $hasMany = array('Answer');

    // Has many topics that belong to topic post join table... jazz
    public $hasAndBelongsToMany = array(
        'Topic' => array('with' => 'TopicPost')
    );
}

class Topic extends AppModel
{
    // Has many posts that belong to topic post join table... jazz
    public $hasAndBelongsToMany = array(
        'Post' => array('with' => 'TopicPost')
    );
}

现在,你真的不需要TopicPost,除非你正在做一些特别的事情,但这很好。而且,尽管您可以使用该模型将Topics 添加到帖子中(反之亦然),但我建议您使用处理HABTM 保存的内置方法。查看this page 了解保存HABTM 的详细信息。

如果您决定删除它,请确保为每个模型中的 HABTM 选项定义连接表和条件per the docs

【讨论】:

  • 更新了我的模型,让它看起来像你的,但我仍然得到和以前一样的错误!
  • @Cameron 什么错误?您没有通过Topic->find() 获得TopicPosts?
猜你喜欢
  • 1970-01-01
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
  • 2017-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多