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

CakePHP 3 CounterCache - don't start counting with 0

我正在尝试将基于 IP 的投票系统迁移到基于登录用户的投票系统,并希望保留旧的 votes/likes。所以我将旧系统 like_count 复制到我的引号 table.

的专栏中

引用table

票 table

我根据投票 table 中的投票在引号 table 中为 like_count 实现了反缓存行为。但是,例如,如果我现在将 ID 为 145 的引用投票,like_count 将跳转到 1 而不是 3616,因为在投票 table.[=12= 中只有 1 票用于引用 ID 145 ]

那么 CounterCache 行为是否可以考虑 like_count 列并从那里开始而不是从 0 开始?

您必须自己考虑,没有针对这种情况的开箱即用功能。

我建议将旧投票存储在单独的列中,比如 legacy_like_count,然后在读取数据时计算新旧投票的总和 votes/likes,就这样手动,或者例如使用虚拟 属性,例如:

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

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

另见