You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
3.1 KiB
105 lines
3.1 KiB
<?php |
|
|
|
declare(strict_types=1); |
|
|
|
namespace App\Service; |
|
|
|
use App\Enum\EventStatusEnum; |
|
use App\Repository\ArticleRepository; |
|
use Doctrine\DBAL\ArrayParameterType; |
|
|
|
/** |
|
* Top topics for the sidebar and topic browse pages. |
|
*/ |
|
final class TopicIndexService |
|
{ |
|
public function __construct( |
|
private readonly ArticleRepository $articleRepository, |
|
private readonly MagazineContentService $magazineContent, |
|
) { |
|
} |
|
|
|
/** |
|
* Most relevant topic strings (default cap 10 in sidebar), scored by count + 5× featured (magazine home cards). |
|
* |
|
* @return list<string> topic labels (lowercase, no #) |
|
*/ |
|
public function getTopTopicLabels(int $limit = 10): array |
|
{ |
|
$conn = $this->articleRepository->getEntityManager()->getConnection(); |
|
$slugs = $this->magazineContent->collectFeaturedArticleSlugsForHome( |
|
$this->magazineContent->getHomeCategoryAIndexTagsFromStoreOnly(), |
|
); |
|
$featured = []; |
|
foreach ($slugs as $s) { |
|
$s = \strtolower(\trim($s)); |
|
if ($s !== '') { |
|
$featured[$s] = true; |
|
} |
|
} |
|
|
|
$rows = $conn->fetchAllAssociative( |
|
'SELECT a.slug, a.topics FROM article a |
|
WHERE a.topics IS NOT NULL |
|
AND a.content IS NOT NULL |
|
AND CHAR_LENGTH(a.content) > 250 |
|
AND a.event_status IN (:st)', |
|
[ |
|
'st' => [EventStatusEnum::PUBLISHED->value, EventStatusEnum::ARCHIVED->value], |
|
], |
|
[ |
|
'st' => ArrayParameterType::INTEGER, |
|
], |
|
); |
|
|
|
$acc = []; |
|
foreach ($rows as $row) { |
|
$raw = $row['topics'] ?? null; |
|
if (\is_array($raw)) { |
|
$dec = $raw; |
|
} elseif (\is_string($raw) && $raw !== '') { |
|
$dec = json_decode($raw, true); |
|
} else { |
|
continue; |
|
} |
|
if (!\is_array($dec)) { |
|
continue; |
|
} |
|
$slug = \strtolower(\trim((string) ($row['slug'] ?? ''))); |
|
$isFeat = $slug !== '' && isset($featured[$slug]); |
|
foreach ($dec as $t) { |
|
if (!\is_string($t) || $t === '') { |
|
continue; |
|
} |
|
$k = \str_replace('#', '', \strtolower(\trim($t))); |
|
if ($k === '') { |
|
continue; |
|
} |
|
if (!isset($acc[$k])) { |
|
$acc[$k] = ['c' => 0, 'f' => 0]; |
|
} |
|
++$acc[$k]['c']; |
|
if ($isFeat) { |
|
++$acc[$k]['f']; |
|
} |
|
} |
|
} |
|
|
|
uasort( |
|
$acc, |
|
static function (array $a, array $b): int { |
|
$sa = $a['c'] + 5 * $a['f']; |
|
$sb = $b['c'] + 5 * $b['f']; |
|
if ($sa === $sb) { |
|
return $b['c'] <=> $a['c']; |
|
} |
|
|
|
return $sb <=> $sa; |
|
} |
|
); |
|
|
|
$keys = array_keys($acc); |
|
|
|
return \array_slice($keys, 0, max(0, $limit)); |
|
} |
|
}
|
|
|