PromptVault/app/Services/PromptService.php
2026-10-26 15:12:16 -05:00

126 lines
3.1 KiB
PHP

<?php
namespace App\Services;
use App\Actions\Prompts\StorePrompt;
use App\Actions\Prompts\UpdatePrompt;
use App\Models\Prompt;
use App\Models\Tag;
use Illuminate\Support\Facades\DB;
/**
* Write side of the prompt domain (commands).
*/
class PromptService
{
public function store(StorePrompt $command): Prompt
{
return DB::transaction(function () use ($command) {
$prompt = Prompt::query()->create([
'name' => $command->name,
'description' => $command->description,
'body' => $command->body,
]);
$prompt->tags()->sync($this->tagIds($command->tags));
return $prompt;
});
}
public function update(UpdatePrompt $command, Prompt $prompt): Prompt
{
return DB::transaction(function () use ($command, $prompt) {
$prompt->forceFill([
'name' => $command->name,
'description' => $command->description,
'body' => $command->body,
])->save();
$prompt->tags()->sync($this->tagIds($command->tags));
return $prompt;
});
}
public function delete(Prompt $prompt): void
{
$prompt->delete();
}
public function duplicate(Prompt $prompt): Prompt
{
return DB::transaction(function () use ($prompt) {
// Stats reset to their column defaults (favorite off, usage 0, never used).
$copy = Prompt::query()->create([
'name' => $this->uniqueCopyName($prompt->name),
'description' => $prompt->description,
'body' => $prompt->body,
]);
$copy->tags()->sync($prompt->tags->pluck('id')->all());
return $copy;
});
}
public function toggleFavorite(Prompt $prompt): Prompt
{
$prompt->forceFill(['is_favorite' => ! $prompt->is_favorite])->save();
return $prompt;
}
public function recordUsage(Prompt $prompt): Prompt
{
$prompt->forceFill([
'usage_count' => $prompt->usage_count + 1,
'last_used_at' => now(),
])->save();
return $prompt;
}
/**
* Normalize tag names (trim, lowercase, dedupe, drop empties) and
* resolve them to existing-or-created tag IDs.
*
* @param list<string> $names
* @return list<int>
*/
private function tagIds(array $names): array
{
$uniqueNames = [];
foreach ($names as $name) {
$name = strtolower(trim((string) $name));
if ($name !== '') {
$uniqueNames[$name] = true;
}
}
$ids = [];
foreach (array_keys($uniqueNames) as $name) {
$tag = Tag::query()->firstOrCreate(['name' => $name]);
$ids[] = $tag->id;
}
return $ids;
}
private function uniqueCopyName(string $name): string
{
$candidate = $name.' (copy)';
$guard = 0;
while (Prompt::query()->where('name', $candidate)->exists() && $guard < 50) {
$candidate .= ' (copy)';
$guard++;
}
return $candidate;
}
}