Files
moonwell-web/app/Services/LoginScreenNewsService.php
T

118 lines
3.6 KiB
PHP

<?php
namespace App\Services;
use App\Models\GameAccountUser;
use App\Models\LoginScreenNews;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
class LoginScreenNewsService
{
public const FEED_HEADER = 'SERVERALERT:';
public const SECTION_SEPARATOR = '----------------------------------------------------------';
public const EMPTY_MESSAGE = '|cFFB7C1CFСкоро здесь появятся новости сервера.|r';
/**
* @return \Illuminate\Support\Collection<int, \App\Models\LoginScreenNews>
*/
public function listForAdmin(): Collection
{
return LoginScreenNews::query()
->ordered()
->get();
}
/**
* @return array{total: int, published: int, draft: int}
*/
public function stats(): array
{
$total = LoginScreenNews::query()->count();
$published = LoginScreenNews::query()->published()->count();
return [
'total' => $total,
'published' => $published,
'draft' => $total - $published,
];
}
/**
* @param array{title: string, body: string, sort_order: int, is_published?: bool} $attributes
*/
public function create(array $attributes, ?GameAccountUser $actor): LoginScreenNews
{
return LoginScreenNews::query()->create([
...$this->normalizeAttributes($attributes),
'created_by_account_id' => $actor?->id,
'created_by_username' => $actor?->username,
'updated_by_account_id' => $actor?->id,
'updated_by_username' => $actor?->username,
]);
}
/**
* @param array{title: string, body: string, sort_order: int, is_published?: bool} $attributes
*/
public function update(LoginScreenNews $newsItem, array $attributes, ?GameAccountUser $actor): LoginScreenNews
{
$newsItem->forceFill([
...$this->normalizeAttributes($attributes),
'updated_by_account_id' => $actor?->id,
'updated_by_username' => $actor?->username,
])->save();
return $newsItem->refresh();
}
public function delete(LoginScreenNews $newsItem): void
{
$newsItem->delete();
}
public function renderFeed(): string
{
$sections = LoginScreenNews::query()
->published()
->ordered()
->pluck('body')
->map(fn (mixed $body): string => $this->normalizeBody((string) $body))
->filter(fn (string $body): bool => $body !== '')
->values();
$payload = $sections->isNotEmpty()
? $sections->implode("\n".self::SECTION_SEPARATOR."\n")
: self::EMPTY_MESSAGE;
return self::FEED_HEADER."\n\n".$payload."\n";
}
/**
* @param array{title: string, body: string, sort_order: int, is_published?: bool} $attributes
* @return array{title: string, body: string, sort_order: int, is_published: bool}
*/
private function normalizeAttributes(array $attributes): array
{
return [
'title' => trim($attributes['title']),
'body' => $this->normalizeBody($attributes['body']),
'sort_order' => (int) $attributes['sort_order'],
'is_published' => (bool) ($attributes['is_published'] ?? false),
];
}
private function normalizeBody(string $body): string
{
$normalized = trim(str_replace(["\r\n", "\r"], "\n", $body));
if (Str::startsWith($normalized, self::FEED_HEADER)) {
$normalized = trim(Str::after($normalized, self::FEED_HEADER));
}
return $normalized;
}
}