romanzipp/laravel-projectable-aggregates

Laravel 项目聚合

0.0.2 2024-08-11 07:27 UTC

This package is auto-updated.

Last update: 2024-09-11 07:37:33 UTC


README

Latest Stable Version Total Downloads License GitHub Build Status

是什么

Laravel Projectable Aggregates 是一个包,允许您轻松地在模型中存储聚合值,如计数、总和、平均值等,从而消除在运行时计算这些值的需要(使用 withCountwithSumwithAvg 等)。

  • 通过在数据库中存储聚合值来 加速数据库查询
  • 使用 模型事件 自动更新 聚合值。
  • 可以选择 定期批量 计算聚合值。

安装

composer require romanzipp/laravel-projectable-aggregates

术语

🟢 消费者

消费者持有可投影聚合数据库字段。这是否则会通过 withCountwithSumwithAvg 等计算关系字段的模式。

🔵 提供者

提供模型提供(当然)给消费者的聚合值。想象一下,对于单个消费者,提供者可以存在多次。

用法

让我们继续以一个具有 Door 模型的 Car 模型为例。我们希望将门数存储在汽车的 project_doors_count 字段中。

1. 在数据库中添加投影字段

new class() extends Migration
{
    public function up()
    {
        Schema::create('cars', function (Blueprint $table) {
            $table->id();
            $table->unsignedInteger('project_doors_count')->default(0);
        });
    }
}

2. 更新您的模型

🟢 汽车(消费者)

消费者模型将向提供者关系附加 ConsumesProjectableAggregate 属性。

use romanzipp\ProjectableAggregates\Attributes\ConsumesProjectableAggregate;
use romanzipp\ProjectableAggregates\ProjectionAggregateType;

class Car extends Model
{
    #[ConsumesProjectableAggregate(
        projectionAttribute: 'project_doors_count',   // <- Name of the projection field in the database
        projectionType: ProjectionAggregateType::TYPE_COUNT
    )]
    public function doors(): HasMany
    {
        return $this->hasMany(Door::class);
    }
}

🔵 门(提供者)

提供者模型将向消费者关系附加 ProvidesProjectableAggregate 属性。

use romanzipp\ProjectableAggregates\Attributes\ProvidesProjectableAggregate;
use romanzipp\ProjectableAggregates\ProjectionAggregateType;

class Door extends Model
{
    #[ProvidesProjectableAggregate(
        projectionAttribute: 'project_doors_count',   // <- Name of the FOREIGN projection field in the database
        projectionType: ProjectionAggregateType::TYPE_COUNT
    )]
    public function car(): BelongsTo
    {
        return $this->belongsTo(Car::class);
    }
}

3. 注册投影聚合

为了监听提供者模型发出的模型事件,您需要在您的 AppServiceProviderboot 方法中注册消费者模型。

use romanzipp\ProjectableAggregates\ProjectableAggregateRegistry;

class AppServiceProvider extends ServiceProvider
{
    public function boot(ProjectableAggregateRegistry $registry)
    {
        $registry->registerConsumers([
            Car::class,
        ]);

        $registry->registerProviders([
            Door::class,
        ]);
    }
}

文档

重要

计算聚合值(无批量)依赖于 Elouent 模型事件,这些事件仅在直接使用 Eloquent 模型本身时才会发出。使用 DB 门面将 不会触发 库更新聚合值。

聚合类型

可以计算三种类型的聚合

  • ProjectionAggregateType::TYPE_COUNT:计算相关模型的数量。
  • ProjectionAggregateType::TYPE_SUM:计算相关模型的值的总和。
  • ProjectionAggregateType::TYPE_AVG:计算相关模型的值的平均值。

重要

为了使用聚合类型 TYPE_SUMTYPE_AVG,您需要指定关系的目标属性。

#[ProvidesProjectableAggregate(
    projectionAttribute: 'project_price_average',
    projectionType: ProjectionAggregateType::TYPE_AVG,
    targetAttribute: 'price',                          // <- Attribute of the related model to average/sum up
)]

触发器

您可以选择只依赖于 模型事件,或者如果您想定期批量计算聚合值。

依赖于模型事件

如果您的提供者关系附加了 ProvidesProjectableAggregate 属性,这将自动工作。一旦创建或删除提供者模型,相应的消费者聚合属性将递增或递减。

定期批量计算

如果您不想或不能依赖于模型事件,您可以使用 bulk-aggregate 命令定期批量计算聚合值。

php artisan aggregates:bulk-aggregate {--queued} {--queue=} {--class=}
  • --queued:向工作队列发送作业。
  • --queue=:指定运行命令的队列。
  • --class=:将批量计算限制为特定的消费者类。

关系

以下关系得到了支持和测试

Provider::belongsTo() <-> Consumer::hasMany()

  • ✅ 模型事件
  • ✅ 批量聚合

Provider::hasOneThrough() <-> Pivot <-> Consumer::hasManyThrough() ⚠️ 进行中

  • ❌ 模型事件
  • ✅ 批量聚合

Provider::morphTo() <-> Consumer::morphMany()

  • ✅ 模型事件
  • ✅ 批量聚合

测试

此存储库包含一个可用于在本地机器上运行测试的 Lando 配置文件。

lando start
lando phpunit

许可

MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件