CakePHP 3 CounterCache - 不要以0开始计数

时间:2018-01-09 13:49:38

标签: cakephp cakephp-3.0 counter-cache

我正在尝试将基于IP的投票系统迁移到基于用户的登录投票系统,并希望保留旧的投票/喜欢。所以我将旧系统like_count复制到我的引号表中的一列中。

引用表

enter image description here

投票表

votes

我根据投票表中的投票,在引号表中为like_count实现了反向缓存行为。但是,例如,如果我现在将id为145的报价投票,那么like_count将跳转到1而不是3616,因为在投票表中只有1票对报价id 145。

那么CounterCache行为是否有一种方法可以考虑到like_count列并从那里开始而不是从0开始?

1 个答案:

答案 0 :(得分:1)

你必须自己解决这个问题,这种情况没有开箱即用的功能。

我建议将旧投票存储在一个单独的列中,比如legacy_like_count,然后在您读取数据时计算新旧投票/喜欢的总和,手动或者为使用虚拟属性的示例,如:

protected $_virtual = ['total_like_count'];

public function _getTotalLikeCount() {
    return $this->_properties['like_count'] + $this->_properties['legacy_like_count'];
}

或者如果您想要存储在数据库中的总计数,请使用计数器缓存行为支持的回调功能,您可以在其中构建计算新投票的自定义查询,并添加旧的喜欢数量,例如:

[
    'Quotes' => [
        'like_count' => function (
            \Cake\Event\Event $event,
            \Cake\Datasource\EntityInterface $entity,
            \Cake\ORM\Table $table
        ) {
            // $event = Model.afterSave or Model.afterDelete (VotesTable)
            // $entity = Vote 
            // $table = VotesTable

            $votes = $table
                ->find()
                ->where([
                    'Votes.quote_id' => $entity->get('quote_id')
                ])
                ->count();

            $quote = $table->Quotes->get($entity->get('quote_id'));

            return $votes + $quote->get('legacy_like_count');
         }
    ]
]

您可能也可以在SQL级别上进行计算,类似于以下内容:

$query = $table->Quotes->find();
return $query
    ->select([
        'totalVotes' => $query
            ->newExpr()
            ->add([
                'Quotes.legacy_like_count',
                $query->func()->count('Votes.id')
            ])
            ->setConjunction('+') // use tieWith() in CakePHP < 3.4
    ])
    ->leftJoinWith('Votes')
    ->where([
        'Quotes.id' => $entity->get('quote_id')
    ])
    ->groupBy('Quotes.id');

会产生类似于以下内容的SQL,如果在示例中返回,则会在like_count列的更新过程中用作子查询:

SELECT
    (Quotes.legacy_like_count + COUNT(Votes.id)) AS totalVotes
FROM
    quotes Quotes
LEFT JOIN
    votes Votes ON Quotes.id = Votes.quote_id
WHERE
    Quotes.id = :c0
GROUP BY
    Quotes.id

请注意,这是所有未经测试的示例代码!

另见