如何在 CakePhp 索引中添加相关记录的计数


How do I add a count of related records in CakePhp index

我正在开发一个应用程序,为一个青年团体存储记录。

这个青年团体有一个徽章系统供成员实现,我有以下表格;

成员徽章member_badges

前两个表是不言自明的,成员是青年团体成员,徽章是徽章的名称,例如。野外工艺、救生、急救等。

member_badges记录成员的成就,并将具有member_id、badge_id、尝试日期和状态(通过或失败)。我们记录失败的尝试,因为它将帮助我们衡量课程的有效性 - 通过率等。

我想创建一个包含以下数据的表;

徽章 |尝试次数 |通票 |失败

我创建了一个徽章控制器函数,如下所示;

public function badgereportsummary() {
    $paginate = array(
        'contain' => array('MemberBadge'));
    $this->Paginator->settings = $paginate;
    $this->set('badges', $this->paginate());
}

现在这以一种方式工作 - 它返回一个徽章数组,每个徽章都包含一个成员徽章数组,我有一个粗略且准备好的页面工作,在视图中使用以下内容

echo h(count($badge['MemberBadge']));

但是 - 这将不允许我在此字段上进行排序,并且将来我还想添加限制日期范围的功能,例如"显示从 1/1/15 到 30/3/15 尝试的急救徽章计数"。我在网上看到了一些关于使用 counterCache 的建议(我已经在应用程序的其他地方使用了它),但这不允许我计算日期范围等的计数。

我想我想的是

将特定页面上的会员徽章计数添加为控制器中的虚拟字段。我一直在搜索文档和谷歌,整天在键盘上敲打我的头,无法解决。非常感谢有关如何实现这一目标的任何建议。

您的摘要报告(徽章 |尝试次数 |通票 |失败)看起来它需要一个 SQL 语句,例如:

SELECT badge.description AS Badge
  , COUNT(*) AS NumberOfAttempts
  , SUM(IF(member_badges.status = 'Fail',0,1)) AS Fails 
  , SUM(IF(member_badges.status = 'Pass',0,1)) AS Passes 
FROM member_badges
JOIN badges ON badges.id = member_badges.badge_id
WHERE member_badges.date_of_attempt BETWEEN '20140101' AND '20140131'
GROUP BY badge.description
ORDER BY NumberOfAttempts DESC;

然后,我将更改您的徽章报告摘要方法来生成此SQL,这相对简单。

  1. 将函数从徽章控制器模型移动到成员徽章模型
  2. 在方法 -> 中为新列名创建虚拟字段
    1. $this->MemberBadge->virtualFields['NumberOfAttempts'] = 0;
    2. $this->MemberBadge->virtualFields['Fails'] = 0;
    3. $this->MemberBadge->virtualFields['Passes'] = 0;
  3. 写下发现:

代码示例

$fields = array('Badge.description'
                ,'COUNT(*) AS MemberBadge__NumberOfAttempts'
                ,'SUM(IF(MemberBadge.status = 'Fail',0,1)) AS MemberBadge__Fails' 
                ,'SUM(IF(MemberBadge.status = 'Pass',0,1)) AS MemberBadge__Passes');
return $this->find('all'
       ,'conditions' => array('MemberBadge.date_of_attempt BETWEEN ? AND ?' => array($start_date,$end_date)
       ,'fields' => $fields
       ,'order' => array('NumberOfAttempts DESC')
       ,'group' => array('Badge.description'));

然后在任何徽章控制器方法中调用$this->Badge->MemberBadge-> badgereportsummary($start_date, $end_date)

我不会使用永久虚场(即在模型中定义虚场),因为这是一个聚合函数。另外,出于您的确切原因,我不会使用 counterCache - 需要根据另一个字段过滤结果。