Code quality cleanup sweep.

This commit is contained in:
Buster "Silver Eagle" Neece 2022-05-08 13:05:02 -05:00
parent fe61967c50
commit a9f066602c
No known key found for this signature in database
GPG Key ID: 9FC8B9E008872109
87 changed files with 245 additions and 283 deletions

View File

@ -6,10 +6,9 @@ declare(strict_types=1);
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
ini_set('display_errors', '1');
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
require dirname(__DIR__) . '/vendor/autoload.php';
$cli = App\AppFactory::createCli(
$autoloader,
[
App\Environment::BASE_DIR => dirname(__DIR__),
]

View File

@ -18,6 +18,7 @@
"ext-iconv": "*",
"ext-intl": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-maxminddb": "*",
"ext-mbstring": "*",
"ext-redis": "*",

View File

@ -8,10 +8,8 @@ use App\Console\Application;
use App\Enums\SupportedLocales;
use App\Http\Factory\ResponseFactory;
use App\Http\Factory\ServerRequestFactory;
use Composer\Autoload\ClassLoader;
use DI;
use DI\Bridge\Slim\ControllerInvoker;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Invoker\Invoker;
use Invoker\ParameterResolver\AssociativeArrayResolver;
use Invoker\ParameterResolver\Container\TypeHintContainerResolver;
@ -31,33 +29,19 @@ use const E_USER_ERROR;
class AppFactory
{
/**
* @param ClassLoader|null $autoloader
* @param array<string, mixed> $appEnvironment
* @param array<string, mixed> $diDefinitions
*
*/
public static function createApp(
?ClassLoader $autoloader = null,
array $appEnvironment = [],
array $diDefinitions = []
): App {
$di = self::buildContainer($autoloader, $appEnvironment, $diDefinitions);
$di = self::buildContainer($appEnvironment, $diDefinitions);
return self::buildAppFromContainer($di);
}
/**
* @param ClassLoader|null $autoloader
* @param array<string, mixed> $appEnvironment
* @param array<string, mixed> $diDefinitions
*
*/
public static function createCli(
?ClassLoader $autoloader = null,
array $appEnvironment = [],
array $diDefinitions = []
): Application {
$di = self::buildContainer($autoloader, $appEnvironment, $diDefinitions);
$di = self::buildContainer($appEnvironment, $diDefinitions);
self::buildAppFromContainer($di);
$env = $di->get(Environment::class);
@ -106,24 +90,10 @@ class AppFactory
return $app;
}
/**
* @param ClassLoader|null $autoloader
* @param array<string, mixed> $appEnvironment
* @param array<string, mixed> $diDefinitions
*
* @noinspection SummerTimeUnsafeTimeManipulationInspection
*
*/
public static function buildContainer(
?ClassLoader $autoloader = null,
array $appEnvironment = [],
array $diDefinitions = []
): DI\Container {
// Register Annotation autoloader
if (null !== $autoloader) {
AnnotationRegistry::registerLoader([$autoloader, 'loadClass']);
}
$environment = self::buildEnvironment($appEnvironment);
Environment::setInstance($environment);
@ -132,22 +102,20 @@ class AppFactory
// Override DI definitions for settings.
$diDefinitions[Environment::class] = $environment;
if ($autoloader) {
$plugins = new Plugins($environment->getBaseDirectory() . '/plugins');
$plugins = new Plugins($environment->getBaseDirectory() . '/plugins');
$diDefinitions[Plugins::class] = $plugins;
$diDefinitions = $plugins->registerServices($diDefinitions);
}
$diDefinitions[Plugins::class] = $plugins;
$diDefinitions = $plugins->registerServices($diDefinitions);
$containerBuilder = new DI\ContainerBuilder();
$containerBuilder->useAutowiring(true);
/*
$containerBuilder->enableDefinitionCache();
// TODO Implement APCu
// $containerBuilder->enableDefinitionCache();
if ($environment->isProduction()) {
$containerBuilder->enableCompilation($environment->getTempDirectory());
}
*/
$containerBuilder->addDefinitions($diDefinitions);

View File

@ -253,9 +253,9 @@ class Assets
$this->addInlineJs(
<<<JS
let ${name};
let {$name};
$(function () {
${name} = ${nameWithoutPrefix}.default('${elementId}', ${propsJson});
{$name} = {$nameWithoutPrefix}.default('{$elementId}', {$propsJson});
});
JS
);

View File

@ -15,6 +15,7 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Path;
use Throwable;
use const PATHINFO_EXTENSION;
@ -101,7 +102,7 @@ class BackupCommand extends AbstractBackupCommand
$tmp_dir_mariadb = '/tmp/azuracast_backup_mariadb';
try {
$fsUtils->mkdir($tmp_dir_mariadb);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$io->error($e->getMessage());
return 1;
}

View File

@ -9,6 +9,7 @@ use App\Entity;
use App\Entity\Repository\StationRepository;
use App\Radio\Backend\Liquidsoap\Command\AbstractCommand;
use App\Radio\Enums\LiquidsoapCommands;
use LogicException;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
@ -17,6 +18,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;
#[AsCommand(
name: 'azuracast:internal:liquidsoap',
@ -62,12 +64,12 @@ class LiquidsoapCommand extends CommandAbstract
try {
$station = $this->stationRepo->findByIdentifier($stationId);
if (!($station instanceof Entity\Station)) {
throw new \LogicException('Station not found.');
throw new LogicException('Station not found.');
}
$command = LiquidsoapCommands::tryFrom($action);
if (null === $command || !$this->di->has($command->getClass())) {
throw new \LogicException('Command not found.');
throw new LogicException('Command not found.');
}
/** @var AbstractCommand $commandObj */
@ -75,7 +77,7 @@ class LiquidsoapCommand extends CommandAbstract
$result = $commandObj->run($station, $asAutoDj, $payload);
$io->writeln($result);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error(
sprintf(
'Liquidsoap command "%s" error: %s',

View File

@ -65,7 +65,7 @@ class SftpEventCommand extends CommandAbstract
$storageLocation = $sftpUser->getStation()->getMediaStorageLocation();
if (!$storageLocation->isLocal()) {
$this->logger->error(sprintf('Storage location "%s" is not local.', (string)$storageLocation));
$this->logger->error(sprintf('Storage location "%s" is not local.', $storageLocation));
return 1;
}

View File

@ -14,6 +14,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;
#[AsCommand(
name: 'azuracast:radio:restart',
@ -73,7 +74,7 @@ class RestartRadioCommand extends CommandAbstract
reloadSupervisor: !$noSupervisorRestart,
forceRestart: true
);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$io->error([
$station . ': ' . $e->getMessage(),
]);

View File

@ -12,6 +12,8 @@ use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Lock\Lock;
use Symfony\Component\Process\Process;
use function random_int;
abstract class AbstractSyncCommand extends CommandAbstract
{
protected array $processes = [];
@ -34,7 +36,7 @@ abstract class AbstractSyncCommand extends CommandAbstract
$process = $processGroup['process'];
// 10% chance that refresh will be called
if (\random_int(1, 100) <= 10) {
if (random_int(1, 100) <= 10) {
$lock->refresh();
}

View File

@ -15,6 +15,8 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use function random_int;
#[AsCommand(
name: 'azuracast:sync:nowplaying',
description: 'Task to run the Now Playing worker task.'
@ -81,7 +83,7 @@ class NowPlayingCommand extends AbstractSyncCommand
if (!isset($this->processes[$shortName])) {
$npTimestamp = (int)$activeStation['nowplaying_timestamp'];
if (time() > $npTimestamp + \random_int(5, 15)) {
if (time() > $npTimestamp + random_int(5, 15)) {
$this->start($io, $shortName);
usleep(250000);

View File

@ -15,6 +15,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;
#[AsCommand(
name: 'azuracast:sync:nowplaying:station',
@ -63,7 +64,7 @@ class NowPlayingPerStationCommand extends CommandAbstract
try {
$this->buildQueueTask->run($station);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error(
'Queue builder error: ' . $e->getMessage(),
['exception' => $e]
@ -72,7 +73,7 @@ class NowPlayingPerStationCommand extends CommandAbstract
try {
$this->nowPlayingTask->run($station);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error(
'Now Playing error: ' . $e->getMessage(),
['exception' => $e]

View File

@ -8,8 +8,10 @@ use App\Entity\Repository\SettingsRepository;
use App\Environment;
use App\Event\GetSyncTasks;
use App\LockFactory;
use App\Sync\Task\AbstractTask;
use Carbon\CarbonImmutable;
use Cron\CronExpression;
use DateTimeZone;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
@ -17,6 +19,8 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use function usleep;
#[AsCommand(
name: 'azuracast:sync:run',
description: 'Task to run the minute\'s synchronized tasks.'
@ -46,7 +50,7 @@ class RunnerCommand extends AbstractSyncCommand
$syncTasksEvent = new GetSyncTasks();
$this->dispatcher->dispatch($syncTasksEvent);
$now = CarbonImmutable::now(new \DateTimeZone('UTC'));
$now = CarbonImmutable::now(new DateTimeZone('UTC'));
foreach ($syncTasksEvent->getTasks() as $taskClass) {
$schedulePattern = $taskClass::getSchedulePattern();
@ -71,12 +75,12 @@ class RunnerCommand extends AbstractSyncCommand
$this->checkRunningProcesses();
}
\usleep(250000);
usleep(250000);
}
/**
* @param SymfonyStyle $io
* @param class-string $taskClass
* @param class-string<AbstractTask> $taskClass
*/
protected function start(
SymfonyStyle $io,

View File

@ -6,9 +6,11 @@ namespace App\Console\Command\Sync;
use App\Console\Command\CommandAbstract;
use App\Sync\Task\AbstractTask;
use InvalidArgumentException;
use Monolog\Logger;
use Psr\Container\ContainerInterface;
use Psr\SimpleCache\CacheInterface;
use ReflectionClass;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@ -43,7 +45,7 @@ class SingleTaskCommand extends CommandAbstract
try {
$this->runTask($task);
} catch (\InvalidArgumentException $e) {
} catch (InvalidArgumentException $e) {
$io->error($e->getMessage());
return 1;
}
@ -60,12 +62,12 @@ class SingleTaskCommand extends CommandAbstract
bool $force = false
): void {
if (!$this->di->has($task)) {
throw new \InvalidArgumentException('Task not found.');
throw new InvalidArgumentException('Task not found.');
}
$taskClass = $this->di->get($task);
if (!($taskClass instanceof AbstractTask)) {
throw new \InvalidArgumentException('Specified class is not a synchronized task.');
throw new InvalidArgumentException('Specified class is not a synchronized task.');
}
$taskShortName = self::getClassShortName($task);
@ -106,6 +108,6 @@ class SingleTaskCommand extends CommandAbstract
*/
public static function getClassShortName(string $taskClass): string
{
return (new \ReflectionClass($taskClass))->getShortName();
return (new ReflectionClass($taskClass))->getShortName();
}
}

View File

@ -19,6 +19,7 @@ use App\Session\Flash;
use App\Sync\NowPlaying\Task\NowPlayingTask;
use Carbon\CarbonImmutable;
use Cron\CronExpression;
use DateTimeZone;
use Doctrine\ORM\EntityManagerInterface;
use Monolog\Handler\TestHandler;
use Monolog\Logger;
@ -55,7 +56,7 @@ class DebugController extends AbstractLogViewerController
}
$syncTimes = [];
$now = CarbonImmutable::now(new \DateTimeZone('UTC'));
$now = CarbonImmutable::now(new DateTimeZone('UTC'));
$syncTasksEvent = new GetSyncTasks();
$dispatcher->dispatch($syncTasksEvent);

View File

@ -7,6 +7,7 @@ namespace App\Controller\Admin;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use RuntimeException;
class ShoutcastAction
{
@ -15,7 +16,7 @@ class ShoutcastAction
Response $response
): ResponseInterface {
if ('x86_64' !== php_uname('m')) {
throw new \RuntimeException('SHOUTcast cannot be installed on non-X86_64 systems.');
throw new RuntimeException('SHOUTcast cannot be installed on non-X86_64 systems.');
}
$router = $request->getRouter();

View File

@ -28,9 +28,9 @@ class StationsAction
props: array_merge(
$stationFormComponent->getProps($request),
[
'listUrl' => (string)$router->fromHere('api:admin:stations'),
'frontendTypes' => $adapters->listFrontendAdapters(false),
'backendTypes' => $adapters->listBackendAdapters(false),
'listUrl' => (string)$router->fromHere('api:admin:stations'),
'frontendTypes' => $adapters->listFrontendAdapters(),
'backendTypes' => $adapters->listBackendAdapters(),
]
)
);

View File

@ -21,6 +21,6 @@ class GetLogAction
): ResponseInterface {
$logPath = File::validateTempPath($path);
return $this->streamLogToResponse($request, $response, $logPath, true);
return $this->streamLogToResponse($request, $response, $logPath);
}
}

View File

@ -10,6 +10,7 @@ use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\Flow;
use Psr\Http\Message\ResponseInterface;
use RuntimeException;
use Symfony\Component\Process\Process;
class PostAction
@ -20,7 +21,7 @@ class PostAction
Environment $environment
): ResponseInterface {
if ('x86_64' !== php_uname('m')) {
throw new \RuntimeException('SHOUTcast cannot be installed on non-X86_64 systems.');
throw new RuntimeException('SHOUTcast cannot be installed on non-X86_64 systems.');
}
$flowResponse = Flow::process($request, $response);

View File

@ -12,6 +12,7 @@ use App\Http\ServerRequest;
use DeepCopy;
use Doctrine\Common\Collections\Collection;
use Psr\Http\Message\ResponseInterface;
use Throwable;
class CloneAction extends StationsController
{
@ -186,7 +187,7 @@ class CloneAction extends StationsController
try {
$this->configuration->writeConfiguration($newStation);
} catch (\Throwable $e) {
} catch (Throwable $e) {
}
$this->em->flush();

View File

@ -20,6 +20,7 @@ use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Throwable;
/** @extends AbstractAdminApiCrudController<Entity\Station> */
#[
@ -331,7 +332,7 @@ class StationsController extends AbstractAdminApiCrudController
station: $station,
forceRestart: true
);
} catch (\Throwable $e) {
} catch (Throwable $e) {
}
}

View File

@ -17,7 +17,7 @@ class DeleteTwoFactorAction extends UsersController
$user = $request->getUser();
$user = $this->em->refetch($user);
$user->setTwoFactorSecret(null);
$user->setTwoFactorSecret();
$this->em->persist($user);
$this->em->flush();

View File

@ -9,9 +9,12 @@ use App\Http\Response;
use App\Http\ServerRequest;
use App\Radio\Backend\Liquidsoap\Command\AbstractCommand;
use App\Radio\Enums\LiquidsoapCommands;
use InvalidArgumentException;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Throwable;
class LiquidsoapAction
{
@ -31,13 +34,13 @@ class LiquidsoapAction
if (!$acl->isAllowed(StationPermissions::View, $station->getIdRequired())) {
$authKey = $request->getHeaderLine('X-Liquidsoap-Api-Key');
if (!$station->validateAdapterApiKey($authKey)) {
throw new \RuntimeException('Invalid API key.');
throw new RuntimeException('Invalid API key.');
}
}
$command = LiquidsoapCommands::tryFrom($action);
if (null === $command || !$di->has($command->getClass())) {
throw new \InvalidArgumentException('Command not found.');
throw new InvalidArgumentException('Command not found.');
}
/** @var AbstractCommand $commandObj */
@ -45,7 +48,7 @@ class LiquidsoapAction
$result = $commandObj->run($station, $asAutoDj, $payload);
$response->getBody()->write((string)$result);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$logger->error(
sprintf(
'Liquidsoap command "%s" error: %s',

View File

@ -24,6 +24,7 @@ use InvalidArgumentException;
use League\Flysystem\StorageAttributes;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Http\Message\ResponseInterface;
use RuntimeException;
use Symfony\Component\Messenger\MessageBus;
use Throwable;
@ -306,7 +307,7 @@ class BatchAction
$result = $this->parseRequest($request, $fs, true);
if (BackendAdapters::Liquidsoap !== $station->getBackendTypeEnum()) {
throw new \RuntimeException('This functionality can only be used on stations that use Liquidsoap.');
throw new RuntimeException('This functionality can only be used on stations that use Liquidsoap.');
}
/** @var Liquidsoap $backend */
@ -336,7 +337,7 @@ class BatchAction
$newQueue = Entity\StationQueue::fromMedia($station, $media);
$newQueue->setTimestampCued($cuedTimestamp);
$newQueue->setIsPlayed(true);
$newQueue->setIsPlayed();
$this->em->persist($newQueue);
$event = AnnotateNextSong::fromStationQueue($newQueue, true);

View File

@ -13,6 +13,7 @@ use App\Radio\Backend\Liquidsoap;
use App\Radio\Backend\Liquidsoap\ConfigWriter;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Http\Message\ResponseInterface;
use Throwable;
class PutAction
{
@ -45,7 +46,7 @@ class PutAction
$config = $event->buildConfiguration();
$liquidsoap->verifyConfig($config);
} catch (\Throwable $e) {
} catch (Throwable $e) {
return $response->withStatus(500)->withJson(Entity\Api\Error::fromException($e));
}

View File

@ -333,7 +333,7 @@ class PodcastEpisodesController extends AbstractApiCrudController
/**
* @inheritDoc
*/
protected function viewRecord(object $record, ServerRequest $request): mixed
protected function viewRecord(object $record, ServerRequest $request): Entity\Api\PodcastEpisode
{
if (!($record instanceof Entity\PodcastEpisode)) {
throw new InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));

View File

@ -268,16 +268,10 @@ class PodcastsController extends AbstractApiCrudController
*/
protected function getRecord(Entity\Station $station, string $id): ?object
{
$record = $this->podcastRepository->fetchPodcastForStation($station, $id);
return $record;
return $this->podcastRepository->fetchPodcastForStation($station, $id);
}
/**
* @param Entity\Podcast $record
* @param ServerRequest $request
*
*/
protected function viewRecord(object $record, ServerRequest $request): mixed
protected function viewRecord(object $record, ServerRequest $request): Entity\Api\Podcast
{
if (!($record instanceof Entity\Podcast)) {
throw new InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));

View File

@ -179,7 +179,7 @@ class RemotesController extends AbstractStationApiCrudController
return $this->listPaginatedFromQuery($request, $response, $qb->getQuery());
}
protected function viewRecord(object $record, ServerRequest $request): mixed
protected function viewRecord(object $record, ServerRequest $request): Entity\Api\StationRemote
{
if (!($record instanceof Entity\StationRemote)) {
throw new InvalidArgumentException(

View File

@ -14,6 +14,7 @@ use App\Radio\Configuration;
use Doctrine\ORM\EntityManagerInterface;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
use Throwable;
#[
OA\Get(
@ -136,7 +137,7 @@ class ServicesController
station: $station,
forceRestart: true
);
} catch (\Throwable $e) {
} catch (Throwable $e) {
return $response->withJson(
new Entity\Api\Error(
500,
@ -159,7 +160,7 @@ class ServicesController
forceRestart: true,
attemptReload: false
);
} catch (\Throwable $e) {
} catch (Throwable $e) {
return $response->withJson(
new Entity\Api\Error(
500,

View File

@ -37,8 +37,7 @@ class TestLogAction extends AbstractWebhooksAction
return $this->streamLogToResponse(
$request,
$response,
$tempPath,
true
$tempPath
);
}
}

View File

@ -38,7 +38,7 @@ class Customization
$this->user = $request->getAttribute(ServerRequest::ATTR_USER);
// Register current theme
$this->theme = $this->determineTheme($request, false);
$this->theme = $this->determineTheme($request);
$this->publicTheme = $this->determineTheme($request, true);
// Register locale
@ -114,7 +114,7 @@ class Customization
$publicCss .= <<<CSS
[data-theme] body.page-minimal {
background-image: url('${backgroundUrl}');
background-image: url('{$backgroundUrl}');
}
CSS;
}

View File

@ -16,7 +16,7 @@ class DecoratedEntityManager extends EntityManagerDecorator implements Reloadabl
public function __construct(callable $createEm)
{
parent::__construct($createEm());
$this->createEm = Closure::fromCallable($createEm);
$this->createEm = $createEm(...);
}
/**

View File

@ -67,9 +67,7 @@ class NowPlaying implements ResolvableUrlInterface
*/
public function resolveUrls(UriInterface $base): void
{
if ($this->station instanceof ResolvableUrlInterface) {
$this->station->resolveUrls($base);
}
$this->station->resolveUrls($base);
if ($this->now_playing instanceof ResolvableUrlInterface) {
$this->now_playing->resolveUrls($base);

View File

@ -60,8 +60,6 @@ class SongHistory implements ResolvableUrlInterface
*/
public function resolveUrls(UriInterface $base): void
{
if ($this->song instanceof ResolvableUrlInterface) {
$this->song->resolveUrls($base);
}
$this->song->resolveUrls($base);
}
}

View File

@ -55,8 +55,6 @@ class StationQueue implements ResolvableUrlInterface
*/
public function resolveUrls(UriInterface $base): void
{
if ($this->song instanceof ResolvableUrlInterface) {
$this->song->resolveUrls($base);
}
$this->song->resolveUrls($base);
}
}

View File

@ -126,11 +126,7 @@ class NowPlayingApiGenerator
?UriInterface $baseUri = null
): Entity\Api\NowPlaying\NowPlaying {
$np = $station->getNowplaying();
if (null !== $np) {
return $np;
}
return $this->offlineApi($station, $baseUri);
return $np ?? $this->offlineApi($station, $baseUri);
}
protected function offlineApi(

View File

@ -5,9 +5,10 @@ declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use JsonSerializable;
#[ORM\Embeddable]
class ListenerDevice implements \JsonSerializable
class ListenerDevice implements JsonSerializable
{
#[ORM\Column(length: 255)]
protected ?string $client = null;
@ -57,7 +58,7 @@ class ListenerDevice implements \JsonSerializable
return $this->os_family;
}
public function jsonSerialize(): mixed
public function jsonSerialize(): array
{
return [
'client' => $this->client,

View File

@ -5,9 +5,10 @@ declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use JsonSerializable;
#[ORM\Embeddable]
class ListenerLocation implements \JsonSerializable
class ListenerLocation implements JsonSerializable
{
#[ORM\Column(length: 255, nullable: false)]
protected string $description = 'Unknown';
@ -57,7 +58,7 @@ class ListenerLocation implements \JsonSerializable
return $this->lon;
}
public function jsonSerialize(): mixed
public function jsonSerialize(): array
{
return [
'description' => $this->description,

View File

@ -17,17 +17,17 @@ final class Version20180425050351 extends AbstractMigration
*/
public function up(Schema $schema): void
{
$this->changeCharset('utf8mb4', 'utf8mb4_bin');
$this->changeCharset('utf8mb4_bin');
}
private function changeCharset(string $charset, string $collate): void
private function changeCharset(string $collate): void
{
$sqlLines = [
'ALTER TABLE `station_media` DROP FOREIGN KEY FK_32AADE3AA0BDB2F3',
'ALTER TABLE `song_history` DROP FOREIGN KEY FK_2AD16164A0BDB2F3',
'ALTER TABLE `station_media` CONVERT TO CHARACTER SET ' . $charset . ' COLLATE ' . $collate,
'ALTER TABLE `song_history` CONVERT TO CHARACTER SET ' . $charset . ' COLLATE ' . $collate,
'ALTER TABLE `songs` CONVERT TO CHARACTER SET ' . $charset . ' COLLATE ' . $collate,
'ALTER TABLE `station_media` CONVERT TO CHARACTER SET utf8mb4 COLLATE ' . $collate,
'ALTER TABLE `song_history` CONVERT TO CHARACTER SET utf8mb4 COLLATE ' . $collate,
'ALTER TABLE `songs` CONVERT TO CHARACTER SET utf8mb4 COLLATE ' . $collate,
'ALTER TABLE `song_history` ADD CONSTRAINT FK_2AD16164A0BDB2F3 FOREIGN KEY (song_id) REFERENCES songs (id) ON DELETE CASCADE',
'ALTER TABLE `station_media` ADD CONSTRAINT FK_32AADE3AA0BDB2F3 FOREIGN KEY (song_id) REFERENCES songs (id) ON DELETE SET NULL',
];
@ -42,6 +42,6 @@ final class Version20180425050351 extends AbstractMigration
*/
public function down(Schema $schema): void
{
$this->changeCharset('utf8mb4', 'utf8mb4_unicode_ci');
$this->changeCharset('utf8mb4_unicode_ci');
}
}

View File

@ -17,10 +17,10 @@ final class Version20180826043500 extends AbstractMigration
*/
public function up(Schema $schema): void
{
$this->changeCharset('utf8mb4', 'utf8mb4_general_ci');
$this->changeCharset('utf8mb4_general_ci');
}
private function changeCharset(string $charset, string $collate): void
private function changeCharset(string $collate): void
{
$db_name = $this->connection->getDatabase() ?? 'azuracast';
@ -51,7 +51,9 @@ final class Version20180826043500 extends AbstractMigration
];
$sqlLines = [
'ALTER DATABASE ' . $this->connection->quoteIdentifier($db_name) . ' CHARACTER SET = ' . $charset . ' COLLATE = ' . $collate,
'ALTER DATABASE ' . $this->connection->quoteIdentifier(
$db_name
) . ' CHARACTER SET = utf8mb4 COLLATE = ' . $collate,
'ALTER TABLE `song_history` DROP FOREIGN KEY FK_2AD16164A0BDB2F3',
'ALTER TABLE `station_media` DROP FOREIGN KEY FK_32AADE3AA0BDB2F3',
];
@ -60,7 +62,11 @@ final class Version20180826043500 extends AbstractMigration
}
foreach ($tables as $table_name) {
$this->addSql('ALTER TABLE ' . $this->connection->quoteIdentifier($table_name) . ' CONVERT TO CHARACTER SET ' . $charset . ' COLLATE ' . $collate);
$this->addSql(
'ALTER TABLE ' . $this->connection->quoteIdentifier(
$table_name
) . ' CONVERT TO CHARACTER SET utf8mb4 COLLATE ' . $collate
);
}
$sqlLines = [
@ -77,6 +83,6 @@ final class Version20180826043500 extends AbstractMigration
*/
public function down(Schema $schema): void
{
$this->changeCharset('utf8mb4', 'utf8mb4_unicode_ci');
$this->changeCharset('utf8mb4_unicode_ci');
}
}

View File

@ -7,25 +7,20 @@ namespace App\Entity\Migration;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210620131126 extends AbstractMigration
{
public function getDescription(): string
{
return '';
return 'Add "max_listener_duration" to station_mounts table.';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE station_mounts ADD max_listener_duration INT NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE station_mounts DROP max_listener_duration');
}
}

View File

@ -7,26 +7,21 @@ namespace App\Entity\Migration;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210703185549 extends AbstractMigration
{
public function getDescription(): string
{
return '';
return 'Add columns to facilitate "loop once" functionality.';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE station_playlists ADD queue_reset_at INT NOT NULL');
$this->addSql('ALTER TABLE station_schedules ADD loop_once TINYINT(1) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE station_playlists DROP queue_reset_at');
$this->addSql('ALTER TABLE station_schedules DROP loop_once');
}

View File

@ -7,25 +7,20 @@ namespace App\Entity\Migration;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210805004608 extends AbstractMigration
{
public function getDescription(): string
{
return '';
return 'Add author and e-mail to podcast table.';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE podcast ADD author VARCHAR(255) NOT NULL, ADD email VARCHAR(255) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE podcast DROP author, DROP email');
}
}

View File

@ -7,26 +7,21 @@ namespace App\Entity\Migration;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20211227232320 extends AbstractMigration
{
public function getDescription(): string
{
return '';
return 'Change on-delete behavior of media on song_history table.';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE song_history DROP FOREIGN KEY FK_2AD16164EA9FDD75');
$this->addSql('ALTER TABLE song_history ADD CONSTRAINT FK_2AD16164EA9FDD75 FOREIGN KEY (media_id) REFERENCES station_media (id) ON DELETE SET NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE song_history DROP FOREIGN KEY FK_2AD16164EA9FDD75');
$this->addSql('ALTER TABLE song_history ADD CONSTRAINT FK_2AD16164EA9FDD75 FOREIGN KEY (media_id) REFERENCES station_media (id) ON DELETE CASCADE');
}

View File

@ -16,6 +16,7 @@ use Doctrine\DBAL\Connection;
use NowPlaying\Result\Client;
use Psr\Log\LoggerInterface;
use Symfony\Component\Serializer\Serializer;
use Throwable;
/**
* @extends Repository<Entity\Listener>
@ -188,7 +189,7 @@ class ListenerRepository extends Repository
$record['device_is_bot'] = $browserResult->isBot ? 1 : 0;
$record['device_browser_family'] = $this->truncateNullableString($browserResult->browserFamily, 150);
$record['device_os_family'] = $this->truncateNullableString($browserResult->osFamily, 150);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error('Device Detector error: ' . $e->getMessage(), [
'user_agent' => $userAgent,
'exception' => $e,
@ -211,7 +212,7 @@ class ListenerRepository extends Repository
$record['location_country'] = $this->truncateNullableString($ipInfo->country, 2);
$record['location_lat'] = $ipInfo->lat;
$record['location_lon'] = $ipInfo->lon;
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error('IP Geolocation error: ' . $e->getMessage(), [
'ip' => $ip,
'exception' => $e,

View File

@ -191,9 +191,9 @@ class StationPlaylistMediaRepository extends Repository
)->setParameter('playlist', $playlist)
->execute();
} elseif (Entity\Enums\PlaylistOrders::Shuffle === $playlist->getOrderEnum()) {
$this->em->transactional(
function () use ($playlist): void {
$allSpmRecordsQuery = $this->em->createQuery(
$this->em->wrapInTransaction(
function (ReloadableEntityManagerInterface $em) use ($playlist): void {
$allSpmRecordsQuery = $em->createQuery(
<<<'DQL'
SELECT spm.id
FROM App\Entity\StationPlaylistMedia spm
@ -202,7 +202,7 @@ class StationPlaylistMediaRepository extends Repository
DQL
)->setParameter('playlist', $playlist);
$updateSpmWeightQuery = $this->em->createQuery(
$updateSpmWeightQuery = $em->createQuery(
<<<'DQL'
UPDATE App\Entity\StationPlaylistMedia spm
SET spm.weight=:weight, spm.is_queued=1

View File

@ -166,11 +166,7 @@ class StationRepository extends Repository
}
$customUrl = $this->settingsRepo->readSettings()->getDefaultAlbumArtUrlAsUri();
if (null !== $customUrl) {
return $customUrl;
}
return AssetFactory::createAlbumArt($this->environment)->getUri();
return $customUrl ?? AssetFactory::createAlbumArt($this->environment)->getUri();
}
public function setFallback(

View File

@ -12,6 +12,7 @@ use App\Service\Avatar;
use App\Utilities\Urls;
use Doctrine\ORM\Mapping as ORM;
use GuzzleHttp\Psr7\Uri;
use InvalidArgumentException;
use OpenApi\Attributes as OA;
use Psr\Http\Message\UriInterface;
use RuntimeException;
@ -245,7 +246,7 @@ class Settings implements Stringable
public function setAnalytics(?string $analytics): void
{
if (null !== $analytics && null === Entity\Enums\AnalyticsLevel::tryFrom($analytics)) {
throw new \InvalidArgumentException('Invalid analytics level.');
throw new InvalidArgumentException('Invalid analytics level.');
}
$this->analytics = $analytics;
@ -337,7 +338,7 @@ class Settings implements Stringable
public function setPublicTheme(?string $publicTheme): void
{
if (null !== $publicTheme && null === SupportedThemes::tryFrom($publicTheme)) {
throw new \InvalidArgumentException('Unsupported theme specified.');
throw new InvalidArgumentException('Unsupported theme specified.');
}
$this->public_theme = $publicTheme;

View File

@ -19,10 +19,12 @@ use DateTimeZone;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
use League\Flysystem\UnixVisibility\PortableVisibilityConverter;
use League\Flysystem\Visibility;
use OpenApi\Attributes as OA;
use Psr\Http\Message\UriInterface;
use RuntimeException;
use Stringable;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Path;
@ -456,7 +458,7 @@ class Station implements Stringable, IdentifiableEntityInterface
public function setFrontendType(?string $frontend_type = null): void
{
if (null !== $frontend_type && null === FrontendAdapters::tryFrom($frontend_type)) {
throw new \InvalidArgumentException('Invalid frontend type specified.');
throw new InvalidArgumentException('Invalid frontend type specified.');
}
$this->frontend_type = $frontend_type;
@ -511,7 +513,7 @@ class Station implements Stringable, IdentifiableEntityInterface
public function setBackendType(string $backend_type = null): void
{
if (null !== $backend_type && null === BackendAdapters::tryFrom($backend_type)) {
throw new \InvalidArgumentException('Invalid frontend type specified.');
throw new InvalidArgumentException('Invalid frontend type specified.');
}
$this->backend_type = $backend_type;
@ -962,7 +964,7 @@ class Station implements Stringable, IdentifiableEntityInterface
public function getMediaStorageLocation(): StorageLocation
{
if (null === $this->media_storage_location) {
throw new \RuntimeException('Media storage location not initialized.');
throw new RuntimeException('Media storage location not initialized.');
}
return $this->media_storage_location;
}
@ -970,7 +972,7 @@ class Station implements Stringable, IdentifiableEntityInterface
public function setMediaStorageLocation(?StorageLocation $storageLocation = null): void
{
if (null !== $storageLocation && StorageLocationTypes::StationMedia !== $storageLocation->getTypeEnum()) {
throw new \RuntimeException('Invalid storage location.');
throw new RuntimeException('Invalid storage location.');
}
$this->media_storage_location = $storageLocation;
@ -979,7 +981,7 @@ class Station implements Stringable, IdentifiableEntityInterface
public function getRecordingsStorageLocation(): StorageLocation
{
if (null === $this->recordings_storage_location) {
throw new \RuntimeException('Recordings storage location not initialized.');
throw new RuntimeException('Recordings storage location not initialized.');
}
return $this->recordings_storage_location;
}
@ -987,7 +989,7 @@ class Station implements Stringable, IdentifiableEntityInterface
public function setRecordingsStorageLocation(?StorageLocation $storageLocation = null): void
{
if (null !== $storageLocation && StorageLocationTypes::StationRecordings !== $storageLocation->getTypeEnum()) {
throw new \RuntimeException('Invalid storage location.');
throw new RuntimeException('Invalid storage location.');
}
$this->recordings_storage_location = $storageLocation;
@ -996,7 +998,7 @@ class Station implements Stringable, IdentifiableEntityInterface
public function getPodcastsStorageLocation(): StorageLocation
{
if (null === $this->podcasts_storage_location) {
throw new \RuntimeException('Podcasts storage location not initialized.');
throw new RuntimeException('Podcasts storage location not initialized.');
}
return $this->podcasts_storage_location;
}
@ -1004,7 +1006,7 @@ class Station implements Stringable, IdentifiableEntityInterface
public function setPodcastsStorageLocation(?StorageLocation $storageLocation = null): void
{
if (null !== $storageLocation && StorageLocationTypes::StationPodcasts !== $storageLocation->getTypeEnum()) {
throw new \RuntimeException('Invalid storage location.');
throw new RuntimeException('Invalid storage location.');
}
$this->podcasts_storage_location = $storageLocation;
@ -1016,7 +1018,7 @@ class Station implements Stringable, IdentifiableEntityInterface
StorageLocationTypes::StationMedia => $this->getMediaStorageLocation(),
StorageLocationTypes::StationRecordings => $this->getRecordingsStorageLocation(),
StorageLocationTypes::StationPodcasts => $this->getPodcastsStorageLocation(),
default => throw new \InvalidArgumentException('Invalid storage location.')
default => throw new InvalidArgumentException('Invalid storage location.')
};
}

View File

@ -7,6 +7,7 @@ namespace App\Entity;
use App\Entity\Enums\StationBackendPerformanceModes;
use App\Radio\Enums\StreamFormats;
use Doctrine\Common\Collections\ArrayCollection;
use InvalidArgumentException;
class StationBackendConfiguration extends ArrayCollection
{
@ -80,7 +81,7 @@ class StationBackendConfiguration extends ArrayCollection
}
if (null !== $format && null === StreamFormats::tryFrom($format)) {
throw new \InvalidArgumentException('Invalid recording type specified.');
throw new InvalidArgumentException('Invalid recording type specified.');
}
$this->set(self::RECORD_STREAMS_FORMAT, $format);

View File

@ -13,6 +13,7 @@ use Azura\Normalizer\Attributes\DeepNormalize;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
use OpenApi\Attributes as OA;
use Stringable;
use Symfony\Component\Serializer\Annotation as Serializer;
@ -251,7 +252,7 @@ class StationPlaylist implements
public function setType(string $type): void
{
if (null === PlaylistTypes::tryFrom($type)) {
throw new \InvalidArgumentException('Invalid playlist type.');
throw new InvalidArgumentException('Invalid playlist type.');
}
$this->type = $type;
@ -270,7 +271,7 @@ class StationPlaylist implements
public function setSource(string $source): void
{
if (null === PlaylistSources::tryFrom($source)) {
throw new \InvalidArgumentException('Invalid playlist source.');
throw new InvalidArgumentException('Invalid playlist source.');
}
$this->source = $source;
@ -289,7 +290,7 @@ class StationPlaylist implements
public function setOrder(string $order): void
{
if (null === PlaylistOrders::tryFrom($order)) {
throw new \InvalidArgumentException('Invalid playlist order.');
throw new InvalidArgumentException('Invalid playlist order.');
}
$this->order = $order;
@ -318,7 +319,7 @@ class StationPlaylist implements
public function setRemoteType(?string $remote_type): void
{
if (null !== $remote_type && null === PlaylistRemoteTypes::tryFrom($remote_type)) {
throw new \InvalidArgumentException('Invalid playlist remote type.');
throw new InvalidArgumentException('Invalid playlist remote type.');
}
$this->remote_type = $remote_type;

View File

@ -12,6 +12,7 @@ use App\Radio\Remote\AbstractRemote;
use App\Utilities;
use Doctrine\ORM\Mapping as ORM;
use GuzzleHttp\Psr7\Uri;
use InvalidArgumentException;
use Psr\Http\Message\UriInterface;
use Stringable;
@ -234,7 +235,7 @@ class StationRemote implements
public function setType(string $type): void
{
if (null === RemoteAdapters::tryFrom($type)) {
throw new \InvalidArgumentException('Invalid type specified.');
throw new InvalidArgumentException('Invalid type specified.');
}
$this->type = $type;

View File

@ -222,7 +222,7 @@ class StationSchedule implements IdentifiableEntityInterface
7 => 'Sun',
];
if (null !== $days) {
if ([] !== $days) {
$displayDays = [];
foreach ($days as $day) {
$displayDays[] = $daysOfWeek[$day];

View File

@ -17,7 +17,7 @@ trait HasSongFields
use TruncateStrings;
#[
OA\Property(),
OA\Property,
ORM\Column(length: 50),
Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
]

View File

@ -11,6 +11,7 @@ use App\Http\ServerRequest;
use Gettext\GettextTranslator;
use Gettext\TranslatorFunctions;
use Gettext\TranslatorInterface;
use Locale;
use PhpMyAdmin\MoTranslator\Loader;
use Psr\Http\Message\ServerRequestInterface;
@ -124,7 +125,7 @@ enum SupportedLocales: string
}
$server_params = $request->getServerParams();
$browser_locale = \Locale::acceptFromHttp($server_params['HTTP_ACCEPT_LANGUAGE'] ?? '');
$browser_locale = Locale::acceptFromHttp($server_params['HTTP_ACCEPT_LANGUAGE'] ?? '');
if (!empty($browser_locale)) {
if (2 === strlen($browser_locale)) {

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Event\Radio;
use App\Entity;
use RuntimeException;
use Symfony\Contracts\EventDispatcher\Event;
/**
@ -80,7 +81,7 @@ class AnnotateNextSong extends Event
public function buildAnnotations(): string
{
if (empty($this->songPath)) {
throw new \RuntimeException('No valid path for song.');
throw new RuntimeException('No valid path for song.');
}
$this->annotations = array_filter($this->annotations);

View File

@ -19,6 +19,8 @@ use Symfony\Component\Lock\Exception\LockConflictedException;
use Symfony\Component\Lock\Key;
use Symfony\Component\Lock\PersistingStoreInterface;
use const PHP_INT_MAX;
/**
* Copied from Symfony 5.x as it was deprecated in 6.x with no suitable replacement.
*
@ -38,7 +40,7 @@ final class RetryTillSaveStore implements BlockingStoreInterface, LoggerAwareInt
public function __construct(
private PersistingStoreInterface $decorated,
private int $retrySleep = 100,
private int $retryCount = \PHP_INT_MAX
private int $retryCount = PHP_INT_MAX
) {
$this->logger = new NullLogger();
}
@ -68,12 +70,10 @@ final class RetryTillSaveStore implements BlockingStoreInterface, LoggerAwareInt
}
} while (++$retry < $this->retryCount);
if (null !== $this->logger) {
$this->logger->warning(
'Failed to store the "{resource}" lock. Abort after {retry} retry.',
['resource' => $key, 'retry' => $retry]
);
}
$this->logger?->warning(
'Failed to store the "{resource}" lock. Abort after {retry} retry.',
['resource' => $key, 'retry' => $retry]
);
throw new LockConflictedException();
}

View File

@ -14,7 +14,7 @@ class MimeTypeExtensionMap extends GeneratedExtensionToMimeTypeMap
public function lookupMimeType(string $extension): ?string
{
return self::MIME_TYPES_FOR_EXTENSIONS[$extension]
return parent::lookupMimeType($extension)
?? self::ADDED_MIME_TYPES[$extension]
?? null;
}

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace App\Message;
use App\Entity\Api\NowPlaying\NowPlaying;
use App\MessageQueue\QueueManager;
use App\MessageQueue\QueueManagerInterface;
class DispatchWebhookMessage extends AbstractUniqueMessage

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace App\Message;
use App\Environment;
use App\MessageQueue\QueueManagerInterface;
class TestWebhookMessage extends AbstractUniqueMessage
{
@ -23,9 +22,4 @@ class TestWebhookMessage extends AbstractUniqueMessage
{
return Environment::getInstance()->getSyncLongExecutionTime();
}
public function getQueue(): string
{
return QueueManagerInterface::QUEUE_NORMAL_PRIORITY;
}
}

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace App;
use App\Http\Response;
use App\Http\Router;
use App\Http\RouterInterface;
use App\Http\ServerRequest;
use Countable;
@ -179,23 +178,21 @@ class Paginator implements IteratorAggregate, Countable
}
$pageLinks = [];
if ($this->router instanceof Router) {
$pageLinks['first'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => 1]);
$pageLinks['first'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => 1]);
$prevPage = $this->paginator->hasPreviousPage()
? $this->paginator->getPreviousPage()
: 1;
$prevPage = $this->paginator->hasPreviousPage()
? $this->paginator->getPreviousPage()
: 1;
$pageLinks['previous'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => $prevPage]);
$pageLinks['previous'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => $prevPage]);
$nextPage = $this->paginator->hasNextPage()
? $this->paginator->getNextPage()
: $this->paginator->getNbPages();
$nextPage = $this->paginator->hasNextPage()
? $this->paginator->getNextPage()
: $this->paginator->getNbPages();
$pageLinks['next'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => $nextPage]);
$pageLinks['next'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => $nextPage]);
$pageLinks['last'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => $totalPages]);
}
$pageLinks['last'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => $totalPages]);
return $response->withJson(
[

View File

@ -15,7 +15,6 @@ use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use Supervisor\Exception\Fault;
use Supervisor\Exception\SupervisorException as SupervisorLibException;
use Supervisor\Process;
use Supervisor\SupervisorInterface;
abstract class AbstractAdapter
@ -106,9 +105,7 @@ abstract class AbstractAdapter
$program_name = $this->getProgramName($station);
try {
$process = $this->supervisor->getProcess($program_name);
return $process instanceof Process && $process->isRunning();
return $this->supervisor->getProcess($program_name)->isRunning();
} catch (Fault\BadNameException) {
return false;
}

View File

@ -10,6 +10,7 @@ use App\Radio\Adapters;
use Doctrine\ORM\EntityManagerInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class Annotations implements EventSubscriberInterface
@ -52,7 +53,7 @@ class Annotations implements EventSubscriberInterface
$queueRow = $this->queueRepo->getNextToSendToAutoDj($station);
if (null === $queueRow) {
throw new \RuntimeException('Queue is empty for station.');
throw new RuntimeException('Queue is empty for station.');
}
$event = AnnotateNextSong::fromStationQueue($queueRow, $asAutoDj);

View File

@ -8,6 +8,7 @@ use App\Entity;
use App\Event\Radio\WriteLiquidsoapConfiguration;
use App\Exception;
use App\Radio\Enums\LiquidsoapQueues;
use LogicException;
use Psr\Http\Message\UriInterface;
use Symfony\Component\Process\Process;
@ -329,7 +330,7 @@ class Liquidsoap extends AbstractBackend
$process->run();
if (1 === $process->getExitCode()) {
throw new \LogicException($process->getOutput());
throw new LogicException($process->getOutput());
}
}
}

View File

@ -7,6 +7,8 @@ namespace App\Radio\Backend\Liquidsoap\Command;
use App\Entity;
use App\Radio\Enums\BackendAdapters;
use Monolog\Logger;
use ReflectionClass;
use Throwable;
abstract class AbstractCommand
{
@ -30,7 +32,7 @@ abstract class AbstractCommand
}
);
$className = (new \ReflectionClass(static::class))->getShortName();
$className = (new ReflectionClass(static::class))->getShortName();
$this->logger->debug(
sprintf('Running Internal Command %s', $className),
[
@ -54,7 +56,7 @@ abstract class AbstractCommand
} else {
return (string)$result;
}
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error(
sprintf(
'Error with Internal Command %s: %s',

View File

@ -6,13 +6,14 @@ namespace App\Radio\Backend\Liquidsoap\Command;
use App\Entity;
use App\Flysystem\StationFilesystems;
use RuntimeException;
class CopyCommand extends AbstractCommand
{
protected function doRun(Entity\Station $station, bool $asAutoDj = false, array $payload = []): string
{
if (empty($payload['uri'])) {
throw new \RuntimeException('No URI provided.');
throw new RuntimeException('No URI provided.');
}
$uri = $payload['uri'];

View File

@ -6,6 +6,7 @@ namespace App\Radio\Backend\Liquidsoap\Command;
use App\Entity;
use Monolog\Logger;
use RuntimeException;
class DjAuthCommand extends AbstractCommand
{
@ -22,7 +23,7 @@ class DjAuthCommand extends AbstractCommand
array $payload = []
): bool {
if (!$station->getEnableStreamers()) {
throw new \RuntimeException('Attempted DJ authentication when streamers are disabled on this station.');
throw new RuntimeException('Attempted DJ authentication when streamers are disabled on this station.');
}
$user = $payload['user'] ?? '';

View File

@ -8,6 +8,7 @@ use App\Entity;
use Doctrine\ORM\EntityManagerInterface;
use Monolog\Logger;
use Psr\SimpleCache\CacheInterface;
use RuntimeException;
class FeedbackCommand extends AbstractCommand
{
@ -24,12 +25,12 @@ class FeedbackCommand extends AbstractCommand
{
// Process extra metadata sent by Liquidsoap (if it exists).
if (empty($payload['media_id'])) {
throw new \RuntimeException('No payload provided.');
throw new RuntimeException('No payload provided.');
}
$media = $this->em->find(Entity\StationMedia::class, $payload['media_id']);
if (!$media instanceof Entity\StationMedia) {
throw new \RuntimeException('Media ID does not exist for station.');
throw new RuntimeException('Media ID does not exist for station.');
}
$sq = $this->queueRepo->findRecentlyCuedSong($station, $media);

View File

@ -116,7 +116,7 @@ class ConfigWriter implements EventSubscriberInterface
$event->appendBlock(
<<<EOF
init.daemon.set(false)
init.daemon.pidfile.path.set("${pidfile}")
init.daemon.pidfile.path.set("{$pidfile}")
log.stdout.set(true)
log.file.set(false)
@ -125,14 +125,14 @@ class ConfigWriter implements EventSubscriberInterface
settings.server.socket.set(true)
settings.server.socket.permissions.set(0o660)
settings.server.socket.path.set("${socketFile}")
settings.server.socket.path.set("{$socketFile}")
settings.harbor.bind_addrs.set(["0.0.0.0"])
settings.tag.encodings.set(["UTF-8","ISO-8859-1"])
settings.encoder.metadata.export.set(["artist","title","album","song"])
setenv("TZ", "${stationTz}")
setenv("TZ", "{$stationTz}")
autodj_is_loading = ref(true)
ignore(autodj_is_loading)
@ -154,8 +154,8 @@ class ConfigWriter implements EventSubscriberInterface
$event->appendBlock(
<<<EOF
azuracast_api_url = "${stationApiUrl}"
azuracast_api_key = "${stationApiAuth}"
azuracast_api_url = "{$stationApiUrl}"
azuracast_api_key = "{$stationApiAuth}"
def azuracast_api_call(~timeout_ms=2000, url, payload) =
full_url = "#{azuracast_api_url}/#{url}"
@ -189,7 +189,7 @@ class ConfigWriter implements EventSubscriberInterface
$event->appendBlock(
<<<EOF
station_media_dir = "${stationMediaDir}"
station_media_dir = "{$stationMediaDir}"
def azuracast_media_protocol(~rlog=_,~maxtime=_,arg) =
["#{station_media_dir}/#{arg}"]
end
@ -240,7 +240,7 @@ class ConfigWriter implements EventSubscriberInterface
<<<EOF
# Optimize Performance
runtime.gc.set(runtime.gc.get().{
space_overhead = ${gcSpaceOverhead},
space_overhead = {$gcSpaceOverhead},
allocation_policy = 2
})
EOF
@ -552,12 +552,12 @@ class ConfigWriter implements EventSubscriberInterface
$event->appendBlock(
<<< EOF
requests = request.queue(id="${requestsQueueName}")
requests = cue_cut(id="cue_${requestsQueueName}", requests)
requests = request.queue(id="{$requestsQueueName}")
requests = cue_cut(id="cue_{$requestsQueueName}", requests)
radio = fallback(id="requests_fallback", track_sensitive = true, [requests, radio])
interrupting_queue = request.queue(id="${interruptingQueueName}")
interrupting_queue = cue_cut(id="cue_${interruptingQueueName}", interrupting_queue)
interrupting_queue = request.queue(id="{$interruptingQueueName}")
interrupting_queue = cue_cut(id="cue_{$interruptingQueueName}", interrupting_queue)
radio = fallback(id="interrupting_fallback", track_sensitive = false, [interrupting_queue, radio])
add_skip_command(radio)
@ -800,7 +800,7 @@ class ConfigWriter implements EventSubscriberInterface
ignore(radio_without_live)
# Live Broadcasting
live = input.harbor(${harborParams})
live = input.harbor({$harborParams})
def insert_missing(m) =
if m == [] then
@ -827,14 +827,14 @@ class ConfigWriter implements EventSubscriberInterface
$event->appendBlock(
<<< EOF
# Record Live Broadcasts
recording_base_path = "${recordBasePath}"
recording_extension = "${recordExtension}"
recording_base_path = "{$recordBasePath}"
recording_extension = "{$recordExtension}"
output.file(
{$formatString},
fun () -> begin
if (!live_enabled) then
"#{recording_base_path}/#{!live_dj}/${recordPathPrefix}_%Y%m%d-%H%M%S.#{recording_extension}.tmp"
"#{recording_base_path}/#{!live_dj}/{$recordPathPrefix}_%Y%m%d-%H%M%S.#{recording_extension}.tmp"
else
""
end
@ -897,7 +897,7 @@ class ConfigWriter implements EventSubscriberInterface
$event->appendBlock(
<<<EOF
radio = fallback(id="safe_fallback", track_sensitive = false, [radio, single(id="error_jingle", "${errorFile}")])
radio = fallback(id="safe_fallback", track_sensitive = false, [radio, single(id="error_jingle", "{$errorFile}")])
EOF
);

View File

@ -17,6 +17,7 @@ use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Filesystem\Filesystem;
use Throwable;
class PlaylistFileWriter implements EventSubscriberInterface
{
@ -136,7 +137,7 @@ class PlaylistFileWriter implements EventSubscriberInterface
try {
$this->eventDispatcher->dispatch($event);
$playlistFile[] = $event->buildAnnotations();
} catch (\Throwable $e) {
} catch (Throwable $e) {
}
}

View File

@ -14,6 +14,7 @@ use App\Radio\Enums\BackendAdapters;
use App\Radio\Enums\FrontendAdapters;
use Doctrine\ORM\EntityManagerInterface;
use Monolog\Logger;
use RuntimeException;
use Supervisor\Exception\SupervisorException;
use Supervisor\SupervisorInterface;
@ -104,7 +105,7 @@ class Configuration
if (!$station->getIsEnabled()) {
$this->unlinkAndStopStation($station, $reloadSupervisor);
throw new \RuntimeException('Station is disabled.');
throw new RuntimeException('Station is disabled.');
}
$frontend = $this->adapters->getFrontendAdapter($station);
@ -113,7 +114,7 @@ class Configuration
// If no processes need to be managed, remove any existing config.
if (!$frontend->hasCommand($station) && !$backend->hasCommand($station)) {
$this->unlinkAndStopStation($station, $reloadSupervisor);
throw new \RuntimeException('Station has no local services.');
throw new RuntimeException('Station has no local services.');
}
// If using AutoDJ and there is no media, don't spin up services.
@ -122,7 +123,7 @@ class Configuration
&& !$this->stationPlaylistRepo->stationHasActivePlaylists($station)
) {
$this->unlinkAndStopStation($station, $reloadSupervisor);
throw new \RuntimeException('Station has no media assigned to playlists.');
throw new RuntimeException('Station has no media assigned to playlists.');
}
// Get group information
@ -174,8 +175,8 @@ class Configuration
$backend->reload($station);
$frontend->reload($station);
} else {
$this->supervisor->stopProcessGroup($backend_group, true);
$this->supervisor->startProcessGroup($backend_group, true);
$this->supervisor->stopProcessGroup($backend_group);
$this->supervisor->startProcessGroup($backend_group);
}
} catch (SupervisorException) {
}
@ -483,7 +484,7 @@ class Configuration
// Try forcing the group to stop, but don't hard-fail if it doesn't.
try {
$this->supervisor->stopProcessGroup($station_group, true);
$this->supervisor->stopProcessGroup($station_group);
$this->supervisor->removeProcessGroup($station_group);
} catch (SupervisorException) {
}

View File

@ -7,6 +7,7 @@ namespace App\Radio\Frontend\Blocklist;
use App\Entity;
use App\Radio\Enums\FrontendAdapters;
use App\Service\IpGeolocation;
use InvalidArgumentException;
use PhpIP\IP;
use PhpIP\IPBlock;
@ -84,7 +85,7 @@ class BlocklistParser
}
}
}
} catch (\InvalidArgumentException) {
} catch (InvalidArgumentException) {
}
}

View File

@ -70,7 +70,7 @@ class RateLimit
$rateLimiterFactory = new RateLimiterFactory($config, $cacheStore, $this->lockFactory);
$rateLimiter = $rateLimiterFactory->create($key);
if (false === $rateLimiter->consume(1)->isAccepted()) {
if (false === $rateLimiter->consume()->isAccepted()) {
throw new Exception\RateLimitExceededException();
}
}

View File

@ -65,13 +65,13 @@ class Flow
return self::handleStandardUpload($request, $tempDir);
}
$flowIdentifier = $params['flowIdentifier'] ?? '';
$flowIdentifier = $params['flowIdentifier'];
$flowChunkNumber = (int)($params['flowChunkNumber'] ?? 1);
$targetSize = (int)($params['flowTotalSize'] ?? 0);
$targetChunks = (int)($params['flowTotalChunks'] ?? 1);
$targetChunks = (int)($params['flowTotalChunks']);
$flowFilename = $params['flowFilename'] ?? ($flowIdentifier ?: ('upload-' . date('Ymd')));
$flowFilename = $params['flowFilename'] ?? ($flowIdentifier);
// init the destination file (format <filename.ext>.part<#chunk>
$chunkBaseDir = $tempDir . '/' . $flowIdentifier;

View File

@ -8,6 +8,7 @@ use App\Service\IpGeolocator;
use Exception;
use MaxMind\Db\Reader;
use Psr\Cache\CacheItemPoolInterface;
use RuntimeException;
use Symfony\Component\Cache\Adapter\ProxyAdapter;
use Symfony\Component\Cache\CacheItem;
use Symfony\Contracts\Cache\CacheInterface;
@ -76,7 +77,7 @@ class IpGeolocation
$reader = $this->reader;
if (null === $reader) {
throw new \RuntimeException('No IP Geolocation reader available.');
throw new RuntimeException('No IP Geolocation reader available.');
}
$cacheKey = $this->readerShortName . '_' . str_replace([':', '.'], '_', $ip);

View File

@ -74,7 +74,7 @@ class CheckMediaTask extends AbstractTask
$this->logger->info(
sprintf(
'Processing media for storage location %s...',
(string)$storageLocation
$storageLocation
)
);
@ -111,7 +111,7 @@ class CheckMediaTask extends AbstractTask
);
} catch (FilesystemException $e) {
$this->logger->error(
sprintf('Flysystem Error for Storage Space %s', (string)$storageLocation),
sprintf('Flysystem Error for Storage Space %s', $storageLocation),
[
'exception' => $e,
]
@ -171,7 +171,7 @@ class CheckMediaTask extends AbstractTask
$this->processNewFiles($storageLocation, $queuedNewFiles, $musicFiles, $stats);
$this->logger->debug(sprintf('Media processed for "%s".', (string)$storageLocation), $stats);
$this->logger->debug(sprintf('Media processed for "%s".', $storageLocation), $stats);
}
protected function processExistingMediaRows(
@ -221,7 +221,7 @@ class CheckMediaTask extends AbstractTask
} else {
$media = $this->em->find(Entity\StationMedia::class, $mediaRow['id']);
if ($media instanceof Entity\StationMedia) {
$this->mediaRepo->remove($media, false);
$this->mediaRepo->remove($media);
}
$stats['deleted']++;

View File

@ -8,6 +8,7 @@ use App\Entity;
use Exception;
use League\Flysystem\StorageAttributes;
use Symfony\Component\Finder\Finder;
use Throwable;
class CleanupStorageTask extends AbstractTask
{
@ -22,7 +23,7 @@ class CleanupStorageTask extends AbstractTask
try {
/** @var Entity\Station $station */
$this->cleanStationTempFiles($station);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error($e->getMessage(), [
'station' => (string)$station,
]);
@ -34,7 +35,7 @@ class CleanupStorageTask extends AbstractTask
try {
/** @var Entity\StorageLocation $storageLocation */
$this->cleanMediaStorageLocation($storageLocation);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error($e->getMessage(), [
'storageLocation' => (string)$storageLocation,
]);
@ -80,7 +81,7 @@ class CleanupStorageTask extends AbstractTask
if (0 === count($allUniqueIds)) {
$this->logger->notice(
sprintf('Skipping storage location %s: no media found.', (string)$storageLocation)
sprintf('Skipping storage location %s: no media found.', $storageLocation)
);
return;
}

View File

@ -8,6 +8,7 @@ use App\Doctrine\ReloadableEntityManagerInterface;
use App\Entity;
use Psr\Log\LoggerInterface;
use Symfony\Component\Finder\Finder;
use Throwable;
class MoveBroadcastsTask extends AbstractTask
{
@ -35,7 +36,7 @@ class MoveBroadcastsTask extends AbstractTask
try {
/** @var Entity\StorageLocation $storageLocation */
$this->processForStorageLocation($storageLocation);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error($e->getMessage(), [
'storageLocation' => (string)$storageLocation,
]);

View File

@ -12,6 +12,7 @@ use League\Flysystem\StorageAttributes;
use Psr\Log\LoggerInterface;
use Supervisor\SupervisorInterface;
use Symfony\Component\Finder\Finder;
use Throwable;
class RotateLogsTask extends AbstractTask
{
@ -43,7 +44,7 @@ class RotateLogsTask extends AbstractTask
try {
$this->rotateStationLogs($station);
} catch (\Throwable $e) {
} catch (Throwable $e) {
$this->logger->error($e->getMessage(), [
'station' => (string)$station,
]);

View File

@ -8,6 +8,7 @@ declare(strict_types=1);
namespace App\Tests;
use App\AppFactory;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Enums\ApplicationEnvironment;
use App\Environment;
@ -38,16 +39,10 @@ class Module extends Framework implements DoctrineProvider
public function _initialize(): void
{
/** @var string $container_class The fully qualified name of the container class. */
$container_class = $this->config['container'];
$autoloader = $GLOBALS['autoloader'];
$this->app = $container_class::createApp(
$autoloader,
$this->app = AppFactory::createApp(
[
Environment::BASE_DIR => Configuration::projectDir(),
Environment::APP_ENV => ApplicationEnvironment::Testing->value,
Environment::APP_ENV => ApplicationEnvironment::Testing->value,
]
);

View File

@ -8,8 +8,11 @@ declare(strict_types=1);
namespace App\Xml;
use RuntimeException;
use XMLReader;
use const LIBXML_XINCLUDE;
/**
* XML config reader.
*/
@ -32,14 +35,14 @@ class Reader
}
/** @var XMLReader|false $reader */
$reader = XMLReader::XML($string, null, \LIBXML_XINCLUDE);
$reader = XMLReader::XML($string, null, LIBXML_XINCLUDE);
if (false === $reader) {
return false;
}
set_error_handler(
function ($error, $message = '') {
throw new \RuntimeException(
throw new RuntimeException(
sprintf('Error reading XML string: %s', $message),
$error
);

View File

@ -8,6 +8,7 @@ declare(strict_types=1);
namespace App\Xml;
use RuntimeException;
use XMLWriter;
class Writer
@ -71,7 +72,7 @@ class Writer
$branchType = 'string';
}
} elseif ($branchType !== (is_numeric($key) ? 'numeric' : 'string')) {
throw new \RuntimeException('Mixing of string and numeric keys is not allowed');
throw new RuntimeException('Mixing of string and numeric keys is not allowed');
}
if ($branchType === 'numeric') {

View File

@ -2,8 +2,7 @@ actor: FunctionalTester
suite_namespace: \Functional
modules:
enabled:
- \App\Tests\Module:
container: \App\AppFactory
- \App\Tests\Module
- Doctrine2:
depends: \App\Tests\Module
- REST:

View File

@ -2,7 +2,6 @@ actor: UnitTester
suite_namespace: \Unit
modules:
enabled:
- \App\Tests\Module:
container: \App\AppFactory
- \App\Tests\Module
error_level: "E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED"

View File

@ -5,12 +5,8 @@ $autoloader->addClassMap([
'Functional\CestAbstract' => __DIR__ . '/Functional/CestAbstract.php',
]);
\Doctrine\Common\Annotations\AnnotationRegistry::registerLoader([$autoloader, 'loadClass']);
$GLOBALS['autoloader'] = $autoloader;
if (!function_exists('__')) {
\PhpMyAdmin\MoTranslator\Loader::loadFunctions();
PhpMyAdmin\MoTranslator\Loader::loadFunctions();
}
// Clear output directory

View File

@ -6,14 +6,13 @@
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
ini_set('display_errors', 1);
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
require dirname(__DIR__) . '/vendor/autoload.php';
const AZURACAST_VERSION = App\Version::FALLBACK_VERSION;
const AZURACAST_API_URL = 'https://localhost/api';
const AZURACAST_API_NAME = 'Testing API';
App\AppFactory::createCli(
$autoloader,
[
App\Environment::BASE_DIR => dirname(__DIR__),
]

View File

@ -6,9 +6,9 @@ use App\Environment;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LogLevel;
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
require dirname(__DIR__) . '/vendor/autoload.php';
$di = App\AppFactory::buildContainer($autoloader,
$di = App\AppFactory::buildContainer(
[
App\Environment::BASE_DIR => dirname(__DIR__),
App\Environment::LOG_LEVEL => LogLevel::DEBUG,

View File

@ -5,10 +5,9 @@ declare(strict_types=1);
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
ini_set('display_errors', '1');
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
require dirname(__DIR__) . '/vendor/autoload.php';
$app = App\AppFactory::createApp(
$autoloader,
[
App\Environment::BASE_DIR => dirname(__DIR__),
]