documentation and env changes
This commit is contained in:
1 parent
f77f3a9e40
commit
d52eb6bd81
59 files changed
+932
-565
No files matched your search
@@ -18,10 +18,10 @@ use Psr\Log\LoggerInterface;
|
||||
class AlbumSearchService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly SpotifyClient $spotify,
|
||||
private readonly SpotifyClient $spotifyClient,
|
||||
private readonly AlbumRepository $albumRepository,
|
||||
private readonly ReviewRepository $reviewRepository,
|
||||
private readonly EntityManagerInterface $em,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly SpotifyGenreResolver $genreResolver,
|
||||
) {
|
||||
@@ -33,12 +33,12 @@ class AlbumSearchService
|
||||
*/
|
||||
public function search(AlbumSearchCriteria $criteria): AlbumSearchResult
|
||||
{
|
||||
$spotifyQuery = $this->buildSpotifyQuery($criteria);
|
||||
$spotifyQuery = $this->buildSpotifySearchQuery($criteria);
|
||||
$hasUserFilters = $this->hasUserFilters($criteria, $spotifyQuery);
|
||||
// Spotify only gets pinged when callers explicitly enable it and we actually have
|
||||
// something to ask for (bare "all" requests would otherwise waste API calls).
|
||||
$shouldQuerySpotify = $criteria->useSpotify()
|
||||
&& ($spotifyQuery !== '' || $criteria->getGenre() !== '' || $criteria->source === 'spotify');
|
||||
$shouldQuerySpotify = $criteria->shouldUseSpotify()
|
||||
&& ($spotifyQuery !== '' || $criteria->genre !== '' || $criteria->source === 'spotify');
|
||||
|
||||
$stats = [];
|
||||
$savedIds = [];
|
||||
@@ -53,7 +53,7 @@ class AlbumSearchService
|
||||
$savedIds = $this->mergeSavedIds($savedIds, $spotifyData['savedIds']);
|
||||
}
|
||||
|
||||
if ($criteria->useUser() && $hasUserFilters) {
|
||||
if ($criteria->shouldUseUserCatalog() && $hasUserFilters) {
|
||||
// Skip the user query unless at least one meaningful filter is present.
|
||||
$userData = $this->resolveUserAlbums($criteria);
|
||||
$userPayloads = $userData['payloads'];
|
||||
@@ -64,11 +64,19 @@ class AlbumSearchService
|
||||
|
||||
return new AlbumSearchResult($criteria, $albums, $stats, $savedIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether Spotify credentials are configured.
|
||||
*/
|
||||
public function isSpotifyConfigured(): bool
|
||||
{
|
||||
return $this->spotifyClient->isConfigured();
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns structured filters into Spotify's free-form query syntax.
|
||||
*/
|
||||
private function buildSpotifyQuery(AlbumSearchCriteria $criteria): string
|
||||
private function buildSpotifySearchQuery(AlbumSearchCriteria $criteria): string
|
||||
{
|
||||
$parts = [];
|
||||
if ($criteria->albumName !== '') {
|
||||
@@ -105,7 +113,7 @@ class AlbumSearchService
|
||||
return $spotifyQuery !== ''
|
||||
|| $criteria->albumName !== ''
|
||||
|| $criteria->artist !== ''
|
||||
|| $criteria->getGenre() !== ''
|
||||
|| $criteria->genre !== ''
|
||||
|| $criteria->yearFrom !== null
|
||||
|| $criteria->yearTo !== null;
|
||||
}
|
||||
@@ -117,22 +125,22 @@ class AlbumSearchService
|
||||
*/
|
||||
private function resolveSpotifyAlbums(AlbumSearchCriteria $criteria, string $spotifyQuery): array
|
||||
{
|
||||
$stored = $this->albumRepository->searchSpotifyAlbums(
|
||||
$storedSpotifyAlbums = $this->albumRepository->searchSpotifyAlbums(
|
||||
$criteria->query,
|
||||
$criteria->albumName,
|
||||
$criteria->artist,
|
||||
$criteria->getGenre(),
|
||||
$criteria->genre,
|
||||
$criteria->yearFrom ?? 0,
|
||||
$criteria->yearTo ?? 0,
|
||||
$criteria->limit
|
||||
);
|
||||
$storedPayloads = array_map(static fn(Album $album) => $album->toTemplateArray(), $stored);
|
||||
$storedPayloads = $this->filterPayloadsByGenre($storedPayloads, $criteria->getGenre());
|
||||
$storedIds = $this->collectSpotifyIds($stored);
|
||||
$storedPayloads = array_map(static fn(Album $album) => $album->toTemplateArray(), $storedSpotifyAlbums);
|
||||
$storedPayloads = $this->filterPayloadsByGenre($storedPayloads, $criteria->genre);
|
||||
$storedIds = $this->collectSpotifyIds($storedSpotifyAlbums);
|
||||
$stats = $storedIds ? $this->reviewRepository->getAggregatesForAlbumIds($storedIds) : [];
|
||||
$savedIds = $storedIds;
|
||||
|
||||
$shouldFetchFromSpotify = $spotifyQuery !== '' && count($stored) < $criteria->limit;
|
||||
$shouldFetchFromSpotify = $spotifyQuery !== '' && count($storedSpotifyAlbums) < $criteria->limit;
|
||||
|
||||
if (!$shouldFetchFromSpotify) {
|
||||
return [
|
||||
@@ -142,9 +150,10 @@ class AlbumSearchService
|
||||
];
|
||||
}
|
||||
|
||||
// Mix cached payloads with just enough fresh API data to satisfy the limit.
|
||||
// Mix cached payloads with just enough fresh API data to satisfy the limit.
|
||||
// This has the consequence of preferring cached data, but reduces API calls.
|
||||
$apiPayloads = $this->fetchSpotifyPayloads($criteria, $spotifyQuery, $storedPayloads);
|
||||
$filteredApiPayloads = $this->filterPayloadsByGenre($apiPayloads['payloads'], $criteria->getGenre());
|
||||
$filteredApiPayloads = $this->filterPayloadsByGenre($apiPayloads['payloads'], $criteria->genre);
|
||||
$payloads = $this->mergePayloadLists($filteredApiPayloads, $storedPayloads, $criteria->limit);
|
||||
$stats = $this->mergeStats($stats, $apiPayloads['stats']);
|
||||
$savedIds = $this->mergeSavedIds($savedIds, $apiPayloads['savedIds']);
|
||||
@@ -160,7 +169,7 @@ class AlbumSearchService
|
||||
*/
|
||||
private function fetchSpotifyPayloads(AlbumSearchCriteria $criteria, string $spotifyQuery, array $storedPayloads): array
|
||||
{
|
||||
$result = $this->spotify->searchAlbums($spotifyQuery, $criteria->limit);
|
||||
$result = $this->spotifyClient->searchAlbums($spotifyQuery, $criteria->limit);
|
||||
$searchItems = $result['albums']['items'] ?? [];
|
||||
$this->logger->info('Album search results received', [
|
||||
'query' => $spotifyQuery,
|
||||
@@ -176,7 +185,7 @@ class AlbumSearchService
|
||||
return ['payloads' => [], 'stats' => [], 'savedIds' => []];
|
||||
}
|
||||
|
||||
$full = $this->spotify->getAlbums($ids);
|
||||
$full = $this->spotifyClient->getAlbums($ids);
|
||||
$albumsPayload = is_array($full) ? ($full['albums'] ?? []) : [];
|
||||
if ($albumsPayload === [] && $searchItems !== []) {
|
||||
$albumsPayload = $searchItems;
|
||||
@@ -196,7 +205,7 @@ class AlbumSearchService
|
||||
);
|
||||
$upserted++;
|
||||
}
|
||||
$this->em->flush();
|
||||
$this->entityManager->flush();
|
||||
$this->logger->info('Albums upserted to DB', ['upserted' => $upserted]);
|
||||
|
||||
$existing = $this->albumRepository->findBySpotifyIdsKeyed($ids);
|
||||
@@ -227,7 +236,7 @@ class AlbumSearchService
|
||||
$criteria->query,
|
||||
$criteria->albumName,
|
||||
$criteria->artist,
|
||||
$criteria->getGenre(),
|
||||
$criteria->genre,
|
||||
$criteria->yearFrom ?? 0,
|
||||
$criteria->yearTo ?? 0,
|
||||
$criteria->limit
|
||||
@@ -260,6 +269,7 @@ class AlbumSearchService
|
||||
$entityId = (int) $album->getId();
|
||||
$localId = (string) $album->getLocalId();
|
||||
if ($localId !== '' && isset($userStats[$entityId])) {
|
||||
// Templates never see entity IDs, so stats must be re-keyed to the user-facing local IDs.
|
||||
$mapped[$localId] = $userStats[$entityId];
|
||||
}
|
||||
}
|
||||
@@ -373,7 +383,7 @@ class AlbumSearchService
|
||||
if ($id !== null && isset($seen[$id])) {
|
||||
continue;
|
||||
}
|
||||
// Fill the remainder of the list with secondary payloads that have not already been emitted.
|
||||
// Secondary payloads often duplicate the primary list; skip anything we've already emitted.
|
||||
$merged[] = $payload;
|
||||
if ($id !== null) {
|
||||
$seen[$id] = true;
|
||||
|
||||
Reference in new issue
Block a user