Removing "App\Entity" imports, part 3

This commit is contained in:
Buster Neece 2023-06-07 11:11:40 -05:00
parent 13d19511a9
commit 6314fa7a09
No known key found for this signature in database
178 changed files with 1574 additions and 1330 deletions

View File

@ -46,10 +46,6 @@
</rule>
<rule ref="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly">
<properties>
<property name="allowPartialUses" value="false"/>
</properties>
<exclude-pattern>config/*$</exclude-pattern>
</rule>
</ruleset>

View File

@ -6,7 +6,6 @@ namespace App\Controller\Api\Stations\Files;
use App\Container\EntityManagerAwareTrait;
use App\Controller\Api\Traits\CanSortResults;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\RouterInterface;
@ -20,6 +19,11 @@ use League\Flysystem\StorageAttributes;
use Psr\Http\Message\ResponseInterface;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use App\Entity\StationMedia;
use App\Entity\StationPlaylist;
use App\Entity\Api\FileList;
use App\Entity\Api\FileListMedia;
use App\Entity\Station;
final class ListAction
{
@ -64,7 +68,7 @@ final class ListAction
$flushCache = (bool)$request->getParam('flushCache', false);
if (!$flushCache && $this->cache->has($cacheKey)) {
/** @var array<int, Entity\Api\FileList> $result */
/** @var array<int, \App\Entity\Api\FileList> $result */
$result = $this->cache->get($cacheKey);
} else {
$pathLike = (empty($currentDir))
@ -73,7 +77,7 @@ final class ListAction
$mediaQueryBuilder = $this->em->createQueryBuilder()
->select('sm')
->from(Entity\StationMedia::class, 'sm')
->from(StationMedia::class, 'sm')
->where('sm.storage_location = :storageLocation')
->andWhere('sm.path LIKE :path')
->setParameter('storageLocation', $station->getMediaStorageLocation())
@ -83,7 +87,7 @@ final class ListAction
$foldersInDirQuery = $this->em->createQuery(
<<<'DQL'
SELECT spf, sp
FROM App\Entity\StationPlaylistFolder spf
FROM App\\App\Entity\StationPlaylistFolder spf
JOIN spf.playlist sp
WHERE spf.station = :station
AND spf.path LIKE :path
@ -94,7 +98,7 @@ final class ListAction
$unprocessableMediaQuery = $this->em->createQuery(
<<<'DQL'
SELECT upm
FROM App\Entity\UnprocessableMedia upm
FROM App\\App\Entity\UnprocessableMedia upm
WHERE upm.storage_location = :storageLocation
AND upm.path LIKE :path
DQL
@ -116,7 +120,7 @@ final class ListAction
'sm.song_id',
<<<'DQL'
SELECT sm2.song_id FROM
App\Entity\StationMedia sm2
App\\App\Entity\StationMedia sm2
WHERE sm2.storage_location = :storageLocation
GROUP BY sm2.song_id
HAVING COUNT(sm2.id) > 1
@ -125,14 +129,14 @@ final class ListAction
);
} elseif ('special:unassigned' === $searchPhrase) {
$mediaQueryBuilder->andWhere(
'sm.id NOT IN (SELECT spm2.media_id FROM App\Entity\StationPlaylistMedia spm2)'
'sm.id NOT IN (SELECT spm2.media_id FROM App\\App\Entity\StationPlaylistMedia spm2)'
);
} else {
[$searchPhrase, $playlist] = $this->parseSearchQuery($station, $searchPhrase);
if (null !== $playlist) {
$mediaQueryBuilder->andWhere(
'sm.id IN (SELECT spm2.media_id FROM App\Entity\StationPlaylistMedia spm2 '
'sm.id IN (SELECT spm2.media_id FROM App\\App\Entity\StationPlaylistMedia spm2 '
. 'WHERE spm2.playlist = :playlist)'
)->setParameter('playlist', $playlist);
}
@ -174,7 +178,7 @@ final class ListAction
$foldersInDir[$folderRow['path']]['playlists'][] = [
'id' => $folderRow['playlist']['id'],
'name' => $folderRow['playlist']['name'],
'short_name' => Entity\StationPlaylist::generateShortName(
'short_name' => StationPlaylist::generateShortName(
$folderRow['playlist']['name']
),
];
@ -195,9 +199,9 @@ final class ListAction
}
} else {
$protectedPaths = [
Entity\StationMedia::DIR_ALBUM_ART,
Entity\StationMedia::DIR_WAVEFORMS,
Entity\StationMedia::DIR_FOLDER_COVERS,
StationMedia::DIR_ALBUM_ART,
StationMedia::DIR_WAVEFORMS,
StationMedia::DIR_FOLDER_COVERS,
];
$files = $fs->listContents($currentDir, false)->filter(
@ -211,7 +215,7 @@ final class ListAction
$result = [];
foreach ($files as $file) {
$row = new Entity\Api\FileList();
$row = new FileList();
if ($file instanceof StorageAttributes) {
$row->path = $file->path();
@ -235,7 +239,7 @@ final class ListAction
}
$row->path_short = $shortname;
$row->media = new Entity\Api\FileListMedia();
$row->media = new FileListMedia();
if (isset($mediaInDir[$row->path])) {
$row->media = $mediaInDir[$row->path]['media'];
@ -272,7 +276,7 @@ final class ListAction
usort(
$result,
static fn(Entity\Api\FileList $a, Entity\Api\FileList $b) => self::sortRows(
static fn(FileList $a, FileList $b) => self::sortRows(
$a,
$b,
$propertyAccessor,
@ -288,14 +292,14 @@ final class ListAction
$stationId = $station->getIdRequired();
$paginator->setPostprocessor(
static fn(Entity\Api\FileList $row) => self::postProcessRow($row, $router, $stationId)
static fn(FileList $row) => self::postProcessRow($row, $router, $stationId)
);
return $paginator->write($response);
}
private function parseSearchQuery(
Entity\Station $station,
Station $station,
string $query
): array {
$playlist = null;
@ -310,14 +314,14 @@ final class ListAction
$playlistNameLookupRaw = $this->em->createQuery(
<<<'DQL'
SELECT sp.id, sp.name
FROM App\Entity\StationPlaylist sp
FROM App\\App\Entity\StationPlaylist sp
WHERE sp.station = :station
DQL
)->setParameter('station', $station)
->getArrayResult();
foreach ($playlistNameLookupRaw as $playlistRow) {
$shortName = Entity\StationPlaylist::generateShortName($playlistRow['name']);
$shortName = StationPlaylist::generateShortName($playlistRow['name']);
if ($shortName === $playlistId) {
$playlistId = $playlistRow['id'];
break;
@ -325,7 +329,7 @@ final class ListAction
}
}
$playlist = $this->em->getRepository(Entity\StationPlaylist::class)
$playlist = $this->em->getRepository(StationPlaylist::class)
->findOneBy(
[
'station' => $station,
@ -345,7 +349,7 @@ final class ListAction
}
private function processMediaInDir(
Entity\Station $station,
Station $station,
?QueryBuilder $qb = null
): array {
if (null === $qb) {
@ -375,7 +379,7 @@ final class ListAction
$customFieldsRaw = $this->em->createQuery(
<<<'DQL'
SELECT smcf.media_id, smcf.field_id, smcf.value
FROM App\Entity\StationMediaCustomField smcf
FROM App\\App\Entity\StationMediaCustomField smcf
WHERE smcf.media_id IN (:ids)
DQL
)->setParameter('ids', $mediaIds)
@ -391,7 +395,7 @@ final class ListAction
$allPlaylistsRaw = $this->em->createQuery(
<<<'DQL'
SELECT spm.media_id, spm.playlist_id, sp.name
FROM App\Entity\StationPlaylistMedia spm
FROM App\\App\Entity\StationPlaylistMedia spm
JOIN spm.playlist sp
WHERE sp.station = :station AND spm.media_id IN (:ids)
DQL
@ -408,7 +412,7 @@ final class ListAction
$mediaInDir = [];
foreach ($mediaInDirRaw as $row) {
$id = $row['id'];
$media = new Entity\Api\FileListMedia();
$media = new FileListMedia();
$media->id = (string)$row['song_id'];
$media->title = (string)$row['title'];
@ -436,7 +440,7 @@ final class ListAction
$playlists[$playlistId] = [
'id' => $playlistId,
'name' => $playlistName,
'short_name' => Entity\StationPlaylist::generateShortName($playlistName),
'short_name' => StationPlaylist::generateShortName($playlistName),
'count' => 1,
];
}
@ -452,8 +456,8 @@ final class ListAction
}
private static function sortRows(
Entity\Api\FileList $a,
Entity\Api\FileList $b,
FileList $a,
FileList $b,
PropertyAccessorInterface $propertyAccessor,
?string $searchPhrase = null,
?string $sort = null,
@ -478,10 +482,10 @@ final class ListAction
}
private static function postProcessRow(
Entity\Api\FileList $row,
FileList $row,
RouterInterface $router,
int $stationId
): Entity\Api\FileList {
): FileList {
if (null !== $row->media->media_id) {
$artMediaId = $row->media->unique_id;
if (0 !== $row->media->art_updated_at) {

View File

@ -4,12 +4,12 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Files;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use League\Flysystem\StorageAttributes;
use Psr\Http\Message\ResponseInterface;
use App\Entity\StationMedia;
final class ListDirectoriesAction
{
@ -30,9 +30,9 @@ final class ListDirectoriesAction
$fsMedia = $this->stationFilesystems->getMediaFilesystem($station);
$protectedPaths = [
Entity\StationMedia::DIR_ALBUM_ART,
Entity\StationMedia::DIR_WAVEFORMS,
Entity\StationMedia::DIR_FOLDER_COVERS,
StationMedia::DIR_ALBUM_ART,
StationMedia::DIR_WAVEFORMS,
StationMedia::DIR_FOLDER_COVERS,
];
$directoriesRaw = $fsMedia->listContents($currentDir, false)->filter(

View File

@ -4,12 +4,13 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Files;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use League\Flysystem\UnableToCreateDirectory;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Api\Error;
use App\Entity\Api\Status;
final class MakeDirectoryAction
{
@ -28,7 +29,7 @@ final class MakeDirectoryAction
if (empty($newDirName)) {
return $response->withStatus(400)
->withJson(new Entity\Api\Error(400, __('No directory specified')));
->withJson(new Error(400, __('No directory specified')));
}
$station = $request->getStation();
@ -41,9 +42,9 @@ final class MakeDirectoryAction
$fsMedia->createDirectory($newDir);
} catch (UnableToCreateDirectory $e) {
return $response->withStatus(400)
->withJson(new Entity\Api\Error(400, $e->getMessage()));
->withJson(new Error(400, $e->getMessage()));
}
return $response->withJson(Entity\Api\Status::created());
return $response->withJson(Status::created());
}
}

View File

@ -4,16 +4,16 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Files;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationMediaRepository;
final class PlayAction
{
public function __construct(
private readonly Entity\Repository\StationMediaRepository $mediaRepo,
private readonly StationMediaRepository $mediaRepo,
private readonly StationFilesystems $stationFilesystems
) {
}

View File

@ -4,12 +4,13 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Files;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Media\BatchUtilities;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Api\Error;
use App\Entity\Api\Status;
final class RenameAction
{
@ -27,18 +28,18 @@ final class RenameAction
$from = $request->getParam('file');
if (empty($from)) {
return $response->withStatus(500)
->withJson(new Entity\Api\Error(500, __('File not specified.')));
->withJson(new Error(500, __('File not specified.')));
}
$to = $request->getParam('newPath');
if (empty($to)) {
return $response->withStatus(500)
->withJson(new Entity\Api\Error(500, __('New path not specified.')));
->withJson(new Error(500, __('New path not specified.')));
}
// No-op if paths match
if ($from === $to) {
return $response->withJson(Entity\Api\Status::updated());
return $response->withJson(Status::updated());
}
$station = $request->getStation();
@ -49,6 +50,6 @@ final class RenameAction
$this->batchUtilities->handleRename($from, $to, $storageLocation, $fsMedia);
return $response->withJson(Entity\Api\Status::updated());
return $response->withJson(Status::updated());
}
}

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\LiquidsoapConfig;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Event\Radio\WriteLiquidsoapConfiguration;
use App\Http\Response;
use App\Http\ServerRequest;
@ -34,7 +33,7 @@ final class PutAction
$station = $this->em->refetch($request->getStation());
$backendConfig = $station->getBackendConfig();
foreach (Entity\StationBackendConfiguration::getCustomConfigurationSections() as $field) {
foreach (\App\Entity\StationBackendConfiguration::getCustomConfigurationSections() as $field) {
if (isset($body[$field])) {
$backendConfig->setCustomConfigurationSection($field, $body[$field]);
}
@ -52,9 +51,9 @@ final class PutAction
$config = $event->buildConfiguration();
$this->liquidsoap->verifyConfig($config);
} catch (Throwable $e) {
return $response->withStatus(500)->withJson(Entity\Api\Error::fromException($e));
return $response->withStatus(500)->withJson(\App\Entity\Api\Error::fromException($e));
}
return $response->withJson(Entity\Api\Status::updated());
return $response->withJson(\App\Entity\Api\Status::updated());
}
}

View File

@ -4,12 +4,13 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Mounts\Intro;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationMountRepository;
use App\Entity\Api\Status;
#[OA\Delete(
path: '/station/{station_id}/mount/{id}/intro',
@ -36,7 +37,7 @@ use Psr\Http\Message\ResponseInterface;
final class DeleteIntroAction
{
public function __construct(
private readonly Entity\Repository\StationMountRepository $mountRepo,
private readonly StationMountRepository $mountRepo,
) {
}
@ -51,6 +52,6 @@ final class DeleteIntroAction
$mount = $this->mountRepo->requireForStation($id, $station);
$this->mountRepo->clearIntro($mount);
return $response->withJson(Entity\Api\Status::deleted());
return $response->withJson(Status::deleted());
}
}

View File

@ -4,13 +4,15 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Mounts\Intro;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationMountRepository;
use App\Entity\StationMount;
use App\Entity\Api\Error;
#[OA\Get(
path: '/station/{station_id}/mount/{id}/intro',
@ -40,7 +42,7 @@ use Psr\Http\Message\ResponseInterface;
final class GetIntroAction
{
public function __construct(
private readonly Entity\Repository\StationMountRepository $mountRepo,
private readonly StationMountRepository $mountRepo,
) {
}
@ -55,7 +57,7 @@ final class GetIntroAction
$station = $request->getStation();
$mount = $this->mountRepo->findForStation($id, $station);
if ($mount instanceof Entity\StationMount) {
if ($mount instanceof StationMount) {
$introPath = $mount->getIntroPath();
if (!empty($introPath)) {
@ -71,6 +73,6 @@ final class GetIntroAction
}
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
}

View File

@ -4,13 +4,14 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Mounts\Intro;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use App\Service\Flow;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationMountRepository;
use App\Entity\Api\Status;
#[OA\Post(
path: '/station/{station_id}/mount/{id}/intro',
@ -37,7 +38,7 @@ use Psr\Http\Message\ResponseInterface;
final class PostIntroAction
{
public function __construct(
private readonly Entity\Repository\StationMountRepository $mountRepo,
private readonly StationMountRepository $mountRepo,
) {
}
@ -58,7 +59,7 @@ final class PostIntroAction
$mount = $this->mountRepo->requireForStation($id, $station);
$this->mountRepo->setIntro($mount, $flowResponse);
return $response->withJson(Entity\Api\Status::updated());
return $response->withJson(Status::updated());
}
return $response->withJson($flowResponse);

View File

@ -4,16 +4,17 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\OnDemand;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationMediaRepository;
use App\Entity\Api\Error;
final class DownloadAction
{
public function __construct(
private readonly Entity\Repository\StationMediaRepository $mediaRepo,
private readonly StationMediaRepository $mediaRepo,
private readonly StationFilesystems $stationFilesystems,
) {
}
@ -29,7 +30,7 @@ final class DownloadAction
// Verify that the station supports on-demand streaming.
if (!$station->getEnableOnDemand()) {
return $response->withStatus(403)
->withJson(new Entity\Api\Error(403, __('This station does not support on-demand streaming.')));
->withJson(new Error(403, __('This station does not support on-demand streaming.')));
}
$media = $this->mediaRepo->requireByUniqueId($media_id, $station);

View File

@ -5,12 +5,14 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts\Art;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\PodcastRepository;
use App\Entity\Api\Error;
use App\Entity\Api\Status;
#[OA\Delete(
path: '/station/{station_id}/podcast/{podcast_id}/art',
@ -39,7 +41,7 @@ final class DeleteArtAction
use EntityManagerAwareTrait;
public function __construct(
private readonly Entity\Repository\PodcastRepository $podcastRepo,
private readonly PodcastRepository $podcastRepo,
) {
}
@ -56,7 +58,7 @@ final class DeleteArtAction
if ($podcast === null) {
return $response->withStatus(404)
->withJson(
new Entity\Api\Error(
new Error(
404,
__('Podcast not found!')
)
@ -67,6 +69,6 @@ final class DeleteArtAction
$this->em->persist($podcast);
$this->em->flush();
return $response->withJson(Entity\Api\Status::deleted());
return $response->withJson(Status::deleted());
}
}

View File

@ -4,13 +4,14 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts\Art;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationRepository;
use App\Entity\Podcast;
#[OA\Get(
path: '/station/{station_id}/podcast/{podcast_id}/art',
@ -40,7 +41,7 @@ use Psr\Http\Message\ResponseInterface;
final class GetArtAction
{
public function __construct(
private readonly Entity\Repository\StationRepository $stationRepo,
private readonly StationRepository $stationRepo,
private readonly StationFilesystems $stationFilesystems,
) {
}
@ -56,7 +57,7 @@ final class GetArtAction
// If a timestamp delimiter is added, strip it automatically.
$podcast_id = explode('|', $podcast_id, 2)[0];
$podcastPath = Entity\Podcast::getArtPath($podcast_id);
$podcastPath = Podcast::getArtPath($podcast_id);
$fsPodcasts = $this->stationFilesystems->getPodcastsFilesystem($station);

View File

@ -5,13 +5,15 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts\Art;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use App\Service\Flow;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\PodcastRepository;
use App\Entity\Api\Error;
use App\Entity\Api\Status;
#[OA\Post(
path: '/station/{station_id}/podcast/{podcast_id}/art',
@ -40,7 +42,7 @@ final class PostArtAction
use EntityManagerAwareTrait;
public function __construct(
private readonly Entity\Repository\PodcastRepository $podcastRepo,
private readonly PodcastRepository $podcastRepo,
) {
}
@ -65,7 +67,7 @@ final class PostArtAction
if (null === $podcast) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
$this->podcastRepo->writePodcastArt(
@ -75,7 +77,7 @@ final class PostArtAction
$this->em->flush();
return $response->withJson(Entity\Api\Status::updated());
return $response->withJson(Status::updated());
}
return $response->withJson($flowResponse);

View File

@ -5,12 +5,14 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts\Episodes\Art;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\PodcastEpisodeRepository;
use App\Entity\Api\Error;
use App\Entity\Api\Status;
#[OA\Delete(
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/art',
@ -57,7 +59,7 @@ final class DeleteArtAction
use EntityManagerAwareTrait;
public function __construct(
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
private readonly PodcastEpisodeRepository $episodeRepo,
) {
}
@ -73,13 +75,13 @@ final class DeleteArtAction
$episode = $this->episodeRepo->fetchEpisodeForStation($station, $episode_id);
if ($episode === null) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
$this->episodeRepo->removeEpisodeArt($episode);
$this->em->persist($episode);
$this->em->flush();
return $response->withJson(Entity\Api\Status::deleted());
return $response->withJson(Status::deleted());
}
}

View File

@ -4,13 +4,15 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts\Episodes\Art;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationRepository;
use App\Entity\PodcastEpisode;
use App\Entity\Podcast;
#[OA\Get(
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/art',
@ -47,7 +49,7 @@ use Psr\Http\Message\ResponseInterface;
final class GetArtAction
{
public function __construct(
private readonly Entity\Repository\StationRepository $stationRepo,
private readonly StationRepository $stationRepo,
private readonly StationFilesystems $stationFilesystems
) {
}
@ -64,7 +66,7 @@ final class GetArtAction
// If a timestamp delimiter is added, strip it automatically.
$episode_id = explode('|', $episode_id, 2)[0];
$episodeArtPath = Entity\PodcastEpisode::getArtPath($episode_id);
$episodeArtPath = PodcastEpisode::getArtPath($episode_id);
$fsPodcasts = $this->stationFilesystems->getPodcastsFilesystem($station);
if ($fsPodcasts->fileExists($episodeArtPath)) {
@ -72,7 +74,7 @@ final class GetArtAction
->streamFilesystemFile($fsPodcasts, $episodeArtPath, null, 'inline', false);
}
$podcastArtPath = Entity\Podcast::getArtPath($podcast_id);
$podcastArtPath = Podcast::getArtPath($podcast_id);
if ($fsPodcasts->fileExists($podcastArtPath)) {
return $response->withCacheLifetime(Response::CACHE_ONE_DAY)

View File

@ -5,13 +5,15 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts\Episodes\Art;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use App\Service\Flow;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\PodcastEpisodeRepository;
use App\Entity\Api\Error;
use App\Entity\Api\Status;
#[OA\Post(
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/art',
@ -47,7 +49,7 @@ final class PostArtAction
use EntityManagerAwareTrait;
public function __construct(
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
private readonly PodcastEpisodeRepository $episodeRepo,
) {
}
@ -70,7 +72,7 @@ final class PostArtAction
if (null === $episode) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
$this->episodeRepo->writeEpisodeArt(
@ -80,7 +82,7 @@ final class PostArtAction
$this->em->flush();
return $response->withJson(Entity\Api\Status::updated());
return $response->withJson(Status::updated());
}
return $response->withJson($flowResponse);

View File

@ -4,12 +4,16 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts\Episodes\Media;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\PodcastEpisodeRepository;
use App\Entity\PodcastEpisode;
use App\Entity\Api\Error;
use App\Entity\PodcastMedia;
use App\Entity\Api\Status;
#[OA\Delete(
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/media',
@ -43,7 +47,7 @@ use Psr\Http\Message\ResponseInterface;
final class DeleteMediaAction
{
public function __construct(
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
private readonly PodcastEpisodeRepository $episodeRepo,
) {
}
@ -57,17 +61,17 @@ final class DeleteMediaAction
$station = $request->getStation();
$episode = $this->episodeRepo->fetchEpisodeForStation($station, $episode_id);
if (!($episode instanceof Entity\PodcastEpisode)) {
if (!($episode instanceof PodcastEpisode)) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
$podcastMedia = $episode->getMedia();
if ($podcastMedia instanceof Entity\PodcastMedia) {
if ($podcastMedia instanceof PodcastMedia) {
$this->episodeRepo->deleteMedia($podcastMedia);
}
return $response->withJson(Entity\Api\Status::deleted());
return $response->withJson(Status::deleted());
}
}

View File

@ -4,13 +4,16 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts\Episodes\Media;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\PodcastEpisodeRepository;
use App\Entity\PodcastEpisode;
use App\Entity\PodcastMedia;
use App\Entity\Api\Error;
#[OA\Get(
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/media',
@ -47,7 +50,7 @@ use Psr\Http\Message\ResponseInterface;
final class GetMediaAction
{
public function __construct(
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
private readonly PodcastEpisodeRepository $episodeRepo,
private readonly StationFilesystems $stationFilesystems,
) {
}
@ -64,10 +67,10 @@ final class GetMediaAction
$station = $request->getStation();
$episode = $this->episodeRepo->fetchEpisodeForStation($station, $episode_id);
if ($episode instanceof Entity\PodcastEpisode) {
if ($episode instanceof PodcastEpisode) {
$podcastMedia = $episode->getMedia();
if ($podcastMedia instanceof Entity\PodcastMedia) {
if ($podcastMedia instanceof PodcastMedia) {
$fsPodcasts = $this->stationFilesystems->getPodcastsFilesystem($station);
$path = $podcastMedia->getPath();
@ -83,6 +86,6 @@ final class GetMediaAction
}
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts\Episodes\Media;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
@ -12,6 +11,9 @@ use App\OpenApi;
use App\Service\Flow;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\PodcastEpisodeRepository;
use App\Entity\Api\Error;
use App\Entity\Api\Status;
#[OA\Post(
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/media',
@ -45,7 +47,7 @@ use Psr\Http\Message\ResponseInterface;
final class PostMediaAction
{
public function __construct(
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
private readonly PodcastEpisodeRepository $episodeRepo,
private readonly StationFilesystems $stationFilesystems
) {
}
@ -69,7 +71,7 @@ final class PostMediaAction
if (null === $episode) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
$this->episodeRepo->uploadMedia(
@ -79,7 +81,7 @@ final class PostMediaAction
$this->stationFilesystems->getPodcastsFilesystem($station)
);
return $response->withJson(Entity\Api\Status::updated());
return $response->withJson(Status::updated());
}
return $response->withJson($flowResponse);

View File

@ -4,17 +4,21 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Reports\Overview;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Utilities\DateRange;
use Psr\Http\Message\ResponseInterface;
use App\Entity\ApiGenerator\SongApiGenerator;
use App\Entity\Repository\SettingsRepository;
use App\Entity\Api\Status;
use App\Entity\SongHistory;
use App\Entity\Song;
final class BestAndWorstAction extends AbstractReportAction
{
public function __construct(
private readonly Entity\ApiGenerator\SongApiGenerator $songApiGenerator,
Entity\Repository\SettingsRepository $settingsRepo
private readonly SongApiGenerator $songApiGenerator,
SettingsRepository $settingsRepo
) {
parent::__construct($settingsRepo);
}
@ -27,7 +31,7 @@ final class BestAndWorstAction extends AbstractReportAction
// Get current analytics level.
if (!$this->isAnalyticsEnabled()) {
return $response->withStatus(400)
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
}
$dateRange = $this->getDateRange($request, $request->getStation()->getTimezoneObject());
@ -47,7 +51,7 @@ final class BestAndWorstAction extends AbstractReportAction
// Get all songs played in timeline.
$baseQuery = $this->em->createQueryBuilder()
->select('sh')
->from(Entity\SongHistory::class, 'sh')
->from(SongHistory::class, 'sh')
->where('sh.station = :station')
->setParameter('station', $station)
->andWhere('sh.timestamp_start <= :end AND sh.timestamp_end >= :start')
@ -71,7 +75,7 @@ final class BestAndWorstAction extends AbstractReportAction
foreach ($rawStats as $category => $rawRows) {
$stats[$category] = array_map(
function ($row) use ($station, $baseUrl) {
$song = ($this->songApiGenerator)(Entity\Song::createFromArray($row), $station);
$song = ($this->songApiGenerator)(Song::createFromArray($row), $station);
$song->resolveUrls($baseUrl);
return [
@ -97,7 +101,7 @@ final class BestAndWorstAction extends AbstractReportAction
$rawRows = $this->em->createQuery(
<<<'DQL'
SELECT sh.song_id, sh.text, sh.artist, sh.title, COUNT(sh.id) AS records
FROM App\Entity\SongHistory sh
FROM App\\App\Entity\SongHistory sh
WHERE sh.station = :station
AND sh.is_visible = 1
AND sh.timestamp_start <= :end
@ -115,7 +119,7 @@ final class BestAndWorstAction extends AbstractReportAction
return array_map(
function ($row) use ($station, $baseUrl) {
$song = ($this->songApiGenerator)(Entity\Song::createFromArray($row), $station);
$song = ($this->songApiGenerator)(Song::createFromArray($row), $station);
$song->resolveUrls($baseUrl);
return [

View File

@ -4,10 +4,10 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Reports\Overview;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Api\Status;
final class ByBrowser extends AbstractReportAction
{
@ -19,7 +19,7 @@ final class ByBrowser extends AbstractReportAction
// Get current analytics level.
if (!$this->isAllAnalyticsEnabled()) {
return $response->withStatus(400)
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
}
$station = $request->getStation();

View File

@ -4,10 +4,10 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Reports\Overview;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Api\Status;
final class ByClient extends AbstractReportAction
{
@ -19,7 +19,7 @@ final class ByClient extends AbstractReportAction
// Get current analytics level.
if (!$this->isAllAnalyticsEnabled()) {
return $response->withStatus(400)
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
}
$station = $request->getStation();

View File

@ -4,11 +4,11 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Reports\Overview;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Intl\Countries;
use App\Entity\Api\Status;
final class ByCountry extends AbstractReportAction
{
@ -20,7 +20,7 @@ final class ByCountry extends AbstractReportAction
// Get current analytics level.
if (!$this->isAllAnalyticsEnabled()) {
return $response->withStatus(400)
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
}
$station = $request->getStation();

View File

@ -4,10 +4,10 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Reports\Overview;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Api\Status;
final class ByListeningTime extends AbstractReportAction
{
@ -19,7 +19,7 @@ final class ByListeningTime extends AbstractReportAction
// Get current analytics level.
if (!$this->isAnalyticsEnabled()) {
return $response->withStatus(400)
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
}
$station = $request->getStation();

View File

@ -4,18 +4,21 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Reports\Overview;
use App\Entity;
use App\Entity\Repository\SettingsRepository;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationMountRepository;
use App\Entity\Repository\StationRemoteRepository;
use App\Entity\Repository\StationHlsStreamRepository;
use App\Entity\Api\Status;
final class ByStream extends AbstractReportAction
{
public function __construct(
private readonly Entity\Repository\StationMountRepository $mountRepo,
private readonly Entity\Repository\StationRemoteRepository $remoteRepo,
private readonly Entity\Repository\StationHlsStreamRepository $hlsStreamRepo,
private readonly StationMountRepository $mountRepo,
private readonly StationRemoteRepository $remoteRepo,
private readonly StationHlsStreamRepository $hlsStreamRepo,
SettingsRepository $settingsRepo,
) {
parent::__construct($settingsRepo);
@ -29,7 +32,7 @@ final class ByStream extends AbstractReportAction
// Get current analytics level.
if (!$this->isAnalyticsEnabled()) {
return $response->withStatus(400)
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
}
$station = $request->getStation();

View File

@ -4,18 +4,21 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Reports\Overview;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Carbon\CarbonImmutable;
use Psr\Http\Message\ResponseInterface;
use stdClass;
use App\Entity\Repository\AnalyticsRepository;
use App\Entity\Repository\SettingsRepository;
use App\Entity\Api\Status;
use App\Entity\Enums\AnalyticsIntervals;
final class ChartsAction extends AbstractReportAction
{
public function __construct(
private readonly Entity\Repository\AnalyticsRepository $analyticsRepo,
Entity\Repository\SettingsRepository $settingsRepo,
private readonly AnalyticsRepository $analyticsRepo,
SettingsRepository $settingsRepo,
) {
parent::__construct($settingsRepo);
}
@ -28,7 +31,7 @@ final class ChartsAction extends AbstractReportAction
// Get current analytics level.
if (!$this->isAnalyticsEnabled()) {
return $response->withStatus(400)
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
}
$station = $request->getStation();
@ -141,7 +144,7 @@ final class ChartsAction extends AbstractReportAction
$hourlyStats = $this->analyticsRepo->findForStationInRange(
$station,
$dateRange,
Entity\Enums\AnalyticsIntervals::Hourly
AnalyticsIntervals::Hourly
);
$totals_by_hour = [];

View File

@ -5,19 +5,21 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Reports;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Paginator;
use Doctrine\ORM\AbstractQuery;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationRequestRepository;
use App\Entity\StationRequest;
use App\Entity\Api\Status;
final class RequestsController
{
use EntityManagerAwareTrait;
public function __construct(
private readonly Entity\Repository\StationRequestRepository $requestRepo
private readonly StationRequestRepository $requestRepo
) {
}
@ -30,7 +32,7 @@ final class RequestsController
$qb = $this->em->createQueryBuilder()
->select('sr, sm')
->from(Entity\StationRequest::class, 'sr')
->from(StationRequest::class, 'sr')
->join('sr.track', 'sm')
->where('sr.station = :station')
->setParameter('station', $station)
@ -73,12 +75,12 @@ final class RequestsController
$station = $request->getStation();
$media = $this->requestRepo->getPendingRequest($request_id, $station);
if ($media instanceof Entity\StationRequest) {
if ($media instanceof StationRequest) {
$this->em->remove($media);
$this->em->flush();
}
return $response->withJson(Entity\Api\Status::deleted());
return $response->withJson(Status::deleted());
}
public function clearAction(
@ -89,6 +91,6 @@ final class RequestsController
$station = $request->getStation();
$this->requestRepo->clearPendingRequests($station);
return $response->withJson(Entity\Api\Status::deleted());
return $response->withJson(Status::deleted());
}
}

View File

@ -5,13 +5,13 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Reports;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\MusicBrainz;
use Carbon\CarbonImmutable;
use Psr\Http\Message\ResponseInterface;
use Throwable;
use App\Entity\Song;
/**
* Produce a report in SoundExchange (the US webcaster licensing agency) format.
@ -68,7 +68,7 @@ final class SoundExchangeAction
$all_media = $this->em->createQuery(
<<<'DQL'
SELECT sm, spm, sp, smcf
FROM App\Entity\StationMedia sm
FROM App\\App\Entity\StationMedia sm
LEFT JOIN sm.custom_fields smcf
LEFT JOIN sm.playlists spm
LEFT JOIN spm.playlist sp
@ -85,7 +85,7 @@ final class SoundExchangeAction
<<<'DQL'
SELECT sh.song_id AS song_id, sh.text, sh.artist, sh.title, sh.media_id, COUNT(sh.id) AS plays,
SUM(sh.unique_listeners) AS unique_listeners
FROM App\Entity\SongHistory sh
FROM App\\App\Entity\SongHistory sh
WHERE sh.station = :station
AND sh.timestamp_start <= :time_end
AND sh.timestamp_end >= :time_start
@ -100,7 +100,7 @@ final class SoundExchangeAction
$history_rows_by_id = array_column($history_rows, null, 'media_id');
// Remove any reference to the "Stream Offline" song.
$offline_song_hash = Entity\Song::createOffline()->getSongId();
$offline_song_hash = Song::createOffline()->getSongId();
unset($history_rows_by_id[$offline_song_hash]);
// Assemble report items
@ -108,7 +108,7 @@ final class SoundExchangeAction
$set_isrc_query = $this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\StationMedia sm
UPDATE App\\App\Entity\StationMedia sm
SET sm.isrc = :isrc
WHERE sm.id = :media_id
DQL
@ -163,7 +163,7 @@ final class SoundExchangeAction
private function findISRC(array $song_row): ?string
{
$song = Entity\Song::createFromArray($song_row);
$song = Song::createFromArray($song_row);
try {
foreach ($this->musicBrainz->findRecordingsForSong($song, 'isrcs') as $recording) {

View File

@ -4,12 +4,13 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\StereoTool;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationRepository;
use App\Entity\Api\Status;
#[OA\Delete(
path: '/station/{station_id}/stereo-tool-configuration',
@ -29,7 +30,7 @@ use Psr\Http\Message\ResponseInterface;
final class DeleteStereoToolConfigurationAction
{
public function __construct(
private readonly Entity\Repository\StationRepository $stationRepo
private readonly StationRepository $stationRepo
) {
}
@ -42,6 +43,6 @@ final class DeleteStereoToolConfigurationAction
$this->stationRepo->clearStereoToolConfiguration($station);
return $response->withJson(Entity\Api\Status::deleted());
return $response->withJson(Status::deleted());
}
}

View File

@ -4,13 +4,13 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\StereoTool;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Api\Error;
#[OA\Get(
path: '/station/{station_id}/stereo-tool-configuration',
@ -55,6 +55,6 @@ final class GetStereoToolConfigurationAction
}
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
}

View File

@ -4,13 +4,14 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\StereoTool;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use App\Service\Flow;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationRepository;
use App\Entity\Api\Status;
#[OA\Post(
path: '/station/{station_id}/stereo-tool-configuration',
@ -30,7 +31,7 @@ use Psr\Http\Message\ResponseInterface;
final class PostStereoToolConfigurationAction
{
public function __construct(
private readonly Entity\Repository\StationRepository $stationRepo
private readonly StationRepository $stationRepo
) {
}
@ -48,6 +49,6 @@ final class PostStereoToolConfigurationAction
$this->stationRepo->setStereoToolConfiguration($station, $flowResponse);
return $response->withJson(Entity\Api\Status::updated());
return $response->withJson(Status::updated());
}
}

View File

@ -4,16 +4,17 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Streamers\Art;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationRepository;
use App\Entity\StationStreamer;
final class GetArtAction
{
public function __construct(
private readonly Entity\Repository\StationRepository $stationRepo,
private readonly StationRepository $stationRepo,
) {
}
@ -28,7 +29,7 @@ final class GetArtAction
$station = $request->getStation();
$artworkPath = Entity\StationStreamer::getArtworkPath($id);
$artworkPath = StationStreamer::getArtworkPath($id);
$fsConfig = StationFilesystems::buildConfigFilesystem($station);
if ($fsConfig->fileExists($artworkPath)) {

View File

@ -4,16 +4,17 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Streamers\Art;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\Flow;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\StationStreamerRepository;
use App\Entity\Api\Status;
final class PostArtAction
{
public function __construct(
private readonly Entity\Repository\StationStreamerRepository $streamerRepo,
private readonly StationStreamerRepository $streamerRepo,
) {
}
@ -41,7 +42,7 @@ final class PostArtAction
$this->streamerRepo->getEntityManager()
->flush();
return $response->withJson(Entity\Api\Status::updated());
return $response->withJson(Status::updated());
}
return $response->withJson($flowResponse);

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Streamers;
use App\Controller\Api\AbstractApiCrudController;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Http\Response;
use App\Http\ServerRequest;
@ -14,13 +13,18 @@ use App\Utilities\File;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use App\Entity\StationStreamerBroadcast;
use App\Entity\Api\Error;
use App\Entity\Api\Status;
use App\Entity\Station;
use App\Entity\StationStreamer;
/**
* @extends AbstractApiCrudController<Entity\StationStreamerBroadcast>
* @extends AbstractApiCrudController<\App\Entity\StationStreamerBroadcast>
*/
final class BroadcastsController extends AbstractApiCrudController
{
protected string $entityClass = Entity\StationStreamerBroadcast::class;
protected string $entityClass = StationStreamerBroadcast::class;
public function __construct(
private readonly StationFilesystems $stationFilesystems,
@ -43,13 +47,13 @@ final class BroadcastsController extends AbstractApiCrudController
if (null === $streamer) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
$query = $this->em->createQuery(
<<<'DQL'
SELECT ssb
FROM App\Entity\StationStreamerBroadcast ssb
FROM App\\App\Entity\StationStreamerBroadcast ssb
WHERE ssb.station = :station AND ssb.streamer = :streamer
ORDER BY ssb.timestampStart DESC
DQL
@ -59,7 +63,7 @@ final class BroadcastsController extends AbstractApiCrudController
$query = $this->em->createQuery(
<<<'DQL'
SELECT ssb, ss
FROM App\Entity\StationStreamerBroadcast ssb
FROM App\\App\Entity\StationStreamerBroadcast ssb
JOIN ssb.streamer ss
WHERE ssb.station = :station
ORDER BY ssb.timestampStart DESC
@ -139,14 +143,14 @@ final class BroadcastsController extends AbstractApiCrudController
if (null === $broadcast) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
$recordingPath = $broadcast->getRecordingPath();
if (empty($recordingPath)) {
return $response->withStatus(400)
->withJson(new Entity\Api\Error(400, __('No recording available.')));
->withJson(new Error(400, __('No recording available.')));
}
$filename = basename($recordingPath);
@ -172,7 +176,7 @@ final class BroadcastsController extends AbstractApiCrudController
if (null === $broadcast) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
->withJson(Error::notFound());
}
$recordingPath = $broadcast->getRecordingPath();
@ -185,13 +189,13 @@ final class BroadcastsController extends AbstractApiCrudController
$this->em->remove($broadcast);
$this->em->flush();
return $response->withJson(Entity\Api\Status::deleted());
return $response->withJson(Status::deleted());
}
private function getRecord(Entity\Station $station, int|string $id): ?Entity\StationStreamerBroadcast
private function getRecord(Station $station, int|string $id): ?StationStreamerBroadcast
{
/** @var Entity\StationStreamerBroadcast|null $broadcast */
$broadcast = $this->em->getRepository(Entity\StationStreamerBroadcast::class)->findOneBy(
/** @var \App\Entity\StationStreamerBroadcast|null $broadcast */
$broadcast = $this->em->getRepository(StationStreamerBroadcast::class)->findOneBy(
[
'id' => (int)$id,
'station' => $station,
@ -200,10 +204,10 @@ final class BroadcastsController extends AbstractApiCrudController
return $broadcast;
}
private function getStreamer(Entity\Station $station, int|string $id): ?Entity\StationStreamer
private function getStreamer(Station $station, int|string $id): ?StationStreamer
{
/** @var Entity\StationStreamer|null $streamer */
$streamer = $this->em->getRepository(Entity\StationStreamer::class)->findOneBy(
/** @var \App\Entity\StationStreamer|null $streamer */
$streamer = $this->em->getRepository(StationStreamer::class)->findOneBy(
[
'id' => (int)$id,
'station' => $station,

View File

@ -5,12 +5,12 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Webhooks;
use App\Controller\Api\Traits\HasLogViewer;
use App\Entity;
use App\Entity\Repository\StationWebhookRepository;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Utilities\File;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Api\Error;
final class TestLogAction
{
@ -34,7 +34,7 @@ final class TestLogAction
if (!str_contains($path, $logPathPortion)) {
return $response
->withStatus(403)
->withJson(new Entity\Api\Error(403, 'Invalid log path.'));
->withJson(new Error(403, 'Invalid log path.'));
}
$tempPath = File::validateTempPath($path);

View File

@ -4,11 +4,11 @@ declare(strict_types=1);
namespace App\Controller\Api\Stations\Webhooks;
use App\Entity;
use App\Entity\Repository\StationWebhookRepository;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Api\Status;
final class ToggleAction
{
@ -36,6 +36,6 @@ final class ToggleAction
? __('Web hook enabled.')
: __('Web hook disabled.');
return $response->withJson(new Entity\Api\Status(true, $flash_message));
return $response->withJson(new Status(true, $flash_message));
}
}

View File

@ -4,11 +4,11 @@ declare(strict_types=1);
namespace App\Controller\Api\Traits;
use App\Entity;
use App\Http\ServerRequest;
use App\Radio\AutoDJ\Scheduler;
use App\Utilities\DateRange;
use Carbon\CarbonInterface;
use App\Entity\StationSchedule;
trait HasScheduleDisplay
{
@ -38,7 +38,7 @@ trait HasScheduleDisplay
$endDate = $dateRange->getEnd();
foreach ($scheduleItems as $scheduleItem) {
/** @var Entity\StationSchedule $scheduleItem */
/** @var \App\Entity\StationSchedule $scheduleItem */
$i = $startDate;
while ($i <= $endDate) {
@ -48,8 +48,8 @@ trait HasScheduleDisplay
$scheduler->shouldSchedulePlayOnCurrentDate($scheduleItem, $i)
&& $scheduler->isScheduleScheduledToPlayToday($scheduleItem, $dayOfWeek)
) {
$rowStart = Entity\StationSchedule::getDateTime($scheduleItem->getStartTime(), $i);
$rowEnd = Entity\StationSchedule::getDateTime($scheduleItem->getEndTime(), $i);
$rowStart = StationSchedule::getDateTime($scheduleItem->getStartTime(), $i);
$rowEnd = StationSchedule::getDateTime($scheduleItem->getEndTime(), $i);
// Handle overnight schedule items
if ($rowEnd < $rowStart) {

View File

@ -4,19 +4,21 @@ declare(strict_types=1);
namespace App\Controller\Frontend\Account;
use App\Entity;
use App\Exception\RateLimitExceededException;
use App\Http\Response;
use App\Http\ServerRequest;
use App\RateLimit;
use App\Service\Mail;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\UserRepository;
use App\Entity\Repository\UserLoginTokenRepository;
use App\Entity\User;
final class ForgotPasswordAction
{
public function __construct(
private readonly Entity\Repository\UserRepository $userRepo,
private readonly Entity\Repository\UserLoginTokenRepository $loginTokenRepo,
private readonly UserRepository $userRepo,
private readonly UserLoginTokenRepository $loginTokenRepo,
private readonly RateLimit $rateLimit,
private readonly Mail $mail
) {
@ -54,7 +56,7 @@ final class ForgotPasswordAction
$email = $request->getParsedBodyParam('email', '');
$user = $this->userRepo->findByEmail($email);
if ($user instanceof Entity\User) {
if ($user instanceof User) {
$email = $this->mail->createMessage();
$email->to($user->getEmail());

View File

@ -5,13 +5,14 @@ declare(strict_types=1);
namespace App\Controller\Frontend\Account;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Exception\RateLimitExceededException;
use App\Http\Response;
use App\Http\ServerRequest;
use App\RateLimit;
use Mezzio\Session\SessionCookiePersistenceInterface;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\SettingsRepository;
use App\Entity\User;
final class LoginAction
{
@ -19,7 +20,7 @@ final class LoginAction
public function __construct(
private readonly RateLimit $rateLimit,
private readonly Entity\Repository\SettingsRepository $settingsRepo
private readonly SettingsRepository $settingsRepo
) {
}
@ -36,7 +37,7 @@ final class LoginAction
if (!$settings->isSetupComplete()) {
$num_users = (int)$this->em->createQuery(
<<<'DQL'
SELECT COUNT(u.id) FROM App\Entity\User u
SELECT COUNT(u.id) FROM App\\App\Entity\User u
DQL
)->getSingleScalarResult();
@ -68,7 +69,7 @@ final class LoginAction
$user = $auth->authenticate($request->getParam('username'), $request->getParam('password'));
if ($user instanceof Entity\User) {
if ($user instanceof User) {
$session = $request->getSession();
// If user selects "remember me", extend the cookie/session lifetime.

View File

@ -4,18 +4,19 @@ declare(strict_types=1);
namespace App\Controller\Frontend\Account;
use App\Entity;
use App\Exception\NotFoundException;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\UserRepository;
use App\Entity\User;
final class MasqueradeAction
{
public const CSRF_NAMESPACE = 'user_masquerade';
public function __construct(
private readonly Entity\Repository\UserRepository $userRepo,
private readonly UserRepository $userRepo,
) {
}
@ -29,7 +30,7 @@ final class MasqueradeAction
$user = $this->userRepo->find($id);
if (!($user instanceof Entity\User)) {
if (!($user instanceof User)) {
throw new NotFoundException(__('User not found.'));
}

View File

@ -5,19 +5,20 @@ declare(strict_types=1);
namespace App\Controller\Frontend\Account;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use Throwable;
use App\Entity\Repository\UserLoginTokenRepository;
use App\Entity\User;
final class RecoverAction
{
use EntityManagerAwareTrait;
public function __construct(
private readonly Entity\Repository\UserLoginTokenRepository $loginTokenRepo,
private readonly UserLoginTokenRepository $loginTokenRepo,
) {
}
@ -29,7 +30,7 @@ final class RecoverAction
$user = $this->loginTokenRepo->authenticate($token);
$flash = $request->getFlash();
if (!$user instanceof Entity\User) {
if (!$user instanceof User) {
$flash->error(
sprintf(
'<b>%s</b>',

View File

@ -4,16 +4,16 @@ declare(strict_types=1);
namespace App\Controller\Frontend;
use App\Entity;
use App\Enums\GlobalPermissions;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\SettingsRepository;
final class DashboardAction
{
public function __construct(
private readonly Entity\Repository\SettingsRepository $settingsRepo
private readonly SettingsRepository $settingsRepo
) {
}

View File

@ -4,15 +4,16 @@ declare(strict_types=1);
namespace App\Controller\Frontend;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\SettingsRepository;
use App\Entity\User;
final class IndexAction
{
public function __construct(
private readonly Entity\Repository\SettingsRepository $settingsRepo
private readonly SettingsRepository $settingsRepo
) {
}
@ -29,7 +30,7 @@ final class IndexAction
// Redirect to login screen if the user isn't logged in.
$user = $request->getAttribute(ServerRequest::ATTR_USER);
if (!($user instanceof Entity\User)) {
if (!($user instanceof User)) {
// Redirect to a custom homepage URL if specified in settings.
$homepageRedirect = $settings->getHomepageRedirectUrl();
if (null !== $homepageRedirect) {

View File

@ -4,17 +4,17 @@ declare(strict_types=1);
namespace App\Controller\Frontend\PublicPages;
use App\Entity;
use App\Exception\StationNotFoundException;
use App\Http\Response;
use App\Http\ServerRequest;
use App\VueComponent\NowPlayingComponent;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\CustomFieldRepository;
final class PlayerAction
{
public function __construct(
private readonly Entity\Repository\CustomFieldRepository $customFieldRepo,
private readonly CustomFieldRepository $customFieldRepo,
private readonly NowPlayingComponent $nowPlayingComponent
) {
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Controller\Frontend\PublicPages;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Radio\Adapters;
@ -31,7 +30,7 @@ final class PlaylistAction
$fa = $this->adapters->getFrontendAdapter($station);
if (null !== $fa) {
foreach ($station->getMounts() as $mount) {
/** @var Entity\StationMount $mount */
/** @var \App\Entity\StationMount $mount */
if (!$mount->getIsVisibleOnPublicPages()) {
continue;
}

View File

@ -4,16 +4,16 @@ declare(strict_types=1);
namespace App\Controller\Frontend\PublicPages;
use App\Entity;
use App\Exception\StationNotFoundException;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\CustomFieldRepository;
final class RequestsAction
{
public function __construct(
private readonly Entity\Repository\CustomFieldRepository $customFieldRepo
private readonly CustomFieldRepository $customFieldRepo
) {
}

View File

@ -6,7 +6,6 @@ namespace App\Controller\Frontend;
use App\Container\EntityManagerAwareTrait;
use App\Container\EnvironmentAwareTrait;
use App\Entity;
use App\Exception\NotLoggedInException;
use App\Exception\ValidationException;
use App\Http\Response;
@ -17,6 +16,10 @@ use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Throwable;
use App\Entity\Repository\SettingsRepository;
use App\Entity\Repository\RolePermissionRepository;
use App\Entity\User;
use App\Entity\Settings;
final class SetupController
{
@ -24,8 +27,8 @@ final class SetupController
use EnvironmentAwareTrait;
public function __construct(
private readonly Entity\Repository\SettingsRepository $settingsRepo,
private readonly Entity\Repository\RolePermissionRepository $permissionRepo,
private readonly SettingsRepository $settingsRepo,
private readonly RolePermissionRepository $permissionRepo,
private readonly ValidatorInterface $validator,
private readonly StationFormComponent $stationFormComponent,
private readonly Version $version
@ -77,7 +80,7 @@ final class SetupController
$role = $this->permissionRepo->ensureSuperAdministratorRole();
// Create user account.
$user = new Entity\User();
$user = new User();
$user->setEmail($data['username']);
$user->setNewPassword($data['password']);
$user->getRoles()->add($role);
@ -170,7 +173,7 @@ final class SetupController
title: __('System Settings'),
props: [
'apiUrl' => $router->named('api:admin:settings', [
'group' => Entity\Settings::GROUP_GENERAL,
'group' => Settings::GROUP_GENERAL,
]),
'releaseChannel' => $this->version->getReleaseChannelEnum()->value,
'continueUrl' => $router->named('dashboard'),
@ -208,7 +211,7 @@ final class SetupController
// Step 1: Register
$num_users = (int)$this->em->createQuery(
<<<'DQL'
SELECT COUNT(u.id) FROM App\Entity\User u
SELECT COUNT(u.id) FROM App\\App\Entity\User u
DQL
)->getSingleScalarResult();
@ -225,7 +228,7 @@ final class SetupController
// Step 2: Set up Station
$num_stations = (int)$this->em->createQuery(
<<<'DQL'
SELECT COUNT(s.id) FROM App\Entity\Station s
SELECT COUNT(s.id) FROM App\\App\Entity\Station s
DQL
)->getSingleScalarResult();

View File

@ -5,19 +5,21 @@ declare(strict_types=1);
namespace App\Controller\Stations;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Enums\StationFeatures;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Media\MimeType;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\CustomFieldRepository;
use App\Entity\Enums\PlaylistSources;
use App\Entity\Enums\StorageLocationTypes;
final class FilesAction
{
use EntityManagerAwareTrait;
public function __construct(
private readonly Entity\Repository\CustomFieldRepository $customFieldRepo
private readonly CustomFieldRepository $customFieldRepo
) {
}
@ -31,12 +33,12 @@ final class FilesAction
$playlists = $this->em->createQuery(
<<<'DQL'
SELECT sp.id, sp.name
FROM App\Entity\StationPlaylist sp
FROM App\\App\Entity\StationPlaylist sp
WHERE sp.station_id = :station_id AND sp.source = :source
ORDER BY sp.name ASC
DQL
)->setParameter('station_id', $station->getId())
->setParameter('source', Entity\Enums\PlaylistSources::Songs->value)
->setParameter('source', PlaylistSources::Songs->value)
->getArrayResult();
$router = $request->getRouter();
@ -56,7 +58,7 @@ final class FilesAction
'mkdirUrl' => $router->fromHere('api:stations:files:mkdir'),
'renameUrl' => $router->fromHere('api:stations:files:rename'),
'quotaUrl' => $router->fromHere('api:stations:quota', [
'type' => Entity\Enums\StorageLocationTypes::StationMedia->value,
'type' => StorageLocationTypes::StationMedia->value,
]),
'initialPlaylists' => $playlists,
'customFields' => $this->customFieldRepo->fetchArray(),

View File

@ -4,11 +4,12 @@ declare(strict_types=1);
namespace App\Controller\Stations;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Intl\Languages;
use App\Entity\PodcastCategory;
use App\Entity\Enums\StorageLocationTypes;
final class PodcastsAction
{
@ -24,7 +25,7 @@ final class PodcastsAction
$userLocale = $locale->value;
$languageOptions = Languages::getNames($userLocale);
$categoriesOptions = Entity\PodcastCategory::getAvailableCategories();
$categoriesOptions = PodcastCategory::getAvailableCategories();
return $request->getView()->renderVuePage(
response: $response,
@ -36,7 +37,7 @@ final class PodcastsAction
'newArtUrl' => $router->fromHere('api:stations:podcasts:new-art'),
'stationUrl' => $router->fromHere('stations:index:index'),
'quotaUrl' => $router->fromHere('api:stations:quota', [
'type' => Entity\Enums\StorageLocationTypes::StationPodcasts->value,
'type' => StorageLocationTypes::StationPodcasts->value,
]),
'locale' => substr($locale->value, 0, 2),
'stationTimeZone' => $station->getTimezone(),

View File

@ -4,15 +4,16 @@ declare(strict_types=1);
namespace App\Controller\Stations\Reports;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\SettingsRepository;
use App\Entity\Enums\AnalyticsLevel;
final class OverviewAction
{
public function __construct(
private readonly Entity\Repository\SettingsRepository $settingsRepo
private readonly SettingsRepository $settingsRepo
) {
}
@ -39,7 +40,7 @@ final class OverviewAction
title: __('Station Statistics'),
props: [
'stationTz' => $request->getStation()->getTimezone(),
'showFullAnalytics' => Entity\Enums\AnalyticsLevel::All === $analyticsLevel,
'showFullAnalytics' => AnalyticsLevel::All === $analyticsLevel,
'listenersByTimePeriodUrl' => $router->fromHere('api:stations:reports:overview-charts'),
'bestAndWorstUrl' => $router->fromHere('api:stations:reports:best-and-worst'),
'byStreamUrl' => $router->fromHere('api:stations:reports:by-stream'),

View File

@ -4,17 +4,17 @@ declare(strict_types=1);
namespace App\Controller\Stations;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\AzuraCastCentral;
use Psr\Http\Message\ResponseInterface;
use App\Entity\Repository\SettingsRepository;
final class StreamersAction
{
public function __construct(
private readonly AzuraCastCentral $acCentral,
private readonly Entity\Repository\SettingsRepository $settingsRepo
private readonly SettingsRepository $settingsRepo
) {
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Doctrine\Event;
use App\Entity;
use App\Entity\Attributes\Auditable;
use App\Entity\Attributes\AuditIgnore;
use Doctrine\Common\EventSubscriber;
@ -17,6 +16,8 @@ use Doctrine\ORM\UnitOfWork;
use ReflectionClass;
use ReflectionObject;
use Stringable;
use App\Entity\Enums\AuditLogOperations;
use App\Entity\Interfaces\IdentifiableEntityInterface;
/**
* A hook into Doctrine's event listener to write changes to "Auditable"
@ -47,7 +48,7 @@ final class AuditLog implements EventSubscriber
$newAuditLogs = array_merge($singleAuditLogs, $collectionAuditLogs);
if (!empty($newAuditLogs)) {
$auditLogMetadata = $em->getClassMetadata(Entity\AuditLog::class);
$auditLogMetadata = $em->getClassMetadata(\App\Entity\AuditLog::class);
foreach ($newAuditLogs as $auditLog) {
$uow->persist($auditLog);
$uow->computeChangeSet($auditLogMetadata, $auditLog);
@ -55,7 +56,7 @@ final class AuditLog implements EventSubscriber
}
}
/** @return Entity\AuditLog[] */
/** @return \App\Entity\AuditLog[] */
private function handleSingleUpdates(
EntityManagerInterface $em,
UnitOfWork $uow
@ -64,15 +65,15 @@ final class AuditLog implements EventSubscriber
$collections = [
[
Entity\Enums\AuditLogOperations::Insert,
AuditLogOperations::Insert,
$uow->getScheduledEntityInsertions(),
],
[
Entity\Enums\AuditLogOperations::Update,
AuditLogOperations::Update,
$uow->getScheduledEntityUpdates(),
],
[
Entity\Enums\AuditLogOperations::Delete,
AuditLogOperations::Delete,
$uow->getScheduledEntityDeletions(),
],
];
@ -114,14 +115,14 @@ final class AuditLog implements EventSubscriber
$changes[$changeField] = [$fieldPrev, $fieldNow];
}
if (Entity\Enums\AuditLogOperations::Update === $changeType && empty($changes)) {
if (AuditLogOperations::Update === $changeType && empty($changes)) {
continue;
}
// Find the identifier method or property.
$identifier = $this->getIdentifier($entity);
$newRecords[] = new Entity\AuditLog(
$newRecords[] = new \App\Entity\AuditLog(
$changeType,
get_class($entity),
$identifier,
@ -135,7 +136,7 @@ final class AuditLog implements EventSubscriber
return $newRecords;
}
/** @return Entity\AuditLog[] */
/** @return \App\Entity\AuditLog[] */
private function handleCollectionUpdates(
UnitOfWork $uow
): array {
@ -215,8 +216,8 @@ final class AuditLog implements EventSubscriber
}
foreach ($associated as [$owner, $ownerIdentifier, $entity, $entityIdentifier]) {
$newRecords[] = new Entity\AuditLog(
Entity\Enums\AuditLogOperations::Insert,
$newRecords[] = new \App\Entity\AuditLog(
AuditLogOperations::Insert,
get_class($owner),
$ownerIdentifier,
(string)get_class($entity),
@ -226,8 +227,8 @@ final class AuditLog implements EventSubscriber
}
foreach ($disassociated as [$owner, $ownerIdentifier, $entity, $entityIdentifier]) {
$newRecords[] = new Entity\AuditLog(
Entity\Enums\AuditLogOperations::Delete,
$newRecords[] = new \App\Entity\AuditLog(
AuditLogOperations::Delete,
get_class($owner),
$ownerIdentifier,
(string)get_class($entity),
@ -282,7 +283,7 @@ final class AuditLog implements EventSubscriber
return $entity->getName();
}
if ($entity instanceof Entity\Interfaces\IdentifiableEntityInterface) {
if ($entity instanceof IdentifiableEntityInterface) {
$entityId = $entity->getId();
if (null !== $entityId) {
return (string)$entityId;

View File

@ -4,12 +4,17 @@ declare(strict_types=1);
namespace App\Doctrine\Event;
use App\Entity;
use App\Entity\Attributes\AuditIgnore;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
use ReflectionObject;
use App\Entity\Enums\AuditLogOperations;
use App\Entity\StationMount;
use App\Entity\StationHlsStream;
use App\Entity\StationRemote;
use App\Entity\StationPlaylist;
use App\Entity\Station;
/**
* A hook into Doctrine's event listener to mark a station as
@ -34,15 +39,15 @@ final class StationRequiresRestart implements EventSubscriber
$collections_to_check = [
[
Entity\Enums\AuditLogOperations::Insert,
AuditLogOperations::Insert,
$uow->getScheduledEntityInsertions(),
],
[
Entity\Enums\AuditLogOperations::Update,
AuditLogOperations::Update,
$uow->getScheduledEntityUpdates(),
],
[
Entity\Enums\AuditLogOperations::Delete,
AuditLogOperations::Delete,
$uow->getScheduledEntityDeletions(),
],
];
@ -52,12 +57,12 @@ final class StationRequiresRestart implements EventSubscriber
foreach ($collections_to_check as [$change_type, $collection]) {
foreach ($collection as $entity) {
if (
($entity instanceof Entity\StationMount)
|| ($entity instanceof Entity\StationHlsStream)
|| ($entity instanceof Entity\StationRemote && $entity->isEditable())
|| ($entity instanceof Entity\StationPlaylist && $entity->getStation()->useManualAutoDJ())
($entity instanceof StationMount)
|| ($entity instanceof StationHlsStream)
|| ($entity instanceof StationRemote && $entity->isEditable())
|| ($entity instanceof StationPlaylist && $entity->getStation()->useManualAutoDJ())
) {
if (Entity\Enums\AuditLogOperations::Update === $change_type) {
if (AuditLogOperations::Update === $change_type) {
$changes = $uow->getEntityChangeSet($entity);
// Look for the @AuditIgnore annotation on a property.
@ -87,7 +92,7 @@ final class StationRequiresRestart implements EventSubscriber
$station->setNeedsRestart(true);
$em->persist($station);
$station_meta = $em->getClassMetadata(Entity\Station::class);
$station_meta = $em->getClassMetadata(Station::class);
$uow->recomputeSingleEntityChangeSet($station_meta, $station);
}
}

View File

@ -4,15 +4,15 @@ declare(strict_types=1);
namespace App\Entity\Api\Admin;
use App\Entity;
use OpenApi\Attributes as OA;
use Psr\Http\Message\UriInterface;
use App\Entity\Api\ResolvableUrlInterface;
#[OA\Schema(
schema: 'Api_Admin_Relay',
type: 'object'
)]
final class Relay implements Entity\Api\ResolvableUrlInterface
final class Relay implements ResolvableUrlInterface
{
#[OA\Property(
description: 'Station ID',
@ -74,7 +74,7 @@ final class Relay implements Entity\Api\ResolvableUrlInterface
)]
public string $admin_pw;
/** @var Entity\Api\NowPlaying\StationMount[] */
/** @var \App\Entity\Api\NowPlaying\StationMount[] */
#[OA\Property]
public array $mounts = [];
@ -86,7 +86,7 @@ final class Relay implements Entity\Api\ResolvableUrlInterface
public function resolveUrls(UriInterface $base): void
{
foreach ($this->mounts as $mount) {
if ($mount instanceof Entity\Api\ResolvableUrlInterface) {
if ($mount instanceof ResolvableUrlInterface) {
$mount->resolveUrls($base);
}
}

View File

@ -4,9 +4,9 @@ declare(strict_types=1);
namespace App\Entity\Api\Admin;
use App\Entity;
use App\Traits\LoadFromParentObject;
use OpenApi\Attributes as OA;
use App\Entity\Api\Traits\HasLinks;
#[OA\Schema(
schema: 'Api_Admin_StorageLocation',
@ -14,7 +14,7 @@ use OpenApi\Attributes as OA;
)]
final class StorageLocation
{
use Entity\Api\Traits\HasLinks;
use HasLinks;
use LoadFromParentObject;
#[OA\Property(example: 1)]

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Entity\Api\NowPlaying;
use App\Entity;
use App\Traits\LoadFromParentObject;
use OpenApi\Attributes as OA;
@ -33,7 +32,7 @@ final class CurrentSong extends SongHistory
*/
public function recalculate(): void
{
$this->elapsed = time() + Entity\SongHistory::PLAYBACK_DELAY_SECONDS - $this->played_at;
$this->elapsed = time() + \App\Entity\SongHistory::PLAYBACK_DELAY_SECONDS - $this->played_at;
if ($this->elapsed < 0) {
$this->elapsed = 0;
}

View File

@ -4,18 +4,20 @@ declare(strict_types=1);
namespace App\Entity\ApiGenerator;
use App\Entity;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use App\Entity\StationSchedule;
use App\Entity\StationPlaylist;
use App\Entity\StationStreamer;
final class ScheduleApiGenerator
{
public function __invoke(
Entity\StationSchedule $scheduleItem,
StationSchedule $scheduleItem,
?CarbonInterface $start,
?CarbonInterface $end,
?CarbonInterface $now
): Entity\Api\StationSchedule {
): \App\Entity\Api\StationSchedule {
$playlist = $scheduleItem->getPlaylist();
$streamer = $scheduleItem->getStreamer();
@ -32,8 +34,8 @@ final class ScheduleApiGenerator
}
if (null === $start || null === $end) {
$start = Entity\StationSchedule::getDateTime($scheduleItem->getStartTime(), $now);
$end = Entity\StationSchedule::getDateTime($scheduleItem->getEndTime(), $now);
$start = StationSchedule::getDateTime($scheduleItem->getStartTime(), $now);
$end = StationSchedule::getDateTime($scheduleItem->getEndTime(), $now);
// Handle overnight schedule items
if ($end < $start) {
@ -41,7 +43,7 @@ final class ScheduleApiGenerator
}
}
$row = new Entity\Api\StationSchedule();
$row = new \App\Entity\Api\StationSchedule();
$row->id = $scheduleItem->getIdRequired();
$row->start_timestamp = $start->getTimestamp();
$row->start = $start->toIso8601String();
@ -49,13 +51,13 @@ final class ScheduleApiGenerator
$row->end = $end->toIso8601String();
$row->is_now = ($start <= $now && $end >= $now);
if ($playlist instanceof Entity\StationPlaylist) {
$row->type = Entity\Api\StationSchedule::TYPE_PLAYLIST;
if ($playlist instanceof StationPlaylist) {
$row->type = \App\Entity\Api\StationSchedule::TYPE_PLAYLIST;
$row->name = $playlist->getName();
$row->title = $row->name;
$row->description = sprintf(__('Playlist: %s'), $row->name);
} elseif ($streamer instanceof Entity\StationStreamer) {
$row->type = Entity\Api\StationSchedule::TYPE_STREAMER;
} elseif ($streamer instanceof StationStreamer) {
$row->type = \App\Entity\Api\StationSchedule::TYPE_STREAMER;
$row->name = $streamer->getDisplayName();
$row->title = $row->name;
$row->description = sprintf(__('Streamer: %s'), $row->name);

View File

@ -5,12 +5,17 @@ declare(strict_types=1);
namespace App\Entity\ApiGenerator;
use App\Container\EntityManagerAwareTrait;
use App\Entity;
use App\Http\Router;
use App\Media\RemoteAlbumArt;
use GuzzleHttp\Psr7\UriResolver;
use GuzzleHttp\Psr7\Utils;
use Psr\Http\Message\UriInterface;
use App\Entity\Repository\StationRepository;
use App\Entity\Repository\CustomFieldRepository;
use App\Entity\Interfaces\SongInterface;
use App\Entity\Station;
use App\Entity\Api\Song;
use App\Entity\StationMedia;
final class SongApiGenerator
{
@ -18,26 +23,26 @@ final class SongApiGenerator
public function __construct(
private readonly Router $router,
private readonly Entity\Repository\StationRepository $stationRepo,
private readonly Entity\Repository\CustomFieldRepository $customFieldRepo,
private readonly StationRepository $stationRepo,
private readonly CustomFieldRepository $customFieldRepo,
private readonly RemoteAlbumArt $remoteAlbumArt
) {
}
public function __invoke(
Entity\Interfaces\SongInterface $song,
?Entity\Station $station = null,
SongInterface $song,
?Station $station = null,
?UriInterface $baseUri = null,
bool $allowRemoteArt = false,
bool $isNowPlaying = false,
): Entity\Api\Song {
$response = new Entity\Api\Song();
): Song {
$response = new Song();
$response->id = $song->getSongId();
$response->text = $song->getText() ?? '';
$response->artist = $song->getArtist() ?? '';
$response->title = $song->getTitle() ?? '';
if ($song instanceof Entity\StationMedia) {
if ($song instanceof StationMedia) {
$response->album = $song->getAlbum() ?? '';
$response->genre = $song->getGenre() ?? '';
$response->isrc = $song->getIsrc() ?? '';
@ -57,12 +62,12 @@ final class SongApiGenerator
}
private function getAlbumArtUrl(
Entity\Interfaces\SongInterface $song,
?Entity\Station $station = null,
SongInterface $song,
?Station $station = null,
bool $allowRemoteArt = false,
bool $isNowPlaying = false,
): UriInterface {
if (null !== $station && $song instanceof Entity\StationMedia) {
if (null !== $station && $song instanceof StationMedia) {
$mediaUpdatedTimestamp = $song->getArtUpdatedAt();
$mediaId = $song->getUniqueId();
if (0 !== $mediaUpdatedTimestamp) {
@ -117,7 +122,7 @@ final class SongApiGenerator
$mediaFieldsRaw = $this->em->createQuery(
<<<'DQL'
SELECT smcf.field_id, smcf.value
FROM App\Entity\StationMediaCustomField smcf
FROM App\\App\Entity\StationMediaCustomField smcf
WHERE smcf.media_id = :media_id
DQL
)->setParameter('media_id', $media_id)

View File

@ -4,9 +4,11 @@ declare(strict_types=1);
namespace App\Entity\ApiGenerator;
use App\Entity;
use App\Entity\Api\NowPlaying\SongHistory;
use Psr\Http\Message\UriInterface;
use App\Entity\StationPlaylist;
use App\Entity\StationStreamer;
use App\Entity\Api\DetailedSongHistory;
final class SongHistoryApiGenerator
{
@ -16,7 +18,7 @@ final class SongHistoryApiGenerator
}
public function __invoke(
Entity\SongHistory $record,
\App\Entity\SongHistory $record,
?UriInterface $baseUri = null,
bool $allowRemoteArt = false,
bool $isNowPlaying = false,
@ -25,16 +27,16 @@ final class SongHistoryApiGenerator
$response->sh_id = $record->getIdRequired();
$response->played_at = (0 === $record->getTimestampStart())
? 0
: $record->getTimestampStart() + Entity\SongHistory::PLAYBACK_DELAY_SECONDS;
: $record->getTimestampStart() + \App\Entity\SongHistory::PLAYBACK_DELAY_SECONDS;
$response->duration = (int)$record->getDuration();
$response->is_request = ($record->getRequest() !== null);
if ($record->getPlaylist() instanceof Entity\StationPlaylist) {
if ($record->getPlaylist() instanceof StationPlaylist) {
$response->playlist = $record->getPlaylist()->getName();
} else {
$response->playlist = '';
}
if ($record->getStreamer() instanceof Entity\StationStreamer) {
if ($record->getStreamer() instanceof StationStreamer) {
$response->streamer = $record->getStreamer()->getDisplayName();
} else {
$response->streamer = '';
@ -62,7 +64,7 @@ final class SongHistoryApiGenerator
}
/**
* @param Entity\SongHistory[] $records
* @param \App\Entity\SongHistory[] $records
* @param UriInterface|null $baseUri
* @param bool $allowRemoteArt
*
@ -80,10 +82,12 @@ final class SongHistoryApiGenerator
return $apiRecords;
}
public function detailed(Entity\SongHistory $record, ?UriInterface $baseUri = null): Entity\Api\DetailedSongHistory
{
public function detailed(
\App\Entity\SongHistory $record,
?UriInterface $baseUri = null
): DetailedSongHistory {
$apiHistory = ($this)($record, $baseUri);
$response = new Entity\Api\DetailedSongHistory();
$response = new DetailedSongHistory();
$response->fromParentObject($apiHistory);
$response->listeners_start = (int)$record->getListenersStart();
$response->listeners_end = (int)$record->getListenersEnd();

View File

@ -4,10 +4,10 @@ declare(strict_types=1);
namespace App\Entity\ApiGenerator;
use App\Entity;
use App\Http\Router;
use App\Radio\Adapters;
use Psr\Http\Message\UriInterface;
use App\Entity\Station;
final class StationApiGenerator
{
@ -18,14 +18,14 @@ final class StationApiGenerator
}
public function __invoke(
Entity\Station $station,
Station $station,
?UriInterface $baseUri = null,
bool $showAllMounts = false
): Entity\Api\NowPlaying\Station {
): \App\Entity\Api\NowPlaying\Station {
$frontend = $this->adapters->getFrontendAdapter($station);
$backend = $this->adapters->getBackendAdapter($station);
$response = new Entity\Api\NowPlaying\Station();
$response = new \App\Entity\Api\NowPlaying\Station();
$response->id = (int)$station->getId();
$response->name = (string)$station->getName();
$response->shortcode = $station->getShortName();

View File

@ -4,8 +4,9 @@ declare(strict_types=1);
namespace App\Entity\ApiGenerator;
use App\Entity;
use Psr\Http\Message\UriInterface;
use App\Entity\StationQueue;
use App\Entity\StationPlaylist;
final class StationQueueApiGenerator
{
@ -15,17 +16,17 @@ final class StationQueueApiGenerator
}
public function __invoke(
Entity\StationQueue $record,
StationQueue $record,
?UriInterface $baseUri = null,
bool $allowRemoteArt = false
): Entity\Api\NowPlaying\StationQueue {
$response = new Entity\Api\NowPlaying\StationQueue();
): \App\Entity\Api\NowPlaying\StationQueue {
$response = new \App\Entity\Api\NowPlaying\StationQueue();
$response->cued_at = $record->getTimestampCued();
$response->played_at = $record->getTimestampPlayed();
$response->duration = (int)$record->getDuration();
$response->is_request = $record->getRequest() !== null;
if ($record->getPlaylist() instanceof Entity\StationPlaylist) {
if ($record->getPlaylist() instanceof StationPlaylist) {
$response->playlist = $record->getPlaylist()->getName();
} else {
$response->playlist = '';

View File

@ -4,17 +4,17 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use Carbon\CarbonImmutable;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use App\Entity\Enums\AnalyticsIntervals;
final class Analytics extends AbstractFixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
$stations = $manager->getRepository(Entity\Station::class)->findAll();
$stations = $manager->getRepository(\App\Entity\Station::class)->findAll();
$midnight_utc = CarbonImmutable::now('UTC')->setTime(0, 0);
@ -27,7 +27,7 @@ final class Analytics extends AbstractFixture implements DependentFixtureInterfa
$day_unique = 0;
foreach ($stations as $station) {
/** @var Entity\Station $station */
/** @var \App\Entity\Station $station */
$station_listeners = random_int(10, 50);
$station_min = random_int(1, $station_listeners);
$station_max = random_int($station_listeners, 150);
@ -39,10 +39,10 @@ final class Analytics extends AbstractFixture implements DependentFixtureInterfa
$day_listeners += $station_listeners;
$day_unique += $station_unique;
$stationPoint = new Entity\Analytics(
$stationPoint = new \App\Entity\Analytics(
$day,
$station,
Entity\Enums\AnalyticsIntervals::Daily,
AnalyticsIntervals::Daily,
$station_min,
$station_max,
$station_listeners,
@ -51,10 +51,10 @@ final class Analytics extends AbstractFixture implements DependentFixtureInterfa
$manager->persist($stationPoint);
}
$totalPoint = new Entity\Analytics(
$totalPoint = new \App\Entity\Analytics(
$day,
null,
Entity\Enums\AnalyticsIntervals::Daily,
AnalyticsIntervals::Daily,
$day_min,
$day_max,
$day_listeners,

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use App\Security\SplitToken;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
@ -17,10 +16,10 @@ final class ApiKey extends AbstractFixture implements DependentFixtureInterface
$demo_api_key = getenv('INIT_DEMO_API_KEY');
if (!empty($demo_api_key) && $this->hasReference('demo_user')) {
/** @var Entity\User $demo_user */
/** @var \App\Entity\User $demo_user */
$demo_user = $this->getReference('demo_user');
$api_key = new Entity\ApiKey($demo_user, SplitToken::fromKeyString($demo_api_key));
$api_key = new \App\Entity\ApiKey($demo_user, SplitToken::fromKeyString($demo_api_key));
$api_key->setComment('Demo User');
$manager->persist($api_key);
@ -29,10 +28,10 @@ final class ApiKey extends AbstractFixture implements DependentFixtureInterface
$admin_api_key = getenv('INIT_ADMIN_API_KEY');
if (!empty($admin_api_key) && $this->hasReference('admin_user')) {
/** @var Entity\User $admin_user */
/** @var \App\Entity\User $admin_user */
$admin_user = $this->getReference('admin_user');
$api_key = new Entity\ApiKey($admin_user, SplitToken::fromKeyString($admin_api_key));
$api_key = new \App\Entity\ApiKey($admin_user, SplitToken::fromKeyString($admin_api_key));
$api_key->setComment('Administrator');
$manager->persist($api_key);

View File

@ -4,21 +4,21 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use App\Entity\PodcastCategory;
final class Podcast extends AbstractFixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
/** @var Entity\Station $station */
/** @var \App\Entity\Station $station */
$station = $this->getReference('station');
$podcastStorage = $station->getPodcastsStorageLocation();
$podcast = new Entity\Podcast($podcastStorage);
$podcast = new \App\Entity\Podcast($podcastStorage);
$podcast->setTitle('The AzuraTest Podcast');
$podcast->setLink('https://demo.azuracast.com');
@ -28,7 +28,7 @@ final class Podcast extends AbstractFixture implements DependentFixtureInterface
$podcast->setEmail('demo@azuracast.com');
$manager->persist($podcast);
$category = new Entity\PodcastCategory($podcast, 'Technology');
$category = new PodcastCategory($podcast, 'Technology');
$manager->persist($category);
$manager->flush();

View File

@ -4,17 +4,18 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\Finder\Finder;
use App\Entity\Repository\PodcastEpisodeRepository;
use App\Entity\Repository\StorageLocationRepository;
final class PodcastEpisode extends AbstractFixture implements DependentFixtureInterface
{
public function __construct(
protected Entity\Repository\PodcastEpisodeRepository $episodeRepo,
protected Entity\Repository\StorageLocationRepository $storageLocationRepo
protected PodcastEpisodeRepository $episodeRepo,
protected StorageLocationRepository $storageLocationRepo
) {
}
@ -26,7 +27,7 @@ final class PodcastEpisode extends AbstractFixture implements DependentFixtureIn
return;
}
/** @var Entity\Podcast $podcast */
/** @var \App\Entity\Podcast $podcast */
$podcast = $this->getReference('podcast');
$fs = $this->storageLocationRepo->getAdapter($podcast->getStorageLocation())
@ -61,7 +62,7 @@ final class PodcastEpisode extends AbstractFixture implements DependentFixtureIn
copy($filePath, $tempPath);
// Create an episode and associate it with the podcast/media.
$episode = new Entity\PodcastEpisode($podcast);
$episode = new \App\Entity\PodcastEpisode($podcast);
/** @noinspection NonSecureArrayRandUsageInspection */
$podcastName = $podcastNames[array_rand($podcastNames)];

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Persistence\ObjectManager;
@ -12,10 +11,10 @@ final class Role extends AbstractFixture
{
public function load(ObjectManager $manager): void
{
$admin_role = new Entity\Role();
$admin_role = new \App\Entity\Role();
$admin_role->setName('Super Administrator');
$demo_role = new Entity\Role();
$demo_role = new \App\Entity\Role();
$demo_role->setName('Demo Account');
$manager->persist($admin_role);

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use App\Enums\GlobalPermissions;
use App\Enums\StationPermissions;
use Doctrine\Common\DataFixtures\AbstractFixture;
@ -15,7 +14,7 @@ final class RolePermission extends AbstractFixture implements DependentFixtureIn
{
public function load(ObjectManager $manager): void
{
/** @var Entity\Station $station */
/** @var \App\Entity\Station $station */
$station = $this->getReference('station');
$permissions = [
@ -35,11 +34,11 @@ final class RolePermission extends AbstractFixture implements DependentFixtureIn
];
foreach ($permissions as $role_reference => $perm_names) {
/** @var Entity\Role $role */
/** @var \App\Entity\Role $role */
$role = $this->getReference($role_reference);
foreach ($perm_names as $perm_name) {
$rp = new Entity\RolePermission($role, $perm_name[1], $perm_name[0]);
$rp = new \App\Entity\RolePermission($role, $perm_name[1], $perm_name[0]);
$manager->persist($rp);
}
}

View File

@ -4,19 +4,19 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Persistence\ObjectManager;
use App\Entity\Enums\AnalyticsLevel;
final class Settings extends AbstractFixture
{
public function load(ObjectManager $manager): void
{
foreach ($manager->getRepository(Entity\Settings::class)->findAll() as $row) {
foreach ($manager->getRepository(\App\Entity\Settings::class)->findAll() as $row) {
$manager->remove($row);
}
$settings = new Entity\Settings();
$settings = new \App\Entity\Settings();
$settings->setBaseUrl((string)(getenv('INIT_BASE_URL') ?: 'http://docker.local'));
$settings->setInstanceName((string)(getenv('INIT_INSTANCE_NAME') ?: 'local test'));
$settings->setGeoliteLicenseKey((string)(getenv('INIT_GEOLITE_LICENSE_KEY') ?: ''));
@ -29,7 +29,7 @@ final class Settings extends AbstractFixture
$settings->setEnableAdvancedFeatures(true);
if (!empty(getenv('INIT_DEMO_API_KEY') ?: '')) {
$settings->setAnalytics(Entity\Enums\AnalyticsLevel::NoIp);
$settings->setAnalytics(AnalyticsLevel::NoIp);
$settings->setCheckForUpdates(false);
$settings->setPublicCustomJs(

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use App\Radio\Enums\BackendAdapters;
use App\Radio\Enums\FrontendAdapters;
use Doctrine\Common\DataFixtures\AbstractFixture;
@ -14,7 +13,7 @@ final class Station extends AbstractFixture
{
public function load(ObjectManager $manager): void
{
$station = new Entity\Station();
$station = new \App\Entity\Station();
$station->setName('AzuraTest Radio');
$station->setDescription('A test radio station.');
$station->setEnableRequests(true);

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use App\Radio\Enums\StreamFormats;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
@ -14,22 +13,22 @@ final class StationHlsStream extends AbstractFixture implements DependentFixture
{
public function load(ObjectManager $manager): void
{
/** @var Entity\Station $station */
/** @var \App\Entity\Station $station */
$station = $this->getReference('station');
$mountLofi = new Entity\StationHlsStream($station);
$mountLofi = new \App\Entity\StationHlsStream($station);
$mountLofi->setName('aac_lofi');
$mountLofi->setFormat(StreamFormats::Aac);
$mountLofi->setBitrate(64);
$manager->persist($mountLofi);
$mountMidfi = new Entity\StationHlsStream($station);
$mountMidfi = new \App\Entity\StationHlsStream($station);
$mountMidfi->setName('aac_midfi');
$mountMidfi->setFormat(StreamFormats::Aac);
$mountMidfi->setBitrate(128);
$manager->persist($mountMidfi);
$mountHifi = new Entity\StationHlsStream($station);
$mountHifi = new \App\Entity\StationHlsStream($station);
$mountHifi->setName('aac_hifi');
$mountHifi->setFormat(StreamFormats::Aac);
$mountHifi->setBitrate(256);

View File

@ -4,18 +4,19 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use App\Media\MediaProcessor;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\Finder\Finder;
use App\Entity\Repository\StorageLocationRepository;
use App\Entity\StationPlaylistMedia;
final class StationMedia extends AbstractFixture implements DependentFixtureInterface
{
public function __construct(
private readonly MediaProcessor $mediaProcessor,
private readonly Entity\Repository\StorageLocationRepository $storageLocationRepo,
private readonly StorageLocationRepository $storageLocationRepo,
) {
}
@ -27,13 +28,13 @@ final class StationMedia extends AbstractFixture implements DependentFixtureInte
return;
}
/** @var Entity\Station $station */
/** @var \App\Entity\Station $station */
$station = $this->getReference('station');
$mediaStorage = $station->getMediaStorageLocation();
$fs = $this->storageLocationRepo->getAdapter($mediaStorage)->getFilesystem();
/** @var Entity\StationPlaylist $playlist */
/** @var \App\Entity\StationPlaylist $playlist */
$playlist = $this->getReference('station_playlist');
$finder = (new Finder())
@ -56,7 +57,7 @@ final class StationMedia extends AbstractFixture implements DependentFixtureInte
$manager->persist($mediaRow);
// Add the file to the playlist.
$spmRow = new Entity\StationPlaylistMedia($playlist, $mediaRow);
$spmRow = new StationPlaylistMedia($playlist, $mediaRow);
$spmRow->setWeight(1);
$manager->persist($spmRow);
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
@ -13,15 +12,15 @@ final class StationMount extends AbstractFixture implements DependentFixtureInte
{
public function load(ObjectManager $manager): void
{
/** @var Entity\Station $station */
/** @var \App\Entity\Station $station */
$station = $this->getReference('station');
$mount_radio = new Entity\StationMount($station);
$mount_radio = new \App\Entity\StationMount($station);
$mount_radio->setName('/radio.mp3');
$mount_radio->setIsDefault(true);
$manager->persist($mount_radio);
$mount_mobile = new Entity\StationMount($station);
$mount_mobile = new \App\Entity\StationMount($station);
$mount_mobile->setName('/mobile.mp3');
$mount_mobile->setAutodjBitrate(64);
$manager->persist($mount_mobile);

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
@ -13,10 +12,10 @@ final class StationPlaylist extends AbstractFixture implements DependentFixtureI
{
public function load(ObjectManager $manager): void
{
/** @var Entity\Station $station */
/** @var \App\Entity\Station $station */
$station = $this->getReference('station');
$playlist = new Entity\StationPlaylist($station);
$playlist = new \App\Entity\StationPlaylist($station);
$playlist->setName('default');
$manager->persist($playlist);
$manager->flush();

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Entity\Fixture;
use App\Entity;
use App\Enums\SupportedThemes;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
@ -18,12 +17,12 @@ final class User extends AbstractFixture implements DependentFixtureInterface
$admin_password = getenv('INIT_ADMIN_PASSWORD');
if (!empty($admin_email) && !empty($admin_password)) {
$demo_user = new Entity\User();
$demo_user = new \App\Entity\User();
$demo_user->setEmail('demo@azuracast.com');
$demo_user->setNewPassword('demo');
$demo_user->setName('AzuraCast Demo User');
/** @var Entity\Role $demoRole */
/** @var \App\Entity\Role $demoRole */
$demoRole = $this->getReference('demo_role');
$demo_user->getRoles()->add($demoRole);
@ -31,13 +30,13 @@ final class User extends AbstractFixture implements DependentFixtureInterface
$this->addReference('demo_user', $demo_user);
$admin_user = new Entity\User();
$admin_user = new \App\Entity\User();
$admin_user->setEmail($admin_email);
$admin_user->setName('System Administrator');
$admin_user->setNewPassword($admin_password);
$admin_user->setTheme(SupportedThemes::Browser);
/** @var Entity\Role $adminRole */
/** @var \App\Entity\Role $adminRole */
$adminRole = $this->getReference('admin_role');
$admin_user->getRoles()->add($adminRole);

View File

@ -4,9 +4,9 @@ declare(strict_types=1);
namespace App\Entity\Interfaces;
use App\Entity;
use App\Entity\Station;
interface StationCloneAwareInterface extends StationAwareInterface
{
public function setStation(Entity\Station $station): void;
public function setStation(Station $station): void;
}

View File

@ -5,11 +5,11 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\Repository;
use App\Entity;
use App\Security\SplitToken;
use App\Entity\User;
/**
* @template TEntity of Entity\ApiKey|Entity\UserLoginToken
* @template TEntity of \App\Entity\ApiKey|\App\Entity\UserLoginToken
* @extends Repository<TEntity>
*/
abstract class AbstractSplitTokenRepository extends Repository
@ -19,7 +19,7 @@ abstract class AbstractSplitTokenRepository extends Repository
*
* @param string $key
*/
public function authenticate(string $key): ?Entity\User
public function authenticate(string $key): ?User
{
$userSuppliedToken = SplitToken::fromKeyString($key);

View File

@ -5,13 +5,14 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\Repository;
use App\Entity;
use App\Utilities\DateRange;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use App\Entity\Station;
use App\Entity\Enums\AnalyticsIntervals;
/**
* @extends Repository<Entity\Analytics>
* @extends Repository<\App\Entity\Analytics>
*/
final class AnalyticsRepository extends Repository
{
@ -19,13 +20,13 @@ final class AnalyticsRepository extends Repository
* @return mixed[]
*/
public function findForStationInRange(
Entity\Station $station,
Station $station,
DateRange $dateRange,
Entity\Enums\AnalyticsIntervals $type = Entity\Enums\AnalyticsIntervals::Daily
AnalyticsIntervals $type = AnalyticsIntervals::Daily
): array {
return $this->em->createQuery(
<<<'DQL'
SELECT a FROM App\Entity\Analytics a
SELECT a FROM App\\App\Entity\Analytics a
WHERE a.station = :station AND a.type = :type AND a.moment BETWEEN :start AND :end
DQL
)->setParameter('station', $station)
@ -39,7 +40,7 @@ final class AnalyticsRepository extends Repository
{
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\Analytics a
DELETE FROM App\\App\Entity\Analytics a
DQL
)->execute();
}
@ -51,23 +52,23 @@ final class AnalyticsRepository extends Repository
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\Analytics a
DELETE FROM App\\App\Entity\Analytics a
WHERE a.type = :type AND a.moment <= :threshold
DQL
)->setParameter('type', Entity\Enums\AnalyticsIntervals::Hourly)
)->setParameter('type', AnalyticsIntervals::Hourly)
->setParameter('threshold', $hourlyRetention)
->execute();
}
public function clearSingleMetric(
Entity\Enums\AnalyticsIntervals $type,
AnalyticsIntervals $type,
CarbonInterface $moment,
?Entity\Station $station = null
?Station $station = null
): void {
if (null === $station) {
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\Analytics a
DELETE FROM App\\App\Entity\Analytics a
WHERE a.station IS NULL AND a.type = :type AND a.moment = :moment
DQL
)->setParameter('type', $type)
@ -76,7 +77,7 @@ final class AnalyticsRepository extends Repository
} else {
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\Analytics a
DELETE FROM App\\App\Entity\Analytics a
WHERE a.station = :station AND a.type = :type AND a.moment = :moment
DQL
)->setParameter('station', $station)

View File

@ -4,10 +4,10 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Entity;
use App\Entity\ApiKey;
/**
* @extends AbstractSplitTokenRepository<Entity\ApiKey>
* @extends AbstractSplitTokenRepository<ApiKey>
*/
final class ApiKeyRepository extends AbstractSplitTokenRepository
{

View File

@ -5,22 +5,25 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\Repository;
use App\Entity;
use App\Entity\Station;
use App\Entity\StationMedia;
use App\Entity\CustomField;
use App\Entity\StationMediaCustomField;
/**
* @extends Repository<Entity\CustomField>
* @extends Repository<\App\Entity\CustomField>
*/
final class CustomFieldRepository extends Repository
{
/**
* @return Entity\CustomField[]
* @return \App\Entity\CustomField[]
*/
public function getAutoAssignableFields(): array
{
$fields = [];
foreach ($this->repository->findAll() as $field) {
/** @var Entity\CustomField $field */
/** @var \App\Entity\CustomField $field */
if (!$field->hasAutoAssign()) {
continue;
}
@ -43,13 +46,13 @@ final class CustomFieldRepository extends Repository
$fieldsRaw = $this->em->createQuery(
<<<'DQL'
SELECT cf.id, cf.name, cf.short_name
FROM App\Entity\CustomField cf
FROM App\\App\Entity\CustomField cf
ORDER BY cf.name ASC
DQL
)->getArrayResult();
foreach ($fieldsRaw as $row) {
$fields[$row['id']] = $row['short_name'] ?? Entity\Station::generateShortName($row['name']);
$fields[$row['id']] = $row['short_name'] ?? Station::generateShortName($row['name']);
}
}
@ -59,16 +62,16 @@ final class CustomFieldRepository extends Repository
/**
* Retrieve a key-value representation of all custom metadata for the specified media.
*
* @param Entity\StationMedia $media
* @param \App\Entity\StationMedia $media
*
* @return mixed[]
*/
public function getCustomFields(Entity\StationMedia $media): array
public function getCustomFields(StationMedia $media): array
{
$metadata_raw = $this->em->createQuery(
<<<'DQL'
SELECT cf.short_name, e.value
FROM App\Entity\StationMediaCustomField e JOIN e.field cf
FROM App\\App\Entity\StationMediaCustomField e JOIN e.field cf
WHERE e.media_id = :media_id
DQL
)->setParameter('media_id', $media->getId())
@ -85,25 +88,25 @@ final class CustomFieldRepository extends Repository
/**
* Set the custom metadata for a specified station based on a provided key-value array.
*
* @param Entity\StationMedia $media
* @param \App\Entity\StationMedia $media
* @param array $custom_fields
*/
public function setCustomFields(Entity\StationMedia $media, array $custom_fields): void
public function setCustomFields(StationMedia $media, array $custom_fields): void
{
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\StationMediaCustomField e WHERE e.media_id = :media_id
DELETE FROM App\\App\Entity\StationMediaCustomField e WHERE e.media_id = :media_id
DQL
)->setParameter('media_id', $media->getId())
->execute();
foreach ($custom_fields as $field_id => $field_value) {
$field = is_numeric($field_id)
? $this->em->find(Entity\CustomField::class, $field_id)
: $this->em->getRepository(Entity\CustomField::class)->findOneBy(['short_name' => $field_id]);
? $this->em->find(CustomField::class, $field_id)
: $this->em->getRepository(CustomField::class)->findOneBy(['short_name' => $field_id]);
if ($field instanceof Entity\CustomField) {
$record = new Entity\StationMediaCustomField($media, $field);
if ($field instanceof CustomField) {
$record = new StationMediaCustomField($media, $field);
$record->setValue($field_value);
$this->em->persist($record);
}

View File

@ -7,7 +7,6 @@ namespace App\Entity\Repository;
use App\Container\LoggerAwareTrait;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Doctrine\Repository;
use App\Entity;
use App\Service\DeviceDetector;
use App\Service\IpGeolocation;
use App\Utilities\File;
@ -18,14 +17,17 @@ use League\Csv\Writer;
use NowPlaying\Result\Client;
use Symfony\Component\Filesystem\Filesystem;
use Throwable;
use App\Entity\Traits\TruncateStrings;
use App\Entity\Listener;
use App\Entity\Station;
/**
* @extends Repository<Entity\Listener>
* @extends Repository<\App\Entity\Listener>
*/
final class ListenerRepository extends Repository
{
use LoggerAwareTrait;
use Entity\Traits\TruncateStrings;
use TruncateStrings;
private string $tableName;
@ -38,19 +40,19 @@ final class ListenerRepository extends Repository
) {
parent::__construct($em);
$this->tableName = $this->em->getClassMetadata(Entity\Listener::class)->getTableName();
$this->tableName = $this->em->getClassMetadata(Listener::class)->getTableName();
$this->conn = $this->em->getConnection();
}
/**
* Get the number of unique listeners for a station during a specified time period.
*
* @param Entity\Station $station
* @param \App\Entity\Station $station
* @param DateTimeInterface|int $start
* @param DateTimeInterface|int $end
*/
public function getUniqueListeners(
Entity\Station $station,
Station $station,
DateTimeInterface|int $start,
DateTimeInterface|int $end
): int {
@ -64,7 +66,7 @@ final class ListenerRepository extends Repository
return (int)$this->em->createQuery(
<<<'DQL'
SELECT COUNT(DISTINCT l.listener_hash)
FROM App\Entity\Listener l
FROM App\\App\Entity\Listener l
WHERE l.station_id = :station_id
AND l.timestamp_start <= :time_end
AND l.timestamp_end >= :time_start
@ -75,12 +77,12 @@ final class ListenerRepository extends Repository
->getSingleScalarResult();
}
public function iterateLiveListenersArray(Entity\Station $station): iterable
public function iterateLiveListenersArray(Station $station): iterable
{
$query = $this->em->createQuery(
<<<'DQL'
SELECT l
FROM App\Entity\Listener l
FROM App\\App\Entity\Listener l
WHERE l.station = :station
AND l.timestamp_end = 0
ORDER BY l.timestamp_start ASC
@ -93,17 +95,17 @@ final class ListenerRepository extends Repository
/**
* Update listener data for a station.
*
* @param Entity\Station $station
* @param \App\Entity\Station $station
* @param Client[] $clients
*/
public function update(Entity\Station $station, array $clients): void
public function update(Station $station, array $clients): void
{
$this->em->wrapInTransaction(
function () use ($station, $clients): void {
$existingClientsRaw = $this->em->createQuery(
<<<'DQL'
SELECT l.id, l.listener_hash
FROM App\Entity\Listener l
FROM App\\App\Entity\Listener l
WHERE l.station = :station
AND l.timestamp_end = 0
DQL
@ -125,7 +127,7 @@ final class ListenerRepository extends Repository
if (!empty($existingClients)) {
$this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\Listener l
UPDATE App\\App\Entity\Listener l
SET l.timestamp_end = :time
WHERE l.id IN (:ids)
DQL
@ -138,7 +140,7 @@ final class ListenerRepository extends Repository
}
private function batchAddClients(
Entity\Station $station,
Station $station,
array &$clients,
array &$existingClients
): void {
@ -162,7 +164,7 @@ final class ListenerRepository extends Repository
$csvColumns = null;
foreach ($clients as $client) {
$identifier = Entity\Listener::calculateListenerHash($client);
$identifier = Listener::calculateListenerHash($client);
// Check for an existing record for this client.
if (isset($existingClients[$identifier])) {
@ -215,7 +217,7 @@ final class ListenerRepository extends Repository
$this->ipGeolocation->saveCache();
}
private function batchAddRow(Entity\Station $station, Client $client): array
private function batchAddRow(Station $station, Client $client): array
{
$record = [
'station_id' => $station->getId(),
@ -224,7 +226,7 @@ final class ListenerRepository extends Repository
'listener_uid' => (int)$client->uid,
'listener_user_agent' => $this->truncateString($client->userAgent ?? ''),
'listener_ip' => $client->ip,
'listener_hash' => Entity\Listener::calculateListenerHash($client),
'listener_hash' => Listener::calculateListenerHash($client),
'mount_id' => null,
'remote_id' => null,
'hls_stream_id' => null,
@ -308,7 +310,7 @@ final class ListenerRepository extends Repository
{
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\Listener l
DELETE FROM App\\App\Entity\Listener l
DQL
)->execute();
}
@ -321,7 +323,7 @@ final class ListenerRepository extends Repository
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\Listener sh
DELETE FROM App\\App\Entity\Listener sh
WHERE sh.timestamp_start != 0
AND sh.timestamp_start <= :threshold
DQL

View File

@ -6,7 +6,6 @@ namespace App\Entity\Repository;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Doctrine\Repository;
use App\Entity;
use App\Exception\InvalidPodcastMediaFileException;
use App\Exception\StorageLocationFullException;
use App\Flysystem\ExtendedFilesystemInterface;
@ -14,9 +13,14 @@ use App\Media\AlbumArt;
use App\Media\MetadataManager;
use League\Flysystem\UnableToDeleteFile;
use League\Flysystem\UnableToRetrieveMetadata;
use App\Entity\Station;
use App\Entity\PodcastEpisode;
use App\Entity\StorageLocation;
use App\Entity\Podcast;
use App\Entity\PodcastMedia;
/**
* @extends Repository<Entity\PodcastEpisode>
* @extends Repository<\App\Entity\PodcastEpisode>
*/
final class PodcastEpisodeRepository extends Repository
{
@ -28,7 +32,7 @@ final class PodcastEpisodeRepository extends Repository
parent::__construct($entityManager);
}
public function fetchEpisodeForStation(Entity\Station $station, string $episodeId): ?Entity\PodcastEpisode
public function fetchEpisodeForStation(Station $station, string $episodeId): ?PodcastEpisode
{
return $this->fetchEpisodeForStorageLocation(
$station->getPodcastsStorageLocation(),
@ -37,13 +41,13 @@ final class PodcastEpisodeRepository extends Repository
}
public function fetchEpisodeForStorageLocation(
Entity\StorageLocation $storageLocation,
StorageLocation $storageLocation,
string $episodeId
): ?Entity\PodcastEpisode {
): ?PodcastEpisode {
return $this->em->createQuery(
<<<'DQL'
SELECT pe
FROM App\Entity\PodcastEpisode pe
FROM App\\App\Entity\PodcastEpisode pe
JOIN pe.podcast p
WHERE pe.id = :id
AND p.storage_location = :storageLocation
@ -54,13 +58,13 @@ final class PodcastEpisodeRepository extends Repository
}
/**
* @return Entity\PodcastEpisode[]
* @return \App\Entity\PodcastEpisode[]
*/
public function fetchPublishedEpisodesForPodcast(Entity\Podcast $podcast): array
public function fetchPublishedEpisodesForPodcast(Podcast $podcast): array
{
$episodes = $this->em->createQueryBuilder()
->select('pe')
->from(Entity\PodcastEpisode::class, 'pe')
->from(PodcastEpisode::class, 'pe')
->where('pe.podcast = :podcast')
->setParameter('podcast', $podcast)
->orderBy('pe.created_at', 'DESC')
@ -69,14 +73,14 @@ final class PodcastEpisodeRepository extends Repository
return array_filter(
$episodes,
static function (Entity\PodcastEpisode $episode) {
static function (PodcastEpisode $episode) {
return $episode->isPublished();
}
);
}
public function writeEpisodeArt(
Entity\PodcastEpisode $episode,
PodcastEpisode $episode,
string $rawArtworkString
): void {
$episodeArtworkString = AlbumArt::resize($rawArtworkString);
@ -90,7 +94,7 @@ final class PodcastEpisodeRepository extends Repository
throw new StorageLocationFullException();
}
$episodeArtworkPath = Entity\PodcastEpisode::getArtPath($episode->getIdRequired());
$episodeArtworkPath = PodcastEpisode::getArtPath($episode->getIdRequired());
$fs->write($episodeArtworkPath, $episodeArtworkString);
$storageLocation->addStorageUsed($episodeArtworkSize);
@ -101,10 +105,10 @@ final class PodcastEpisodeRepository extends Repository
}
public function removeEpisodeArt(
Entity\PodcastEpisode $episode,
PodcastEpisode $episode,
?ExtendedFilesystemInterface $fs = null
): void {
$artworkPath = Entity\PodcastEpisode::getArtPath($episode->getIdRequired());
$artworkPath = PodcastEpisode::getArtPath($episode->getIdRequired());
$storageLocation = $episode->getPodcast()->getStorageLocation();
$fs ??= $this->storageLocationRepo->getAdapter($storageLocation)
@ -129,7 +133,7 @@ final class PodcastEpisodeRepository extends Repository
}
public function uploadMedia(
Entity\PodcastEpisode $episode,
PodcastEpisode $episode,
string $originalPath,
string $uploadPath,
?ExtendedFilesystemInterface $fs = null
@ -155,7 +159,7 @@ final class PodcastEpisodeRepository extends Repository
}
$existingMedia = $episode->getMedia();
if ($existingMedia instanceof Entity\PodcastMedia) {
if ($existingMedia instanceof PodcastMedia) {
$this->deleteMedia($existingMedia, $fs);
$episode->setMedia(null);
}
@ -163,7 +167,7 @@ final class PodcastEpisodeRepository extends Repository
$ext = pathinfo($originalPath, PATHINFO_EXTENSION);
$path = $podcast->getId() . '/' . $episode->getId() . '.' . $ext;
$podcastMedia = new Entity\PodcastMedia($storageLocation);
$podcastMedia = new PodcastMedia($storageLocation);
$podcastMedia->setPath($path);
$podcastMedia->setOriginalName(basename($originalPath));
@ -195,7 +199,7 @@ final class PodcastEpisodeRepository extends Repository
}
public function deleteMedia(
Entity\PodcastMedia $media,
PodcastMedia $media,
?ExtendedFilesystemInterface $fs = null
): void {
$storageLocation = $media->getStorageLocation();
@ -223,7 +227,7 @@ final class PodcastEpisodeRepository extends Repository
}
public function delete(
Entity\PodcastEpisode $episode,
PodcastEpisode $episode,
?ExtendedFilesystemInterface $fs = null
): void {
$fs ??= $this->storageLocationRepo->getAdapter($episode->getPodcast()->getStorageLocation())

View File

@ -6,15 +6,17 @@ namespace App\Entity\Repository;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Doctrine\Repository;
use App\Entity;
use App\Exception\StorageLocationFullException;
use App\Flysystem\ExtendedFilesystemInterface;
use App\Media\AlbumArt;
use League\Flysystem\UnableToDeleteFile;
use League\Flysystem\UnableToRetrieveMetadata;
use App\Entity\Station;
use App\Entity\Podcast;
use App\Entity\StorageLocation;
/**
* @extends Repository<Entity\Podcast>
* @extends Repository<\App\Entity\Podcast>
*/
final class PodcastRepository extends Repository
{
@ -26,15 +28,15 @@ final class PodcastRepository extends Repository
parent::__construct($entityManager);
}
public function fetchPodcastForStation(Entity\Station $station, string $podcastId): ?Entity\Podcast
public function fetchPodcastForStation(Station $station, string $podcastId): ?Podcast
{
return $this->fetchPodcastForStorageLocation($station->getPodcastsStorageLocation(), $podcastId);
}
public function fetchPodcastForStorageLocation(
Entity\StorageLocation $storageLocation,
StorageLocation $storageLocation,
string $podcastId
): ?Entity\Podcast {
): ?Podcast {
return $this->repository->findOneBy(
[
'id' => $podcastId,
@ -44,14 +46,14 @@ final class PodcastRepository extends Repository
}
/**
* @return Entity\Podcast[]
* @return \App\Entity\Podcast[]
*/
public function fetchPublishedPodcastsForStation(Entity\Station $station): array
public function fetchPublishedPodcastsForStation(Station $station): array
{
$podcasts = $this->em->createQuery(
<<<'DQL'
SELECT p, pe
FROM App\Entity\Podcast p
FROM App\\App\Entity\Podcast p
LEFT JOIN p.episodes pe
WHERE p.storage_location = :storageLocation
DQL
@ -60,7 +62,7 @@ final class PodcastRepository extends Repository
return array_filter(
$podcasts,
static function (Entity\Podcast $podcast) {
static function (Podcast $podcast) {
foreach ($podcast->getEpisodes() as $episode) {
if ($episode->isPublished()) {
return true;
@ -73,7 +75,7 @@ final class PodcastRepository extends Repository
}
public function writePodcastArt(
Entity\Podcast $podcast,
Podcast $podcast,
string $rawArtworkString,
?ExtendedFilesystemInterface $fs = null
): void {
@ -87,7 +89,7 @@ final class PodcastRepository extends Repository
throw new StorageLocationFullException();
}
$podcastArtworkPath = Entity\Podcast::getArtPath($podcast->getIdRequired());
$podcastArtworkPath = Podcast::getArtPath($podcast->getIdRequired());
$fs->write($podcastArtworkPath, $podcastArtworkString);
$storageLocation->addStorageUsed($podcastArtworkSize);
@ -98,13 +100,13 @@ final class PodcastRepository extends Repository
}
public function removePodcastArt(
Entity\Podcast $podcast,
Podcast $podcast,
?ExtendedFilesystemInterface $fs = null
): void {
$storageLocation = $podcast->getStorageLocation();
$fs ??= $this->storageLocationRepo->getAdapter($storageLocation)->getFilesystem();
$artworkPath = Entity\Podcast::getArtPath($podcast->getIdRequired());
$artworkPath = Podcast::getArtPath($podcast->getIdRequired());
try {
$size = $fs->fileSize($artworkPath);
@ -125,7 +127,7 @@ final class PodcastRepository extends Repository
}
public function delete(
Entity\Podcast $podcast,
Podcast $podcast,
?ExtendedFilesystemInterface $fs = null
): void {
$fs ??= $this->storageLocationRepo->getAdapter($podcast->getStorageLocation())

View File

@ -5,25 +5,26 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\Repository;
use App\Entity;
use App\Enums\GlobalPermissions;
use App\Entity\Role;
use App\Entity\RolePermission;
/**
* @extends Repository<Entity\RolePermission>
* @extends Repository<\App\Entity\RolePermission>
*/
final class RolePermissionRepository extends Repository
{
/**
* @param Entity\Role $role
* @param \App\Entity\Role $role
*
* @return mixed[]
*/
public function getActionsForRole(Entity\Role $role): array
public function getActionsForRole(Role $role): array
{
$role_has_action = $this->em->createQuery(
<<<'DQL'
SELECT e
FROM App\Entity\RolePermission e
FROM App\\App\Entity\RolePermission e
WHERE e.role_id = :role_id
DQL
)->setParameter('role_id', $role->getId())
@ -41,27 +42,27 @@ final class RolePermissionRepository extends Repository
return $result;
}
public function ensureSuperAdministratorRole(): Entity\Role
public function ensureSuperAdministratorRole(): Role
{
$superAdminRole = $this->em->createQuery(
<<<'DQL'
SELECT r FROM
App\Entity\Role r LEFT JOIN r.permissions rp
App\\App\Entity\Role r LEFT JOIN r.permissions rp
WHERE rp.station IS NULL AND rp.action_name = :action
DQL
)->setParameter('action', GlobalPermissions::All->value)
->setMaxResults(1)
->getOneOrNullResult();
if ($superAdminRole instanceof Entity\Role) {
if ($superAdminRole instanceof Role) {
return $superAdminRole;
}
$newRole = new Entity\Role();
$newRole = new Role();
$newRole->setName('Super Administrator');
$this->em->persist($newRole);
$newPerm = new Entity\RolePermission($newRole, null, GlobalPermissions::All);
$newPerm = new RolePermission($newRole, null, GlobalPermissions::All);
$this->em->persist($newPerm);
$this->em->flush();

View File

@ -5,10 +5,10 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\Repository;
use App\Entity;
use App\Entity\Role;
/**
* @extends Repository<Entity\Role>
* @extends Repository<Role>
*/
final class RoleRepository extends Repository
{

View File

@ -6,18 +6,18 @@ namespace App\Entity\Repository;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Doctrine\Repository;
use App\Entity;
use App\Exception\ValidationException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use App\Entity\Settings;
/**
* @extends Repository<Entity\Settings>
* @extends Repository<\App\Entity\Settings>
*/
final class SettingsRepository extends Repository
{
protected string $entityClass = Entity\Settings::class;
protected string $entityClass = Settings::class;
public function __construct(
ReloadableEntityManagerInterface $em,
@ -27,21 +27,21 @@ final class SettingsRepository extends Repository
parent::__construct($em);
}
public function readSettings(): Entity\Settings
public function readSettings(): Settings
{
static $settingsId = null;
if (null !== $settingsId) {
$settings = $this->repository->find($settingsId);
if ($settings instanceof Entity\Settings) {
if ($settings instanceof Settings) {
return $settings;
}
}
$settings = $this->repository->findOneBy([]);
if (!($settings instanceof Entity\Settings)) {
$settings = new Entity\Settings();
if (!($settings instanceof Settings)) {
$settings = new Settings();
$this->em->persist($settings);
$this->em->flush();
}
@ -52,9 +52,9 @@ final class SettingsRepository extends Repository
}
/**
* @param Entity\Settings|array $settingsObj
* @param \App\Entity\Settings|array $settingsObj
*/
public function writeSettings(Entity\Settings|array $settingsObj): void
public function writeSettings(Settings|array $settingsObj): void
{
if (is_array($settingsObj)) {
$settings = $this->readSettings();
@ -72,11 +72,11 @@ final class SettingsRepository extends Repository
$this->em->flush();
}
public function fromArray(Entity\Settings $entity, array $source): Entity\Settings
public function fromArray(Settings $entity, array $source): Settings
{
return $this->serializer->denormalize(
$source,
Entity\Settings::class,
Settings::class,
null,
[
AbstractNormalizer::OBJECT_TO_POPULATE => $entity,
@ -84,7 +84,7 @@ final class SettingsRepository extends Repository
);
}
public function toArray(Entity\Settings $entity): array
public function toArray(Settings $entity): array
{
return (array)$this->serializer->normalize(
$entity

View File

@ -5,12 +5,14 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Entity;
use Carbon\CarbonImmutable;
use RuntimeException;
use App\Entity\Station;
use App\Entity\Interfaces\SongInterface;
use App\Entity\SongHistory;
/**
* @extends AbstractStationBasedRepository<Entity\SongHistory>
* @extends AbstractStationBasedRepository<\App\Entity\SongHistory>
*/
final class SongHistoryRepository extends AbstractStationBasedRepository
{
@ -23,12 +25,12 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
}
/**
* @param Entity\Station $station
* @param \App\Entity\Station $station
*
* @return Entity\SongHistory[]
* @return \App\Entity\SongHistory[]
*/
public function getVisibleHistory(
Entity\Station $station,
Station $station,
?int $numEntries = null
): array {
$numEntries ??= $station->getApiHistoryItems();
@ -38,7 +40,7 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
return $this->em->createQuery(
<<<'DQL'
SELECT sh FROM App\Entity\SongHistory sh
SELECT sh FROM App\\App\Entity\SongHistory sh
LEFT JOIN sh.media sm
WHERE sh.station = :station
AND sh.is_visible = 1
@ -50,8 +52,8 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
}
public function updateSongFromNowPlaying(
Entity\Station $station,
Entity\Interfaces\SongInterface $song
Station $station,
SongInterface $song
): void {
if (!$this->isDifferentFromCurrentSong($station, $song)) {
return;
@ -61,18 +63,18 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
$upcomingTrack = $this->stationQueueRepository->findRecentlyCuedSong($station, $song);
if (null !== $upcomingTrack) {
$this->stationQueueRepository->trackPlayed($station, $upcomingTrack);
$newSong = Entity\SongHistory::fromQueue($upcomingTrack);
$newSong = SongHistory::fromQueue($upcomingTrack);
} else {
$newSong = new Entity\SongHistory($station, $song);
$newSong = new SongHistory($station, $song);
}
$this->changeCurrentSong($station, $newSong);
}
public function updateListenersFromNowPlaying(
Entity\Station $station,
Station $station,
int $listeners
): Entity\SongHistory {
): SongHistory {
$currentSong = $station->getCurrentSong();
if (null === $currentSong) {
throw new RuntimeException('No track to update.');
@ -86,17 +88,17 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
}
public function isDifferentFromCurrentSong(
Entity\Station $station,
Entity\Interfaces\SongInterface $toCompare
Station $station,
SongInterface $toCompare
): bool {
$currentSong = $station->getCurrentSong();
return !(null !== $currentSong) || $currentSong->getSongId() !== $toCompare->getSongId();
}
public function changeCurrentSong(
Entity\Station $station,
Entity\SongHistory $newCurrentSong
): Entity\SongHistory {
Station $station,
SongHistory $newCurrentSong
): SongHistory {
$previousCurrentSong = $station->getCurrentSong();
if (null !== $previousCurrentSong) {
@ -132,19 +134,19 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
}
/**
* @param Entity\Station $station
* @param \App\Entity\Station $station
* @param int $start
* @param int $end
*
* @return mixed[] [int $minimumListeners, int $maximumListeners, float $averageListeners]
*/
public function getStatsByTimeRange(Entity\Station $station, int $start, int $end): array
public function getStatsByTimeRange(Station $station, int $start, int $end): array
{
$historyTotals = $this->em->createQuery(
<<<'DQL'
SELECT AVG(sh.listeners_end) AS listeners_avg, MAX(sh.listeners_end) AS listeners_max,
MIN(sh.listeners_end) AS listeners_min
FROM App\Entity\SongHistory sh
FROM App\\App\Entity\SongHistory sh
WHERE sh.station = :station
AND sh.timestamp_end >= :start
AND sh.timestamp_start <= :end
@ -169,7 +171,7 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\SongHistory sh
DELETE FROM App\\App\Entity\SongHistory sh
WHERE sh.timestamp_start != 0
AND sh.timestamp_start <= :threshold
DQL

View File

@ -4,25 +4,25 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Entity;
use App\Entity\Station;
/**
* @extends AbstractStationBasedRepository<Entity\StationHlsStream>
* @extends AbstractStationBasedRepository<\App\Entity\StationHlsStream>
*/
final class StationHlsStreamRepository extends AbstractStationBasedRepository
{
/**
* @param Entity\Station $station
* @param \App\Entity\Station $station
*
* @return mixed[]
*/
public function getDisplayNames(Entity\Station $station): array
public function getDisplayNames(Station $station): array
{
$streams = $this->repository->findBy(['station' => $station]);
$displayNames = [];
/** @var Entity\StationHlsStream $stream */
/** @var \App\Entity\StationHlsStream $stream */
foreach ($streams as $stream) {
$displayNames[$stream->getIdRequired()] = 'HLS: ' . $stream->getName();
}

View File

@ -7,7 +7,6 @@ namespace App\Entity\Repository;
use App\Container\LoggerAwareTrait;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Doctrine\Repository;
use App\Entity;
use App\Exception\NotFoundException;
use App\Flysystem\ExtendedFilesystemInterface;
use App\Media\AlbumArt;
@ -22,8 +21,14 @@ use const JSON_PRETTY_PRINT;
use const JSON_THROW_ON_ERROR;
use const JSON_UNESCAPED_SLASHES;
use App\Entity\Station;
use App\Entity\StationMedia;
use App\Entity\StorageLocation;
use App\Entity\StationMediaCustomField;
use App\Entity\Song;
/**
* @extends Repository<Entity\StationMedia>
* @extends Repository<\App\Entity\StationMedia>
*/
final class StationMediaRepository extends Repository
{
@ -40,18 +45,18 @@ final class StationMediaRepository extends Repository
parent::__construct($em);
}
public function findForStation(int|string $id, Entity\Station $station): ?Entity\StationMedia
public function findForStation(int|string $id, Station $station): ?StationMedia
{
if (!is_numeric($id) && Entity\StationMedia::UNIQUE_ID_LENGTH === strlen($id)) {
if (!is_numeric($id) && StationMedia::UNIQUE_ID_LENGTH === strlen($id)) {
$media = $this->findByUniqueId($id, $station);
if ($media instanceof Entity\StationMedia) {
if ($media instanceof StationMedia) {
return $media;
}
}
$storageLocation = $this->getStorageLocation($station);
/** @var Entity\StationMedia|null $media */
/** @var \App\Entity\StationMedia|null $media */
$media = $this->repository->findOneBy(
[
'storage_location' => $storageLocation,
@ -62,7 +67,7 @@ final class StationMediaRepository extends Repository
return $media;
}
public function requireForStation(int|string $id, Entity\Station $station): Entity\StationMedia
public function requireForStation(int|string $id, Station $station): StationMedia
{
$record = $this->findForStation($id, $station);
if (null === $record) {
@ -73,14 +78,16 @@ final class StationMediaRepository extends Repository
/**
* @param string $path
* @param Entity\Station|Entity\StorageLocation $source
* @param \App\Entity\Station|\App\Entity\StorageLocation $source
*
*/
public function findByPath(string $path, Entity\Station|Entity\StorageLocation $source): ?Entity\StationMedia
{
public function findByPath(
string $path,
Station|StorageLocation $source
): ?StationMedia {
$storageLocation = $this->getStorageLocation($source);
/** @var Entity\StationMedia|null $media */
/** @var \App\Entity\StationMedia|null $media */
$media = $this->repository->findOneBy(
[
'storage_location' => $storageLocation,
@ -91,13 +98,13 @@ final class StationMediaRepository extends Repository
return $media;
}
public function iteratePaths(array $paths, Entity\Station|Entity\StorageLocation $source): Generator
public function iteratePaths(array $paths, Station|StorageLocation $source): Generator
{
$storageLocation = $this->getStorageLocation($source);
foreach ($paths as $path) {
$media = $this->findByPath($path, $storageLocation);
if ($media instanceof Entity\StationMedia) {
if ($media instanceof StationMedia) {
yield $path => $media;
}
}
@ -105,16 +112,16 @@ final class StationMediaRepository extends Repository
/**
* @param string $uniqueId
* @param Entity\Station|Entity\StorageLocation $source
* @param \App\Entity\Station|\App\Entity\StorageLocation $source
*
*/
public function findByUniqueId(
string $uniqueId,
Entity\Station|Entity\StorageLocation $source
): ?Entity\StationMedia {
Station|StorageLocation $source
): ?StationMedia {
$storageLocation = $this->getStorageLocation($source);
/** @var Entity\StationMedia|null $media */
/** @var \App\Entity\StationMedia|null $media */
$media = $this->repository->findOneBy(
[
'storage_location' => $storageLocation,
@ -127,8 +134,8 @@ final class StationMediaRepository extends Repository
public function requireByUniqueId(
string $uniqueId,
Entity\Station|Entity\StorageLocation $source
): Entity\StationMedia {
Station|StorageLocation $source
): StationMedia {
$record = $this->findByUniqueId($uniqueId, $source);
if (null === $record) {
throw new NotFoundException();
@ -136,9 +143,9 @@ final class StationMediaRepository extends Repository
return $record;
}
private function getStorageLocation(Entity\Station|Entity\StorageLocation $source): Entity\StorageLocation
private function getStorageLocation(Station|StorageLocation $source): StorageLocation
{
if ($source instanceof Entity\Station) {
if ($source instanceof Station) {
return $source->getMediaStorageLocation();
}
@ -148,12 +155,12 @@ final class StationMediaRepository extends Repository
/**
* Process metadata information from media file.
*
* @param Entity\StationMedia $media
* @param \App\Entity\StationMedia $media
* @param string $filePath
* @param ExtendedFilesystemInterface|null $fs
*/
public function loadFromFile(
Entity\StationMedia $media,
StationMedia $media,
string $filePath,
?ExtendedFilesystemInterface $fs = null
): void {
@ -168,7 +175,7 @@ final class StationMediaRepository extends Repository
// Clear existing auto-assigned custom fields.
$fieldCollection = $media->getCustomFields();
foreach ($fieldCollection as $existingCustomField) {
/** @var Entity\StationMediaCustomField $existingCustomField */
/** @var \App\Entity\StationMediaCustomField $existingCustomField */
if ($existingCustomField->getField()->hasAutoAssign()) {
$this->em->remove($existingCustomField);
$fieldCollection->removeElement($existingCustomField);
@ -179,7 +186,7 @@ final class StationMediaRepository extends Repository
$tags = $metadata->getTags();
foreach ($customFieldsToSet as $tag => $customFieldKey) {
if (!empty($tags[$tag])) {
$customFieldRow = new Entity\StationMediaCustomField($media, $customFieldKey);
$customFieldRow = new StationMediaCustomField($media, $customFieldKey);
$customFieldRow->setValue($tags[$tag]);
$this->em->persist($customFieldRow);
@ -216,7 +223,7 @@ final class StationMediaRepository extends Repository
$filename = pathinfo($media->getPath(), PATHINFO_FILENAME);
$filename = str_replace('_', ' ', $filename);
$songObj = Entity\Song::createFromText($filename);
$songObj = Song::createFromText($filename);
$media->setSong($songObj);
}
@ -228,7 +235,7 @@ final class StationMediaRepository extends Repository
}
public function updateAlbumArt(
Entity\StationMedia $media,
StationMedia $media,
string $rawArtString
): bool {
$fs = $this->getFilesystem($media);
@ -238,7 +245,7 @@ final class StationMediaRepository extends Repository
}
public function writeAlbumArt(
Entity\StationMedia $media,
StationMedia $media,
string $rawArtString,
?ExtendedFilesystemInterface $fs = null
): void {
@ -247,19 +254,19 @@ final class StationMediaRepository extends Repository
$media->setArtUpdatedAt(time());
$this->em->persist($media);
$albumArtPath = Entity\StationMedia::getArtPath($media->getUniqueId());
$albumArtPath = StationMedia::getArtPath($media->getUniqueId());
$albumArtString = AlbumArt::resize($rawArtString);
$fs->write($albumArtPath, $albumArtString);
}
public function removeAlbumArt(
Entity\StationMedia $media,
StationMedia $media,
?ExtendedFilesystemInterface $fs = null
): void {
$fs ??= $this->getFilesystem($media);
$currentAlbumArtPath = Entity\StationMedia::getArtPath($media->getUniqueId());
$currentAlbumArtPath = StationMedia::getArtPath($media->getUniqueId());
$fs->delete($currentAlbumArtPath);
$media->setArtUpdatedAt(0);
@ -270,14 +277,14 @@ final class StationMediaRepository extends Repository
}
public function writeToFile(
Entity\StationMedia $media,
StationMedia $media,
?ExtendedFilesystemInterface $fs = null
): bool {
$fs ??= $this->getFilesystem($media);
$metadata = $media->toMetadata();
$art_path = Entity\StationMedia::getArtPath($media->getUniqueId());
$art_path = StationMedia::getArtPath($media->getUniqueId());
if ($fs->fileExists($art_path)) {
$metadata->setArtwork($fs->read($art_path));
}
@ -296,7 +303,7 @@ final class StationMediaRepository extends Repository
}
public function updateWaveform(
Entity\StationMedia $media,
StationMedia $media,
?ExtendedFilesystemInterface $fs = null
): void {
$fs ??= $this->getFilesystem($media);
@ -309,14 +316,14 @@ final class StationMediaRepository extends Repository
}
public function writeWaveform(
Entity\StationMedia $media,
StationMedia $media,
string $path,
?ExtendedFilesystemInterface $fs = null
): void {
$fs ??= $this->getFilesystem($media);
$waveform = AudioWaveform::getWaveformFor($path);
$waveformPath = Entity\StationMedia::getWaveformPath($media->getUniqueId());
$waveformPath = StationMedia::getWaveformPath($media->getUniqueId());
$fs->write(
$waveformPath,
@ -328,14 +335,14 @@ final class StationMediaRepository extends Repository
}
/**
* @param Entity\StationMedia $media
* @param \App\Entity\StationMedia $media
* @param bool $deleteFile Whether to remove the media file itself (disabled for batch operations).
* @param ExtendedFilesystemInterface|null $fs
*
* @return Entity\StationPlaylist[] The IDs as keys and records as values for all affected playlists.
* @return \App\Entity\StationPlaylist[] The IDs as keys and records as values for all affected playlists.
*/
public function remove(
Entity\StationMedia $media,
StationMedia $media,
bool $deleteFile = false,
?ExtendedFilesystemInterface $fs = null
): array {
@ -366,7 +373,7 @@ final class StationMediaRepository extends Repository
return $affectedPlaylists;
}
private function getFilesystem(Entity\StationMedia $media): ExtendedFilesystemInterface
private function getFilesystem(StationMedia $media): ExtendedFilesystemInterface
{
return $this->storageLocationRepo->getAdapter($media->getStorageLocation())
->getFilesystem();

View File

@ -4,20 +4,23 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Entity;
use App\Entity\Station;
use App\Entity\Enums\PlaylistSources;
use App\Entity\StationPlaylist;
use App\Entity\StationPlaylistFolder;
/**
* @extends AbstractStationBasedRepository<Entity\StationPlaylistFolder>
* @extends AbstractStationBasedRepository<\App\Entity\StationPlaylistFolder>
*/
final class StationPlaylistFolderRepository extends AbstractStationBasedRepository
{
/**
* @param Entity\Station $station
* @param Entity\StationPlaylist[] $playlists
* @param \App\Entity\Station $station
* @param \App\Entity\StationPlaylist[] $playlists
* @param string $path
*/
public function setPlaylistsForFolder(
Entity\Station $station,
Station $station,
array $playlists,
string $path
): void {
@ -27,7 +30,7 @@ final class StationPlaylistFolderRepository extends AbstractStationBasedReposito
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\StationPlaylistFolder spf
DELETE FROM App\\App\Entity\StationPlaylistFolder spf
WHERE spf.station = :station AND spf.path = :path
DQL
)->setParameter('station', $station)
@ -35,11 +38,11 @@ final class StationPlaylistFolderRepository extends AbstractStationBasedReposito
->execute();
foreach ($playlists as $playlistId => $playlistRecord) {
if (Entity\Enums\PlaylistSources::Songs === $playlistRecord->getSource()) {
/** @var Entity\StationPlaylist $playlist */
$playlist = $this->em->getReference(Entity\StationPlaylist::class, $playlistId);
if (PlaylistSources::Songs === $playlistRecord->getSource()) {
/** @var \App\Entity\StationPlaylist $playlist */
$playlist = $this->em->getReference(StationPlaylist::class, $playlistId);
$newRecord = new Entity\StationPlaylistFolder($station, $playlist, $path);
$newRecord = new StationPlaylistFolder($station, $playlist, $path);
$this->em->persist($newRecord);
}
}

View File

@ -6,16 +6,22 @@ namespace App\Entity\Repository;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Doctrine\Repository;
use App\Entity;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Doctrine\ORM\NoResultException;
use Doctrine\ORM\QueryBuilder;
use InvalidArgumentException;
use RuntimeException;
use App\Entity\StationMedia;
use App\Entity\StationPlaylist;
use App\Entity\Enums\PlaylistSources;
use App\Entity\Enums\PlaylistOrders;
use App\Entity\StationPlaylistMedia;
use App\Entity\Station;
use App\Entity\Api\StationPlaylistQueue;
/**
* @extends Repository<Entity\StationPlaylistMedia>
* @extends Repository<\App\Entity\StationPlaylistMedia>
*/
final class StationPlaylistMediaRepository extends Repository
{
@ -30,23 +36,23 @@ final class StationPlaylistMediaRepository extends Repository
* Add the specified media to the specified playlist.
* Must flush the EntityManager after using.
*
* @param Entity\StationMedia $media
* @param Entity\StationPlaylist $playlist
* @param \App\Entity\StationMedia $media
* @param \App\Entity\StationPlaylist $playlist
* @param int $weight
*
* @return int The weight assigned to the newly added record.
*/
public function addMediaToPlaylist(
Entity\StationMedia $media,
Entity\StationPlaylist $playlist,
StationMedia $media,
StationPlaylist $playlist,
int $weight = 0
): int {
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
if (PlaylistSources::Songs !== $playlist->getSource()) {
throw new RuntimeException('This playlist is not meant to contain songs!');
}
// Only update existing record for random-order playlists.
$isNonSequential = Entity\Enums\PlaylistOrders::Sequential !== $playlist->getOrder();
$isNonSequential = PlaylistOrders::Sequential !== $playlist->getOrder();
$record = ($isNonSequential)
? $this->repository->findOneBy(
@ -56,7 +62,7 @@ final class StationPlaylistMediaRepository extends Repository
]
) : null;
if ($record instanceof Entity\StationPlaylistMedia) {
if ($record instanceof StationPlaylistMedia) {
if (0 !== $weight) {
$record->setWeight($weight);
$this->em->persist($record);
@ -69,7 +75,7 @@ final class StationPlaylistMediaRepository extends Repository
$weight = random_int(1, $weight);
}
$record = new Entity\StationPlaylistMedia($playlist, $media);
$record = new StationPlaylistMedia($playlist, $media);
$record->setWeight($weight);
$this->em->persist($record);
}
@ -77,13 +83,13 @@ final class StationPlaylistMediaRepository extends Repository
return $weight;
}
public function getHighestSongWeight(Entity\StationPlaylist $playlist): int
public function getHighestSongWeight(StationPlaylist $playlist): int
{
try {
$highest_weight = $this->em->createQuery(
<<<'DQL'
SELECT MAX(e.weight)
FROM App\Entity\StationPlaylistMedia e
FROM App\\App\Entity\StationPlaylistMedia e
WHERE e.playlist_id = :playlist_id
DQL
)->setParameter('playlist_id', $playlist->getId())
@ -98,21 +104,21 @@ final class StationPlaylistMediaRepository extends Repository
/**
* Remove all playlist associations from the specified media object.
*
* @param Entity\StationMedia $media
* @param Entity\Station|null $station
* @param \App\Entity\StationMedia $media
* @param \App\Entity\Station|null $station
*
* @return Entity\StationPlaylist[] The IDs as keys and records as values for all affected playlists.
* @return \App\Entity\StationPlaylist[] The IDs as keys and records as values for all affected playlists.
*/
public function clearPlaylistsFromMedia(
Entity\StationMedia $media,
?Entity\Station $station = null
StationMedia $media,
?Station $station = null
): array {
$affectedPlaylists = [];
$playlists = $media->getPlaylists();
if (null !== $station) {
$playlists = $playlists->filter(
function (Entity\StationPlaylistMedia $spm) use ($station) {
function (StationPlaylistMedia $spm) use ($station) {
return $spm->getPlaylist()->getStation()->getId() === $station->getId();
}
);
@ -137,14 +143,14 @@ final class StationPlaylistMediaRepository extends Repository
* ...
* ]
*
* @param Entity\StationPlaylist $playlist
* @param \App\Entity\StationPlaylist $playlist
* @param array $mapping
*/
public function setMediaOrder(Entity\StationPlaylist $playlist, array $mapping): void
public function setMediaOrder(StationPlaylist $playlist, array $mapping): void
{
$update_query = $this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\StationPlaylistMedia e
UPDATE App\\App\Entity\StationPlaylistMedia e
SET e.weight = :weight
WHERE e.playlist_id = :playlist_id
AND e.id = :id
@ -162,28 +168,28 @@ final class StationPlaylistMediaRepository extends Repository
);
}
public function resetQueue(Entity\StationPlaylist $playlist, CarbonInterface $now = null): void
public function resetQueue(StationPlaylist $playlist, CarbonInterface $now = null): void
{
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
if (PlaylistSources::Songs !== $playlist->getSource()) {
throw new InvalidArgumentException('Playlist must contain songs.');
}
if (Entity\Enums\PlaylistOrders::Sequential === $playlist->getOrder()) {
if (PlaylistOrders::Sequential === $playlist->getOrder()) {
$this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\StationPlaylistMedia spm
UPDATE App\\App\Entity\StationPlaylistMedia spm
SET spm.is_queued = 1
WHERE spm.playlist = :playlist
DQL
)->setParameter('playlist', $playlist)
->execute();
} elseif (Entity\Enums\PlaylistOrders::Shuffle === $playlist->getOrder()) {
} elseif (PlaylistOrders::Shuffle === $playlist->getOrder()) {
$this->em->wrapInTransaction(
function () use ($playlist): void {
$allSpmRecordsQuery = $this->em->createQuery(
<<<'DQL'
SELECT spm.id
FROM App\Entity\StationPlaylistMedia spm
FROM App\\App\Entity\StationPlaylistMedia spm
WHERE spm.playlist = :playlist
ORDER BY RAND()
DQL
@ -191,7 +197,7 @@ final class StationPlaylistMediaRepository extends Repository
$updateSpmWeightQuery = $this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\StationPlaylistMedia spm
UPDATE App\\App\Entity\StationPlaylistMedia spm
SET spm.weight=:weight, spm.is_queued=1
WHERE spm.id = :id
DQL
@ -218,12 +224,12 @@ final class StationPlaylistMediaRepository extends Repository
$this->em->flush();
}
public function resetAllQueues(Entity\Station $station): void
public function resetAllQueues(Station $station): void
{
$now = CarbonImmutable::now($station->getTimezoneObject());
foreach ($station->getPlaylists() as $playlist) {
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
if (PlaylistSources::Songs !== $playlist->getSource()) {
continue;
}
@ -232,22 +238,22 @@ final class StationPlaylistMediaRepository extends Repository
}
/**
* @return Entity\Api\StationPlaylistQueue[]
* @return \App\Entity\Api\StationPlaylistQueue[]
*/
public function getQueue(Entity\StationPlaylist $playlist): array
public function getQueue(StationPlaylist $playlist): array
{
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
if (PlaylistSources::Songs !== $playlist->getSource()) {
throw new InvalidArgumentException('Playlist must contain songs.');
}
$queuedMediaQuery = $this->em->createQueryBuilder()
->select(['spm.id AS spm_id', 'sm.id', 'sm.song_id', 'sm.artist', 'sm.title'])
->from(Entity\StationMedia::class, 'sm')
->from(StationMedia::class, 'sm')
->join('sm.playlists', 'spm')
->where('spm.playlist = :playlist')
->setParameter('playlist', $playlist);
if (Entity\Enums\PlaylistOrders::Random === $playlist->getOrder()) {
if (PlaylistOrders::Random === $playlist->getOrder()) {
$queuedMediaQuery = $queuedMediaQuery->orderBy('RAND()');
} else {
$queuedMediaQuery = $queuedMediaQuery->andWhere('spm.is_queued = 1')
@ -257,8 +263,8 @@ final class StationPlaylistMediaRepository extends Repository
$queuedMedia = $queuedMediaQuery->getQuery()->getArrayResult();
return array_map(
static function ($val): Entity\Api\StationPlaylistQueue {
$record = new Entity\Api\StationPlaylistQueue();
static function ($val): StationPlaylistQueue {
$record = new StationPlaylistQueue();
$record->spm_id = $val['spm_id'];
$record->media_id = $val['id'];
$record->song_id = $val['song_id'];
@ -271,13 +277,13 @@ final class StationPlaylistMediaRepository extends Repository
);
}
public function isQueueCompletelyFilled(Entity\StationPlaylist $playlist): bool
public function isQueueCompletelyFilled(StationPlaylist $playlist): bool
{
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
if (PlaylistSources::Songs !== $playlist->getSource()) {
return true;
}
if (Entity\Enums\PlaylistOrders::Random === $playlist->getOrder()) {
if (PlaylistOrders::Random === $playlist->getOrder()) {
return true;
}
@ -289,13 +295,13 @@ final class StationPlaylistMediaRepository extends Repository
return $notQueuedMediaCount === 0;
}
public function isQueueEmpty(Entity\StationPlaylist $playlist): bool
public function isQueueEmpty(StationPlaylist $playlist): bool
{
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
if (PlaylistSources::Songs !== $playlist->getSource()) {
return false;
}
if (Entity\Enums\PlaylistOrders::Random === $playlist->getOrder()) {
if (PlaylistOrders::Random === $playlist->getOrder()) {
return false;
}
@ -311,11 +317,11 @@ final class StationPlaylistMediaRepository extends Repository
return $notQueuedMediaCount === $totalMediaCount;
}
private function getCountPlaylistMediaBaseQuery(Entity\StationPlaylist $playlist): QueryBuilder
private function getCountPlaylistMediaBaseQuery(StationPlaylist $playlist): QueryBuilder
{
return $this->em->createQueryBuilder()
->select('count(spm.id)')
->from(Entity\StationMedia::class, 'sm')
->from(StationMedia::class, 'sm')
->join('sm.playlists', 'spm')
->where('spm.playlist = :playlist')
->setParameter('playlist', $playlist);

View File

@ -4,37 +4,38 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Entity;
use App\Entity\Station;
use App\Entity\Enums\PlaylistSources;
/**
* @extends AbstractStationBasedRepository<Entity\StationPlaylist>
* @extends AbstractStationBasedRepository<\App\Entity\StationPlaylist>
*/
final class StationPlaylistRepository extends AbstractStationBasedRepository
{
/**
* @return Entity\StationPlaylist[]
* @return \App\Entity\StationPlaylist[]
*/
public function getAllForStation(Entity\Station $station): array
public function getAllForStation(Station $station): array
{
return $this->repository->findBy([
'station' => $station,
]);
}
public function stationHasActivePlaylists(Entity\Station $station): bool
public function stationHasActivePlaylists(Station $station): bool
{
foreach ($station->getPlaylists() as $playlist) {
if (!$playlist->getIsEnabled()) {
continue;
}
if (Entity\Enums\PlaylistSources::RemoteUrl === $playlist->getSource()) {
if (PlaylistSources::RemoteUrl === $playlist->getSource()) {
return true;
}
$mediaCount = $this->em->createQuery(
<<<DQL
SELECT COUNT(spm.id) FROM App\Entity\StationPlaylistMedia spm
SELECT COUNT(spm.id) FROM App\\App\Entity\StationPlaylistMedia spm
JOIN spm.playlist sp
WHERE sp.station = :station
DQL

View File

@ -4,22 +4,28 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Entity;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use App\Entity\StationMedia;
use App\Entity\StationPlaylist;
use App\Entity\Station;
use App\Entity\StationQueue;
use App\Entity\Interfaces\SongInterface;
/**
* @extends AbstractStationBasedRepository<Entity\StationQueue>
* @extends AbstractStationBasedRepository<\App\Entity\StationQueue>
*/
final class StationQueueRepository extends AbstractStationBasedRepository
{
public function clearForMediaAndPlaylist(Entity\StationMedia $media, Entity\StationPlaylist $playlist): void
{
public function clearForMediaAndPlaylist(
StationMedia $media,
StationPlaylist $playlist
): void {
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\StationQueue sq
DELETE FROM App\\App\Entity\StationQueue sq
WHERE sq.media = :media
AND sq.playlist = :playlist
AND sq.is_played = 0
@ -29,7 +35,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
->execute();
}
public function getNextVisible(Entity\Station $station): ?Entity\StationQueue
public function getNextVisible(Station $station): ?StationQueue
{
return $this->getUnplayedBaseQuery($station)
->andWhere('sq.is_visible = 1')
@ -39,12 +45,12 @@ final class StationQueueRepository extends AbstractStationBasedRepository
}
public function trackPlayed(
Entity\Station $station,
Entity\StationQueue $row
Station $station,
StationQueue $row
): void {
$this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\StationQueue sq
UPDATE App\\App\Entity\StationQueue sq
SET sq.timestamp_played = :timestamp
WHERE sq.station = :station
AND sq.id = :id
@ -56,7 +62,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
$this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\StationQueue sq
UPDATE App\\App\Entity\StationQueue sq
SET sq.is_played=1, sq.sent_to_autodj=1
WHERE sq.station = :station
AND sq.is_played = 0
@ -69,7 +75,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
}
public function isPlaylistRecentlyPlayed(
Entity\StationPlaylist $playlist,
StationPlaylist $playlist,
?int $playPerSongs = null
): bool {
$playPerSongs ??= $playlist->getPlayPerSongs();
@ -77,7 +83,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
$recentPlayedQuery = $this->em->createQuery(
<<<'DQL'
SELECT sq.playlist_id
FROM App\Entity\StationQueue sq
FROM App\\App\Entity\StationQueue sq
WHERE sq.station = :station
AND sq.playlist_id IS NOT NULL
AND (sq.playlist = :playlist OR sq.is_visible = 1)
@ -96,7 +102,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
* @return mixed[]
*/
public function getRecentlyPlayedByTimeRange(
Entity\Station $station,
Station $station,
CarbonInterface $now,
int $minutes
): array {
@ -105,7 +111,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
return $this->em->createQuery(
<<<'DQL'
SELECT sq.song_id, sq.timestamp_played, sq.title, sq.artist
FROM App\Entity\StationQueue sq
FROM App\\App\Entity\StationQueue sq
WHERE sq.station = :station
AND (sq.is_played = 0 OR sq.timestamp_played >= :threshold)
ORDER BY sq.timestamp_played DESC
@ -116,24 +122,24 @@ final class StationQueueRepository extends AbstractStationBasedRepository
}
/**
* @param Entity\Station $station
* @return Entity\StationQueue[]
* @param \App\Entity\Station $station
* @return \App\Entity\StationQueue[]
*/
public function getUnplayedQueue(Entity\Station $station): array
public function getUnplayedQueue(Station $station): array
{
return $this->getUnplayedQuery($station)->execute();
}
public function getUnplayedQuery(Entity\Station $station): Query
public function getUnplayedQuery(Station $station): Query
{
return $this->getUnplayedBaseQuery($station)->getQuery();
}
public function clearUpcomingQueue(Entity\Station $station): void
public function clearUpcomingQueue(Station $station): void
{
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\StationQueue sq
DELETE FROM App\\App\Entity\StationQueue sq
WHERE sq.station = :station
AND sq.sent_to_autodj = 0
DQL
@ -141,7 +147,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
->execute();
}
public function getNextToSendToAutoDj(Entity\Station $station): ?Entity\StationQueue
public function getNextToSendToAutoDj(Station $station): ?StationQueue
{
return $this->getBaseQuery($station)
->andWhere('sq.sent_to_autodj = 0')
@ -152,9 +158,9 @@ final class StationQueueRepository extends AbstractStationBasedRepository
}
public function findRecentlyCuedSong(
Entity\Station $station,
Entity\Interfaces\SongInterface $song
): ?Entity\StationQueue {
Station $station,
SongInterface $song
): ?StationQueue {
return $this->getUnplayedBaseQuery($station)
->andWhere('sq.sent_to_autodj = 1')
->andWhere('sq.song_id = :song_id')
@ -164,7 +170,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
->getOneOrNullResult();
}
public function hasCuedPlaylistMedia(Entity\StationPlaylist $playlist): bool
public function hasCuedPlaylistMedia(StationPlaylist $playlist): bool
{
$station = $playlist->getStation();
@ -178,7 +184,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
return $cuedPlaylistContentCount > 0;
}
private function getUnplayedBaseQuery(Entity\Station $station): QueryBuilder
private function getUnplayedBaseQuery(Station $station): QueryBuilder
{
return $this->getBaseQuery($station)
->andWhere('sq.is_played = 0')
@ -186,21 +192,21 @@ final class StationQueueRepository extends AbstractStationBasedRepository
->addOrderBy('sq.timestamp_cued', 'ASC');
}
private function getBaseQuery(Entity\Station $station): QueryBuilder
private function getBaseQuery(Station $station): QueryBuilder
{
return $this->em->createQueryBuilder()
->select('sq, sm, sp')
->from(Entity\StationQueue::class, 'sq')
->from(StationQueue::class, 'sq')
->leftJoin('sq.media', 'sm')
->leftJoin('sq.playlist', 'sp')
->where('sq.station = :station')
->setParameter('station', $station);
}
public function clearUnplayed(?Entity\Station $station = null): void
public function clearUnplayed(?Station $station = null): void
{
$qb = $this->em->createQueryBuilder()
->delete(Entity\StationQueue::class, 'sq')
->delete(StationQueue::class, 'sq')
->where('sq.is_played = 0');
if (null !== $station) {
@ -219,7 +225,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\StationQueue sq
DELETE FROM App\\App\Entity\StationQueue sq
WHERE sq.timestamp_cued <= :threshold
DQL
)->setParameter('threshold', $threshold)

View File

@ -4,26 +4,26 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Entity;
use App\Entity\Station;
/**
* @extends AbstractStationBasedRepository<Entity\StationRemote>
* @extends AbstractStationBasedRepository<\App\Entity\StationRemote>
*/
final class StationRemoteRepository extends AbstractStationBasedRepository
{
/**
* @param Entity\Station $station
* @param \App\Entity\Station $station
*
* @return mixed[]
*/
public function getDisplayNames(Entity\Station $station): array
public function getDisplayNames(Station $station): array
{
$remotes = $this->repository->findBy(['station' => $station]);
$displayNames = [];
foreach ($remotes as $remote) {
/** @var Entity\StationRemote $remote */
/** @var \App\Entity\StationRemote $remote */
$displayNames[$remote->getId()] = $remote->getDisplayName();
}

View File

@ -8,16 +8,18 @@ use App\Assets\AssetTypes;
use App\Container\EnvironmentAwareTrait;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Doctrine\Repository;
use App\Entity;
use App\Flysystem\ExtendedFilesystemInterface;
use App\Flysystem\StationFilesystems;
use App\Radio\Enums\StreamFormats;
use App\Service\Flow\UploadedFile;
use Closure;
use Psr\Http\Message\UriInterface;
use App\Entity\Station;
use App\Entity\StationMount;
use App\Entity\StationHlsStream;
/**
* @extends Repository<Entity\Station>
* @extends Repository<\App\Entity\Station>
*/
final class StationRepository extends Repository
{
@ -33,7 +35,7 @@ final class StationRepository extends Repository
/**
* @param string $identifier A numeric or string identifier for a station.
*/
public function findByIdentifier(string $identifier): ?Entity\Station
public function findByIdentifier(string $identifier): ?Station
{
return is_numeric($identifier)
? $this->repository->find($identifier)
@ -44,19 +46,19 @@ final class StationRepository extends Repository
{
return $this->em->createQuery(
<<<'DQL'
SELECT COUNT(s.id) FROM App\Entity\Station s WHERE s.is_enabled = 1
SELECT COUNT(s.id) FROM App\\App\Entity\Station s WHERE s.is_enabled = 1
DQL
)->getSingleScalarResult();
}
/**
* @return array<array-key, Entity\Station>
* @return array<array-key, \App\Entity\Station>
*/
public function fetchAll(): mixed
{
return $this->em->createQuery(
<<<'DQL'
SELECT s FROM App\Entity\Station s ORDER BY s.name ASC
SELECT s FROM App\\App\Entity\Station s ORDER BY s.name ASC
DQL
)->execute();
}
@ -88,13 +90,13 @@ final class StationRepository extends Repository
}
/**
* @return iterable<Entity\Station>
* @return iterable<\App\Entity\Station>
*/
public function iterateEnabledStations(): iterable
{
return $this->em->createQuery(
<<<DQL
SELECT s FROM App\Entity\Station s WHERE s.is_enabled = 1
SELECT s FROM App\\App\Entity\Station s WHERE s.is_enabled = 1
DQL
)->toIterable();
}
@ -102,7 +104,7 @@ final class StationRepository extends Repository
/**
* Reset mount points to their adapter defaults (in the event of an adapter change).
*/
public function resetMounts(Entity\Station $station): void
public function resetMounts(Station $station): void
{
foreach ($station->getMounts() as $mount) {
$this->em->remove($mount);
@ -110,7 +112,7 @@ final class StationRepository extends Repository
// Create default mountpoints if station supports them.
if ($station->getFrontendType()->supportsMounts()) {
$record = new Entity\StationMount($station);
$record = new StationMount($station);
$record->setName('/radio.mp3');
$record->setIsDefault(true);
$record->setEnableAutodj(true);
@ -123,7 +125,7 @@ final class StationRepository extends Repository
$this->em->refresh($station);
}
public function resetHls(Entity\Station $station): void
public function resetHls(Station $station): void
{
foreach ($station->getHlsStreams() as $hlsStream) {
$this->em->remove($hlsStream);
@ -137,7 +139,7 @@ final class StationRepository extends Repository
];
foreach ($streams as $name => $bitrate) {
$record = new Entity\StationHlsStream($station);
$record = new StationHlsStream($station);
$record->setName($name);
$record->setFormat(StreamFormats::Aac);
$record->setBitrate($bitrate);
@ -149,11 +151,11 @@ final class StationRepository extends Repository
$this->em->refresh($station);
}
public function flushRelatedMedia(Entity\Station $station): void
public function flushRelatedMedia(Station $station): void
{
$this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\SongHistory sh SET sh.media = null
UPDATE App\\App\Entity\SongHistory sh SET sh.media = null
WHERE sh.station = :station
DQL
)->setParameter('station', $station)
@ -161,9 +163,9 @@ final class StationRepository extends Repository
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\StationPlaylistMedia spm
DELETE FROM App\\App\Entity\StationPlaylistMedia spm
WHERE spm.playlist_id IN (
SELECT sp.id FROM App\Entity\StationPlaylist sp WHERE sp.station = :station
SELECT sp.id FROM App\\App\Entity\StationPlaylist sp WHERE sp.station = :station
)
DQL
)->setParameter('station', $station)
@ -171,14 +173,14 @@ final class StationRepository extends Repository
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\StationQueue sq WHERE sq.station = :station
DELETE FROM App\\App\Entity\StationQueue sq WHERE sq.station = :station
DQL
)->setParameter('station', $station)
->execute();
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\StationRequest sr WHERE sr.station = :station
DELETE FROM App\\App\Entity\StationRequest sr WHERE sr.station = :station
DQL
)->setParameter('station', $station)
->execute();
@ -187,9 +189,9 @@ final class StationRepository extends Repository
/**
* Return the URL to use for songs with no specified album artwork, when artwork is displayed.
*
* @param Entity\Station|null $station
* @param \App\Entity\Station|null $station
*/
public function getDefaultAlbumArtUrl(?Entity\Station $station = null): UriInterface
public function getDefaultAlbumArtUrl(?Station $station = null): UriInterface
{
if (null !== $station) {
$stationAlbumArt = AssetTypes::AlbumArt->createObject($this->environment, $station);
@ -208,7 +210,7 @@ final class StationRepository extends Repository
}
public function setFallback(
Entity\Station $station,
Station $station,
UploadedFile $file,
?ExtendedFilesystemInterface $fs = null
): void {
@ -231,7 +233,7 @@ final class StationRepository extends Repository
}
public function doDeleteFallback(
Entity\Station $station,
Station $station,
?ExtendedFilesystemInterface $fs = null
): void {
$fs ??= StationFilesystems::buildConfigFilesystem($station);
@ -245,7 +247,7 @@ final class StationRepository extends Repository
}
public function clearFallback(
Entity\Station $station,
Station $station,
?ExtendedFilesystemInterface $fs = null
): void {
$this->doDeleteFallback($station, $fs);
@ -256,7 +258,7 @@ final class StationRepository extends Repository
}
public function setStereoToolConfiguration(
Entity\Station $station,
Station $station,
UploadedFile $file,
?ExtendedFilesystemInterface $fs = null
): void {
@ -280,7 +282,7 @@ final class StationRepository extends Repository
}
public function doDeleteStereoToolConfiguration(
Entity\Station $station,
Station $station,
?ExtendedFilesystemInterface $fs = null
): void {
$backendConfig = $station->getBackendConfig();
@ -293,7 +295,7 @@ final class StationRepository extends Repository
}
public function clearStereoToolConfiguration(
Entity\Station $station,
Station $station,
?ExtendedFilesystemInterface $fs = null
): void {
$this->doDeleteStereoToolConfiguration($station, $fs);

View File

@ -5,16 +5,19 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Entity;
use App\Exception;
use App\Radio\AutoDJ;
use App\Radio\Frontend\Blocklist\BlocklistParser;
use App\Service\DeviceDetector;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use App\Entity\Station;
use App\Entity\StationRequest;
use App\Entity\StationMedia;
use App\Entity\Api\StationPlaylistQueue;
/**
* @extends AbstractStationBasedRepository<Entity\StationRequest>
* @extends AbstractStationBasedRepository<\App\Entity\StationRequest>
*/
final class StationRequestRepository extends AbstractStationBasedRepository
{
@ -28,7 +31,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
parent::__construct($em);
}
public function getPendingRequest(int|string $id, Entity\Station $station): ?Entity\StationRequest
public function getPendingRequest(int|string $id, Station $station): ?StationRequest
{
return $this->repository->findOneBy(
[
@ -39,11 +42,11 @@ final class StationRequestRepository extends AbstractStationBasedRepository
);
}
public function clearPendingRequests(Entity\Station $station): void
public function clearPendingRequests(Station $station): void
{
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\StationRequest sr
DELETE FROM App\\App\Entity\StationRequest sr
WHERE sr.station = :station
AND sr.played_at = 0
DQL
@ -52,7 +55,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
}
public function submit(
Entity\Station $station,
Station $station,
string $trackId,
bool $isAuthenticated,
string $ip,
@ -100,7 +103,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
$recentRequests = (int)$this->em->createQuery(
<<<'DQL'
SELECT COUNT(sr.id) FROM App\Entity\StationRequest sr
SELECT COUNT(sr.id) FROM App\\App\Entity\StationRequest sr
WHERE sr.ip = :user_ip
AND sr.timestamp >= :threshold
DQL
@ -116,7 +119,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
}
// Save request locally.
$record = new Entity\StationRequest($station, $media_item, $ip);
$record = new StationRequest($station, $media_item, $ip);
$this->em->persist($record);
$this->em->flush();
@ -126,12 +129,12 @@ final class StationRequestRepository extends AbstractStationBasedRepository
/**
* Check if the song is already enqueued as a request.
*
* @param Entity\StationMedia $media
* @param Entity\Station $station
* @param \App\Entity\StationMedia $media
* @param \App\Entity\Station $station
*
* @throws Exception
*/
public function checkPendingRequest(Entity\StationMedia $media, Entity\Station $station): bool
public function checkPendingRequest(StationMedia $media, Station $station): bool
{
$pending_request_threshold = time() - (60 * 10);
@ -139,7 +142,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
$pending_request = $this->em->createQuery(
<<<'DQL'
SELECT sr.timestamp
FROM App\Entity\StationRequest sr
FROM App\\App\Entity\StationRequest sr
WHERE sr.track_id = :track_id
AND sr.station_id = :station_id
AND (sr.timestamp >= :threshold OR sr.played_at = 0)
@ -162,16 +165,16 @@ final class StationRequestRepository extends AbstractStationBasedRepository
}
public function getNextPlayableRequest(
Entity\Station $station,
Station $station,
?CarbonInterface $now = null
): ?Entity\StationRequest {
): ?StationRequest {
$now ??= CarbonImmutable::now($station->getTimezoneObject());
// Look up all requests that have at least waited as long as the threshold.
$requests = $this->em->createQuery(
<<<'DQL'
SELECT sr, sm
FROM App\Entity\StationRequest sr JOIN sr.track sm
FROM App\\App\Entity\StationRequest sr JOIN sr.track sm
WHERE sr.played_at = 0
AND sr.station = :station
ORDER BY sr.skip_delay DESC, sr.id ASC
@ -180,7 +183,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
->execute();
foreach ($requests as $request) {
/** @var Entity\StationRequest $request */
/** @var \App\Entity\StationRequest $request */
if ($request->shouldPlayNow($now)) {
try {
$this->checkRecentPlay($request->getTrack(), $station);
@ -198,12 +201,12 @@ final class StationRequestRepository extends AbstractStationBasedRepository
/**
* Check the most recent song history.
*
* @param Entity\StationMedia $media
* @param Entity\Station $station
* @param \App\Entity\StationMedia $media
* @param \App\Entity\Station $station
*
* @throws Exception
*/
public function checkRecentPlay(Entity\StationMedia $media, Entity\Station $station): bool
public function checkRecentPlay(StationMedia $media, Station $station): bool
{
$lastPlayThresholdMins = ($station->getRequestThreshold() ?? 15);
@ -215,7 +218,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
$recentTracks = $this->em->createQuery(
<<<'DQL'
SELECT sh FROM App\Entity\SongHistory sh
SELECT sh FROM App\\App\Entity\SongHistory sh
WHERE sh.station = :station
AND sh.timestamp_start >= :threshold
ORDER BY sh.timestamp_start DESC
@ -224,7 +227,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
->setParameter('threshold', $lastPlayThreshold)
->getArrayResult();
$eligibleTrack = new Entity\Api\StationPlaylistQueue();
$eligibleTrack = new StationPlaylistQueue();
$eligibleTrack->media_id = $media->getIdRequired();
$eligibleTrack->song_id = $media->getSongId();
$eligibleTrack->title = $media->getTitle() ?? '';

View File

@ -6,30 +6,36 @@ namespace App\Entity\Repository;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Doctrine\Repository;
use App\Entity;
use App\Radio\AutoDJ\Scheduler;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use App\Entity\ApiGenerator\ScheduleApiGenerator;
use App\Entity\StationPlaylist;
use App\Entity\StationStreamer;
use App\Entity\StationSchedule;
use App\Entity\Station;
/**
* @extends Repository<Entity\StationSchedule>
* @extends Repository<\App\Entity\StationSchedule>
*/
final class StationScheduleRepository extends Repository
{
public function __construct(
ReloadableEntityManagerInterface $em,
private readonly Scheduler $scheduler,
private readonly Entity\ApiGenerator\ScheduleApiGenerator $scheduleApiGenerator
private readonly ScheduleApiGenerator $scheduleApiGenerator
) {
parent::__construct($em);
}
/**
* @param Entity\StationPlaylist|Entity\StationStreamer $relation
* @param \App\Entity\StationPlaylist|\App\Entity\StationStreamer $relation
* @param array $items
*/
public function setScheduleItems(Entity\StationPlaylist|Entity\StationStreamer $relation, array $items = []): void
{
public function setScheduleItems(
StationPlaylist|StationStreamer $relation,
array $items = []
): void {
$rawScheduleItems = $this->findByRelation($relation);
$scheduleItems = [];
@ -42,7 +48,7 @@ final class StationScheduleRepository extends Repository
$record = $scheduleItems[$item['id']];
unset($scheduleItems[$item['id']]);
} else {
$record = new Entity\StationSchedule($relation);
$record = new StationSchedule($relation);
}
$record->setStartTime((int)$item['start_time']);
@ -63,13 +69,13 @@ final class StationScheduleRepository extends Repository
}
/**
* @param Entity\StationPlaylist|Entity\StationStreamer $relation
* @param \App\Entity\StationPlaylist|\App\Entity\StationStreamer $relation
*
* @return Entity\StationSchedule[]
* @return \App\Entity\StationSchedule[]
*/
public function findByRelation(Entity\StationPlaylist|Entity\StationStreamer $relation): array
public function findByRelation(StationPlaylist|StationStreamer $relation): array
{
if ($relation instanceof Entity\StationPlaylist) {
if ($relation instanceof StationPlaylist) {
return $this->repository->findBy(['playlist' => $relation]);
}
@ -77,16 +83,16 @@ final class StationScheduleRepository extends Repository
}
/**
* @param Entity\Station $station
* @param \App\Entity\Station $station
*
* @return Entity\StationSchedule[]
* @return \App\Entity\StationSchedule[]
*/
public function getAllScheduledItemsForStation(Entity\Station $station): array
public function getAllScheduledItemsForStation(Station $station): array
{
return $this->em->createQuery(
<<<'DQL'
SELECT ssc, sp, sst
FROM App\Entity\StationSchedule ssc
FROM App\\App\Entity\StationSchedule ssc
LEFT JOIN ssc.playlist sp
LEFT JOIN ssc.streamer sst
WHERE (sp.station = :station AND sp.is_jingle = 0 AND sp.is_enabled = 1)
@ -97,12 +103,12 @@ final class StationScheduleRepository extends Repository
}
/**
* @param Entity\Station $station
* @param \App\Entity\Station $station
* @param CarbonInterface|null $now
*
* @return Entity\Api\StationSchedule[]
* @return \App\Entity\Api\StationSchedule[]
*/
public function getUpcomingSchedule(Entity\Station $station, CarbonInterface $now = null): array
public function getUpcomingSchedule(Station $station, CarbonInterface $now = null): array
{
if (null === $now) {
$now = CarbonImmutable::now($station->getTimezoneObject());
@ -114,7 +120,7 @@ final class StationScheduleRepository extends Repository
$events = [];
foreach ($this->getAllScheduledItemsForStation($station) as $scheduleItem) {
/** @var Entity\StationSchedule $scheduleItem */
/** @var \App\Entity\StationSchedule $scheduleItem */
$i = $startDate;
while ($i <= $endDate) {
@ -124,8 +130,8 @@ final class StationScheduleRepository extends Repository
$this->scheduler->shouldSchedulePlayOnCurrentDate($scheduleItem, $i)
&& $this->scheduler->isScheduleScheduledToPlayToday($scheduleItem, $dayOfWeek)
) {
$start = Entity\StationSchedule::getDateTime($scheduleItem->getStartTime(), $i);
$end = Entity\StationSchedule::getDateTime($scheduleItem->getEndTime(), $i);
$start = StationSchedule::getDateTime($scheduleItem->getStartTime(), $i);
$end = StationSchedule::getDateTime($scheduleItem->getEndTime(), $i);
// Handle overnight schedule items
if ($end < $start) {

View File

@ -5,26 +5,28 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\Repository;
use App\Entity;
use Carbon\CarbonImmutable;
use App\Entity\Station;
use App\Entity\StationStreamerBroadcast;
use App\Entity\StationStreamer;
/**
* @extends Repository<Entity\StationStreamerBroadcast>
* @extends Repository<\App\Entity\StationStreamerBroadcast>
*/
final class StationStreamerBroadcastRepository extends Repository
{
public function getLatestBroadcast(Entity\Station $station): ?Entity\StationStreamerBroadcast
public function getLatestBroadcast(Station $station): ?StationStreamerBroadcast
{
$currentStreamer = $station->getCurrentStreamer();
if (null === $currentStreamer) {
return null;
}
/** @var Entity\StationStreamerBroadcast|null $latestBroadcast */
/** @var \App\Entity\StationStreamerBroadcast|null $latestBroadcast */
$latestBroadcast = $this->em->createQuery(
<<<'DQL'
SELECT ssb
FROM App\Entity\StationStreamerBroadcast ssb
FROM App\\App\Entity\StationStreamerBroadcast ssb
WHERE ssb.station = :station AND ssb.streamer = :streamer
ORDER BY ssb.timestampStart DESC
DQL
@ -36,11 +38,11 @@ final class StationStreamerBroadcastRepository extends Repository
return $latestBroadcast;
}
public function endAllActiveBroadcasts(Entity\Station $station): void
public function endAllActiveBroadcasts(Station $station): void
{
$this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\StationStreamerBroadcast ssb
UPDATE App\\App\Entity\StationStreamerBroadcast ssb
SET ssb.timestampEnd = :time
WHERE ssb.station = :station
AND ssb.timestampEnd = 0
@ -51,11 +53,11 @@ final class StationStreamerBroadcastRepository extends Repository
}
/**
* @param Entity\Station $station
* @param \App\Entity\Station $station
*
* @return Entity\StationStreamerBroadcast[]
* @return \App\Entity\StationStreamerBroadcast[]
*/
public function getActiveBroadcasts(Entity\Station $station): array
public function getActiveBroadcasts(Station $station): array
{
return $this->repository->findBy([
'station' => $station,
@ -63,7 +65,7 @@ final class StationStreamerBroadcastRepository extends Repository
]);
}
public function findByPath(Entity\Station $station, string $path): ?Entity\StationStreamerBroadcast
public function findByPath(Station $station, string $path): ?StationStreamerBroadcast
{
return $this->repository->findOneBy([
'station' => $station,
@ -72,12 +74,12 @@ final class StationStreamerBroadcastRepository extends Repository
}
public function getOrCreateFromPath(
Entity\Station $station,
Station $station,
string $recordingPath,
): ?Entity\StationStreamerBroadcast {
): ?StationStreamerBroadcast {
$streamerUsername = pathinfo($recordingPath, PATHINFO_DIRNAME);
$streamer = $this->em->getRepository(Entity\StationStreamer::class)
$streamer = $this->em->getRepository(StationStreamer::class)
->findOneBy([
'station' => $station,
'streamer_username' => $streamerUsername,
@ -89,7 +91,7 @@ final class StationStreamerBroadcastRepository extends Repository
}
$startTimeRaw = str_replace(
Entity\StationStreamerBroadcast::PATH_PREFIX . '_',
StationStreamerBroadcast::PATH_PREFIX . '_',
'',
pathinfo($recordingPath, PATHINFO_FILENAME)
);
@ -106,7 +108,7 @@ final class StationStreamerBroadcastRepository extends Repository
$record = $this->em->createQuery(
<<<'DQL'
SELECT ssb
FROM App\Entity\StationStreamerBroadcast ssb
FROM App\\App\Entity\StationStreamerBroadcast ssb
WHERE ssb.streamer = :streamer
AND ssb.timestampStart >= :start AND ssb.timestampStart <= :end
AND ssb.recordingPath IS NULL
@ -118,7 +120,7 @@ final class StationStreamerBroadcastRepository extends Repository
->getOneOrNullResult();
if (null === $record) {
$record = new Entity\StationStreamerBroadcast($streamer);
$record = new StationStreamerBroadcast($streamer);
}
$record->setTimestampStart($startTime->getTimestamp());

View File

@ -5,13 +5,15 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Entity;
use App\Flysystem\StationFilesystems;
use App\Media\AlbumArt;
use App\Radio\AutoDJ\Scheduler;
use App\Entity\Station;
use App\Entity\StationStreamer;
use App\Entity\StationStreamerBroadcast;
/**
* @extends AbstractStationBasedRepository<Entity\StationStreamer>
* @extends AbstractStationBasedRepository<\App\Entity\StationStreamer>
*/
final class StationStreamerRepository extends AbstractStationBasedRepository
{
@ -26,12 +28,12 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
/**
* Attempt to authenticate a streamer.
*
* @param Entity\Station $station
* @param \App\Entity\Station $station
* @param string $username
* @param string $password
*/
public function authenticate(
Entity\Station $station,
Station $station,
string $username = '',
string $password = ''
): bool {
@ -41,7 +43,7 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
}
$streamer = $this->getStreamer($station, $username);
if (!($streamer instanceof Entity\StationStreamer)) {
if (!($streamer instanceof StationStreamer)) {
return false;
}
@ -49,17 +51,17 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
}
/**
* @param Entity\Station $station
* @param \App\Entity\Station $station
* @param string $username
*
*/
public function onConnect(Entity\Station $station, string $username = ''): string|bool
public function onConnect(Station $station, string $username = ''): string|bool
{
// End all current streamer sessions.
$this->broadcastRepo->endAllActiveBroadcasts($station);
$streamer = $this->getStreamer($station, $username);
if (!($streamer instanceof Entity\StationStreamer)) {
if (!($streamer instanceof StationStreamer)) {
return false;
}
@ -67,14 +69,14 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
$station->setCurrentStreamer($streamer);
$this->em->persist($station);
$record = new Entity\StationStreamerBroadcast($streamer);
$record = new StationStreamerBroadcast($streamer);
$this->em->persist($record);
$this->em->flush();
return true;
}
public function onDisconnect(Entity\Station $station): bool
public function onDisconnect(Station $station): bool
{
foreach ($this->broadcastRepo->getActiveBroadcasts($station) as $broadcast) {
$broadcast->setTimestampEnd(time());
@ -90,10 +92,10 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
}
public function getStreamer(
Entity\Station $station,
Station $station,
string $username = '',
bool $activeOnly = true
): ?Entity\StationStreamer {
): ?StationStreamer {
$criteria = [
'station' => $station,
'streamer_username' => $username,
@ -103,17 +105,17 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
$criteria['is_active'] = 1;
}
/** @var Entity\StationStreamer|null $streamer */
/** @var \App\Entity\StationStreamer|null $streamer */
$streamer = $this->repository->findOneBy($criteria);
return $streamer;
}
public function writeArtwork(
Entity\StationStreamer $streamer,
StationStreamer $streamer,
string $rawArtworkString
): void {
$artworkPath = Entity\StationStreamer::getArtworkPath($streamer->getIdRequired());
$artworkPath = StationStreamer::getArtworkPath($streamer->getIdRequired());
$artworkString = AlbumArt::resize($rawArtworkString);
$fsConfig = StationFilesystems::buildConfigFilesystem($streamer->getStation());
@ -124,9 +126,9 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
}
public function removeArtwork(
Entity\StationStreamer $streamer
StationStreamer $streamer
): void {
$artworkPath = Entity\StationStreamer::getArtworkPath($streamer->getIdRequired());
$artworkPath = StationStreamer::getArtworkPath($streamer->getIdRequired());
$fsConfig = StationFilesystems::buildConfigFilesystem($streamer->getStation());
$fsConfig->delete($artworkPath);
@ -136,7 +138,7 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
}
public function delete(
Entity\StationStreamer $streamer
StationStreamer $streamer
): void {
$this->removeArtwork($streamer);

View File

@ -4,10 +4,10 @@ declare(strict_types=1);
namespace App\Entity\Repository;
use App\Entity;
use App\Entity\StationWebhook;
/**
* @extends AbstractStationBasedRepository<Entity\StationWebhook>
* @extends AbstractStationBasedRepository<StationWebhook>
*/
final class StationWebhookRepository extends AbstractStationBasedRepository
{

Some files were not shown because too many files have changed in this diff Show More