Orm 在CakePHP中,定义同步的方法在两个模型之间有多个和一个关联?

Orm 在CakePHP中,定义同步的方法在两个模型之间有多个和一个关联?,orm,cakephp,has-many,has-one,Orm,Cakephp,Has Many,Has One,在CakePHP框架中,我长期以来遇到的一个问题是,在两个模型之间同时定义hasOne和hasMany关系。例如: BlogEntry有很多评论 bloggentry有一条MostRecentComment(其中MostRecentComment是带有最近创建的字段的注释) 在BlogEntry模型属性中定义这些关系是有问题的。CakePHP的ORM实现了一个has-one关系作为一个内部连接,因此,只要有多个注释,BlogEntry::find('all')调用就会为每个BlogEntry返回

在CakePHP框架中,我长期以来遇到的一个问题是,在两个模型之间同时定义
hasOne
hasMany
关系。例如:

BlogEntry有很多评论

bloggentry有一条MostRecentComment
(其中
MostRecentComment
是带有最近创建的
字段的
注释

在BlogEntry模型属性中定义这些关系是有问题的。CakePHP的ORM实现了一个has-one关系作为一个
内部连接
,因此,只要有多个注释,
BlogEntry::find('all')
调用就会为每个BlogEntry返回多个结果

我过去曾以几种方式处理过这些情况:

  • 使用模型回调(有时,甚至在控制器或视图中!),我用:
    $this->data['MostRecentComment']=$this->data['Comment'][0]
    如果,比如说,我需要通过
    Comment.created
    以外的任何方式对注释进行排序,这会很快变得难看。它也不会将内置的分页功能用于按MostRecentComment字段排序(例如,按
    MostRecentComment.created
    按逆时间顺序排序博客条目结果)

  • 维护一个额外的外键,
    BlogEntry。最新的评论id
    。这很烦人,并且打破了Cake的ORM:其含义是
    BlogEntry属于最新的评论
    。它可以工作,但看起来……错了

  • 这些解决方案还有很多不尽如人意的地方,所以前几天我坐下来研究这个问题,并制定了一个更好的解决方案。我在下面发布了我的最终解决方案,但我会很激动(也许只是有点尴尬)发现有一个让我大吃一惊的简单解决方案,我一直没有找到。或者任何其他符合我标准的解决方案:

    • 它必须能够在
      Model::find
      级别按MostRecentComment字段进行排序(即,不仅仅是结果信息)
    • 评论
      博客条目
      表中不需要额外的字段
    • 它应该尊重CakePHP ORM的“精神”

    (我也不确定这个问题的标题是否尽可能简洁/信息丰富。)

    我开发的解决方案如下:

    class BlogEntry extends AppModel
    {
        var $hasMany = array( 'Comment' );
    
        function beforeFind( $queryData )
        {
            $this->_bindMostRecentComment();
    
            return $queryData;
        }
    
        function _bindMostRecentComment()
        {
            if ( isset($this->hasOne['MostRecentComment'])) { return; }
    
            $dbo = $this->Comment->getDatasource();
            $subQuery = String::insert("`MostRecentComment`.`id` = (:q)", array(
                'q'=>$dbo->buildStatement(array(
                    'fields' => array( String::insert(':sqInnerComment:eq.:sqid:eq', array('sq'=>$dbo->startQuote, 'eq'=>$dbo->endQuote))),
                    'table'  => $dbo->fullTableName($this->Comment),
                    'alias'  => 'InnerComment',
                    'limit'  => 1,
                    'order'  => array('InnerComment.created'=>'DESC'),
                    'group'  => null,
                    'conditions' => array(
                        'InnerComment.blog_entry_id = BlogEntry.id'
                    )
                ), $this->Comment)
            ));
    
            $this->bindModel(array('hasOne'=>array(
                'MostRecentComment'=>array(
                    'className' => 'Comment',
                    'conditions' => array( $subQuery )
                )
            )),false);
    
            return;
        }
    
        // Other model stuff
    }
    
    概念很简单。
    \u bindMostRecentComment
    方法定义了一个标准,它有一个关联,在关联条件中使用一个子查询,以确保只有最新的注释连接到BlogEntry查询。该方法本身在任何
    模型::find()之前被调用
    calls,每个博客条目的最新评论都可以过滤或排序

    我意识到在
    hasOne
    类成员中定义这种关联是可能的,但我必须编写一堆原始SQL,这让我停顿了一下

    我宁愿从BlogEntry的构造函数调用
    \u bindMostRecentComment
    ,但是(根据文档)使绑定永久化的Model::bindModel()参数似乎不起作用,因此绑定必须在beforeFind回调中完成