Collapse profile group contribution queries

This commit is contained in:
2026-08-30 07:58:38 +02:00
parent dba1f73e01
commit 7805baa17d
2 changed files with 256 additions and 30 deletions
@@ -0,0 +1,170 @@
<?php
declare(strict_types=1);
use App\Http\Controllers\User\ProfileController;
use App\Models\Group;
use App\Models\GroupContributorStat;
use App\Models\GroupMember;
use App\Models\GroupProject;
use App\Models\GroupProjectMember;
use App\Models\GroupRelease;
use App\Models\GroupReleaseContributor;
use App\Models\User;
use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\DB;
function invokeGroupContributionHistory(User $user): array
{
$method = new ReflectionMethod(ProfileController::class, 'buildGroupContributionHistory');
$method->setAccessible(true);
return $method->invoke(app(ProfileController::class), $user);
}
function makeGroupRelease(Group $group, User $creator, string $title, CarbonImmutable $releasedAt, string $visibility = GroupRelease::VISIBILITY_PUBLIC): GroupRelease
{
return GroupRelease::create([
'group_id' => $group->id,
'title' => $title,
'slug' => strtolower(str_replace(' ', '-', $title)) . '-' . uniqid(),
'status' => GroupRelease::STATUS_RELEASED,
'current_stage' => GroupRelease::STAGE_RELEASED,
'visibility' => $visibility,
'released_at' => $releasedAt,
'published_at' => $releasedAt,
'created_by_user_id' => $creator->id,
]);
}
it('preserves contribution output semantics while loading group data in bulk', function (): void {
$user = User::factory()->create();
$owner = User::factory()->create();
$group = Group::factory()->create([
'owner_user_id' => $owner->id,
'name' => 'Visible Contribution Group',
'slug' => 'visible-contribution-group-' . uniqid(),
]);
GroupContributorStat::create([
'group_id' => $group->id,
'user_id' => $user->id,
'credited_artworks_count' => 7,
'release_count' => 5,
'project_count' => 3,
'review_actions_count' => 2,
]);
GroupMember::create([
'group_id' => $group->id,
'user_id' => $user->id,
'role' => Group::ROLE_EDITOR,
'status' => Group::STATUS_ACTIVE,
]);
$project = GroupProject::create([
'group_id' => $group->id,
'title' => 'Visible Project',
'slug' => 'visible-project-' . uniqid(),
'status' => GroupProject::STATUS_ACTIVE,
'visibility' => GroupProject::VISIBILITY_PUBLIC,
'created_by_user_id' => $owner->id,
]);
GroupProjectMember::create([
'group_project_id' => $project->id,
'user_id' => $user->id,
'role_label' => 'Project Lead',
'is_lead' => true,
]);
$newest = makeGroupRelease($group, $user, 'Newest Release', CarbonImmutable::parse('2026-08-20 12:00:00'));
$middle = makeGroupRelease($group, $owner, 'Middle Release', CarbonImmutable::parse('2026-08-19 12:00:00'));
$oldest = makeGroupRelease($group, $owner, 'Oldest Release', CarbonImmutable::parse('2026-08-18 12:00:00'));
makeGroupRelease($group, $owner, 'Hidden Release', CarbonImmutable::parse('2026-08-21 12:00:00'), GroupRelease::VISIBILITY_PRIVATE);
GroupReleaseContributor::create([
'group_release_id' => $middle->id,
'user_id' => $user->id,
'role_label' => 'Release Contributor',
'sort_order' => 0,
]);
GroupReleaseContributor::create([
'group_release_id' => $oldest->id,
'user_id' => $user->id,
'role_label' => 'Project Lead',
'sort_order' => 1,
]);
$result = invokeGroupContributionHistory($user);
expect($result)->toHaveCount(1);
expect($result[0]['group'])->toMatchArray([
'id' => $group->id,
'name' => 'Visible Contribution Group',
'slug' => $group->slug,
]);
expect($result[0]['joined_at'])->toBeString();
expect($result[0]['counts'])->toBe([
'credited_artworks' => 7,
'releases' => 5,
'projects' => 3,
'review_actions' => 2,
]);
expect($result[0]['role_labels'])->toBe(['Release Contributor', 'Project Lead']);
expect($result[0]['recent_release_titles'])->toBe(['Newest Release', 'Middle Release', 'Oldest Release']);
expect($result[0]['role'])->toBe(Group::ROLE_EDITOR);
expect($result[0]['trusted_indicator'])->toBeFalse();
});
it('keeps public visibility filtering and owner role semantics', function (): void {
$user = User::factory()->create();
$ownerGroup = Group::factory()->create([
'owner_user_id' => $user->id,
'slug' => 'owner-contribution-group-' . uniqid(),
]);
$privateGroup = Group::factory()->private()->create([
'slug' => 'private-contribution-group-' . uniqid(),
]);
GroupContributorStat::create(['group_id' => $ownerGroup->id, 'user_id' => $user->id]);
GroupContributorStat::create(['group_id' => $privateGroup->id, 'user_id' => $user->id, 'release_count' => 99]);
$result = invokeGroupContributionHistory($user);
expect($result)->toHaveCount(1)
->and($result[0]['group']['id'])->toBe($ownerGroup->id)
->and($result[0]['role'])->toBe(Group::ROLE_OWNER)
->and($result[0]['joined_at'])->toBeString();
});
it('keeps contribution-history query count bounded as group count grows', function (): void {
$counts = [];
foreach ([0, 1, 2, 4, 8] as $groupCount) {
$user = User::factory()->create();
for ($index = 0; $index < $groupCount; $index++) {
$group = Group::factory()->create([
'slug' => 'query-count-group-' . $groupCount . '-' . $index . '-' . uniqid(),
]);
GroupContributorStat::create([
'group_id' => $group->id,
'user_id' => $user->id,
'credited_artworks_count' => $groupCount - $index,
'release_count' => $groupCount - $index,
]);
}
DB::flushQueryLog();
DB::enableQueryLog();
invokeGroupContributionHistory($user);
$counts[$groupCount] = count(DB::getQueryLog());
DB::disableQueryLog();
}
expect($counts)->toBe([
0 => 1,
1 => 8,
2 => 8,
4 => 8,
8 => 8,
]);
});