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
请注意,这是所有未经测试的示例代码!
另见
我正在尝试将基于 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
请注意,这是所有未经测试的示例代码!
另见