计数器缓存

class Cake\ORM\Behavior\CounterCacheBehavior

很多时候,Web 应用程序需要显示相关对象的计数。例如,在显示文章列表时,您可能想要显示每篇文章有多少评论。或者在显示用户时,您可能想要显示她有多少朋友/关注者。计数器缓存行为适用于这种情况。计数器缓存将在调用它时更新关联模型中分配的选项字段。这些字段应该存在于数据库中,并且类型为 INT。

基本用法

您像其他行为一样启用计数器缓存行为,但它不会做任何事情,直到您配置一些关系和每个关系上应该存储的字段计数。使用下面的示例,我们可以使用以下方法为每篇文章缓存评论计数

class CommentsTable extends Table
{
    public function initialize(array $config): void
    {
        $this->addBehavior('CounterCache', [
            'Articles' => ['comment_count']
        ]);
    }
}

注意

comment_count 应该存在于 articles 表中。

计数器缓存配置应该是一个关系名称和该关系的特定配置的映射。

如您所见,您需要在您实际想要更新字段的关联的“另一端”添加行为。在这个示例中,行为被添加到 CommentsTable,即使它更新了 ArticlesTable 中的 comment_count 字段。

计数器的值将在每次保存或删除实体时更新。计数器不会在以下情况下更新

  • 在不更改数据的情况下保存实体,或

  • 使用 updateAll(),或

  • 使用 deleteAll(),或

  • 执行您编写的 SQL 代码

高级用法

如果您需要为少于所有相关记录的记录保留缓存的计数器,您可以提供其他条件或查找器方法来生成计数器值

// Use a specific find method.
// In this case find(published)
$this->addBehavior('CounterCache', [
    'Articles' => [
        'comment_count' => [
            'finder' => 'published',
        ],
    ],
]);

如果您没有自定义查找器方法,您可以提供一个条件数组来查找记录

$this->addBehavior('CounterCache', [
    'Articles' => [
        'comment_count' => [
            'conditions' => ['Comments.spam' => false],
        ],
    ],
]);

如果您希望计数器缓存更新多个字段,例如同时显示条件计数和基本计数,您可以在数组中添加这些字段

$this->addBehavior('CounterCache', [
    'Articles' => ['comment_count',
        'published_comment_count' => [
            'finder' => 'published',
        ],
    ],
]);

如果您希望自己计算计数器缓存字段值,您可以将 ignoreDirty 选项设置为 true。这将防止在您之前将其设置为脏状态时重新计算该字段

$this->addBehavior('CounterCache', [
    'Articles' => [
        'comment_count' => [
            'ignoreDirty' => true,
        ],
    ],
]);

最后,如果自定义查找器和条件不适合,您可以提供一个回调函数。您的函数必须返回要存储的计数值

$this->addBehavior('CounterCache', [
    'Articles' => [
        'rating_avg' => function ($event, $entity, $table, $original) {
            return 4.5;
        }
    ],
]);

您的函数可以返回 false 以跳过更新计数器列,或者返回一个生成计数值的 SelectQuery 对象。如果您返回一个 SelectQuery 对象,您的查询将用作更新语句中的子查询。 $table 参数是指向包含行为的表对象的(而不是目标关系的),以方便起见。回调至少调用一次,其中 $original 设置为 false。如果实体更新更改了关联,则回调将调用第二次,其中 true,然后返回值将更新先前关联项目的计数器。

注意

计数器缓存行为仅适用于 belongsTo 关联。例如,对于“评论属于文章”,您需要将计数器缓存行为添加到 CommentsTable 以生成文章表的 comment_count

版本 5.1.2 中更改: 从 CakePHP 5.1.2 开始,计数器缓存值使用单个查询(使用子查询)来更新,而不是使用单独的查询来获取计数和更新记录。如果需要,您可以通过在配置中将 useSubQuery 键设置为 false 来禁用子查询的使用 [‘Articles’ => [‘comment_count’ => [‘useSubQuery’ => false]]

多对多关系用法

可以在 belongsToMany 关联中使用计数器缓存行为。首先,您需要将 throughcascadeCallbacks 选项添加到 belongsToMany 关联

'through'          => 'CommentsArticles',
'cascadeCallbacks' => true

另请参阅 使用“through”选项 如何配置自定义联接表。

CommentsArticles 是联接表类名。如果您没有它,您应该使用 bake CLI 工具创建它。

然后,在 src/Model/Table/CommentsArticlesTable.php 中,您需要使用与上面描述相同的代码添加行为。

$this->addBehavior('CounterCache', [
    'Articles' => ['comments_count'],
]);

最后,使用 bin/cake cache clear_all 清除所有缓存,然后试用。