optimizations

This commit is contained in:
2026-03-28 19:15:39 +01:00
parent 0b25d9570a
commit cab4fbd83e
509 changed files with 1016804 additions and 1605 deletions

View File

@@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\Collection;
use App\Models\CollectionHistory;
use App\Models\User;
use App\Services\CollectionHealthService;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Validation\ValidationException;
class CollectionHistoryService
{
/**
* @var array<string, array<int, string>>
*/
private const RESTORABLE_FIELDS = [
'updated' => ['title', 'visibility', 'lifecycle_state'],
'workflow_updated' => ['workflow_state', 'program_key', 'partner_key', 'experiment_key', 'placement_eligibility'],
'partner_program_metadata_updated' => ['partner_key', 'trust_tier', 'promotion_tier', 'sponsorship_state', 'ownership_domain', 'commercial_review_state', 'legal_review_state'],
];
public function __construct(
private readonly CollectionHealthService $health,
) {
}
public function record(Collection $collection, ?User $actor, string $actionType, ?string $summary = null, ?array $before = null, ?array $after = null): void
{
CollectionHistory::query()->create([
'collection_id' => $collection->id,
'actor_user_id' => $actor?->id,
'action_type' => $actionType,
'summary' => $summary,
'before_json' => $before,
'after_json' => $after,
'created_at' => now(),
]);
$collection->forceFill([
'history_count' => (int) $collection->history_count + 1,
])->save();
}
public function historyFor(Collection $collection, int $perPage = 40): LengthAwarePaginator
{
return CollectionHistory::query()
->with('actor:id,username,name')
->where('collection_id', $collection->id)
->orderByDesc('created_at')
->paginate(max(10, min($perPage, 80)));
}
public function mapPaginator(LengthAwarePaginator $paginator): array
{
return [
'data' => collect($paginator->items())->map(function (CollectionHistory $entry): array {
$restorableFields = $this->restorablePayload($entry);
return [
'id' => (int) $entry->id,
'action_type' => $entry->action_type,
'summary' => $entry->summary,
'before' => $entry->before_json,
'after' => $entry->after_json,
'can_restore' => $restorableFields !== [],
'restore_fields' => array_keys($restorableFields),
'created_at' => $entry->created_at?->toISOString(),
'actor' => $entry->actor ? [
'id' => (int) $entry->actor->id,
'username' => $entry->actor->username,
'name' => $entry->actor->name,
] : null,
];
})->values()->all(),
'meta' => [
'current_page' => $paginator->currentPage(),
'last_page' => $paginator->lastPage(),
'per_page' => $paginator->perPage(),
'total' => $paginator->total(),
],
];
}
public function canRestore(CollectionHistory $entry): bool
{
return $this->restorablePayload($entry) !== [];
}
public function restore(Collection $collection, CollectionHistory $entry, ?User $actor = null): Collection
{
if ((int) $entry->collection_id !== (int) $collection->id) {
throw ValidationException::withMessages([
'history' => 'This history entry does not belong to the selected collection.',
]);
}
$payload = $this->restorablePayload($entry);
if ($payload === []) {
throw ValidationException::withMessages([
'history' => 'This history entry cannot be restored safely.',
]);
}
$working = $collection->fresh();
$before = [];
foreach (array_keys($payload) as $field) {
$before[$field] = $working->{$field};
}
$working->forceFill($payload);
$healthPayload = $this->health->evaluate($working);
$working->forceFill(array_merge($healthPayload, $payload, [
'last_activity_at' => now(),
]))->save();
$fresh = $working->fresh();
$this->record(
$fresh,
$actor,
'history_restored',
sprintf('Collection restored from history entry #%d.', $entry->id),
array_merge(['restored_history_id' => (int) $entry->id], $before),
array_merge(['restored_history_id' => (int) $entry->id], $payload),
);
return $fresh;
}
/**
* @return array<string, mixed>
*/
private function restorablePayload(CollectionHistory $entry): array
{
$before = is_array($entry->before_json) ? $entry->before_json : [];
$fields = self::RESTORABLE_FIELDS[$entry->action_type] ?? [];
$payload = [];
foreach ($fields as $field) {
if (array_key_exists($field, $before)) {
$payload[$field] = $before[$field];
}
}
return $payload;
}
}