126 lines
3.1 KiB
PHP
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;
|
|
}
|
|
}
|