Stop using a singleton for Config (#298)

This commit is contained in:
Pierre Rudloff 2020-10-17 22:07:07 +02:00
parent 6fc294afbe
commit 7e2afd8221
14 changed files with 87 additions and 169 deletions

View file

@ -20,12 +20,6 @@ use Jawira\CaseConverter\Convert;
*/
class Config
{
/**
* Singleton instance.
*
* @var Config|null
*/
private static $instance;
/**
* youtube-dl binary path.
@ -160,10 +154,11 @@ class Config
* @param mixed[] $options Options
* @throws ConfigException
*/
private function __construct(array $options = [])
public function __construct(array $options = [])
{
$this->applyOptions($options);
$this->getEnv();
$this->validateOptions();
$localeManager = LocaleManager::getInstance();
if (empty($this->genericFormats)) {
@ -271,34 +266,17 @@ class Config
}
}
/**
* Get Config singleton instance.
*
* @return Config
* @todo Stop using a singleton.
*/
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Set options from a YAML file.
*
* @param string $file Path to the YAML file
* @return void
* @return Config
* @throws ConfigException
*/
public static function setFile(string $file)
public static function fromFile(string $file)
{
if (is_file($file)) {
$options = Yaml::parse(strval(file_get_contents($file)));
self::$instance = new self($options);
self::$instance->validateOptions();
return new self(Yaml::parse(strval(file_get_contents($file))));
} else {
throw new ConfigException("Can't find config file at " . $file);
}
@ -308,29 +286,13 @@ class Config
* Manually set some options.
*
* @param mixed[] $options Options (see `config/config.example.yml` for available options)
* @param bool $update True to update an existing instance
* @return void
* @throws ConfigException
*/
public static function setOptions(array $options, $update = true)
public function setOptions(array $options)
{
if ($update) {
$config = self::getInstance();
$config->applyOptions($options);
$config->validateOptions();
} else {
self::$instance = new self($options);
}
}
/**
* Destroy singleton instance.
*
* @return void
*/
public static function destroyInstance()
{
self::$instance = null;
$this->applyOptions($options);
$this->validateOptions();
}
/**

View file

@ -19,10 +19,10 @@ class ConfigFactory
{
$configPath = __DIR__ . '/../config/config.yml';
if (is_file($configPath)) {
Config::setFile($configPath);
$config = Config::fromFile($configPath);
} else {
$config = new Config();
}
$config = Config::getInstance();
if ($config->uglyUrls) {
$container['router'] = new UglyRouter();
}

View file

@ -27,22 +27,12 @@ abstract class BaseTest extends TestCase
/**
* Prepare tests.
* @throws ConfigException
*/
protected function setUp(): void
{
Config::setFile($this->getConfigFile());
$this->checkRequirements();
}
/**
* Destroy properties after test.
*/
protected function tearDown(): void
{
Config::destroyInstance();
}
/**
* Check tests requirements.
* @return void

View file

@ -14,23 +14,6 @@ use Alltube\Exception\ConfigException;
*/
class ConfigTest extends BaseTest
{
/**
* Config class instance.
*
* @var Config
*/
private $config;
/**
* Prepare tests.
* @throws ConfigException
*/
protected function setUp(): void
{
parent::setUp();
$this->config = Config::getInstance();
}
/**
* Test the getInstance function.
@ -39,21 +22,7 @@ class ConfigTest extends BaseTest
*/
public function testGetInstance()
{
$config = Config::getInstance();
$this->assertEquals(false, $config->convert);
$this->assertConfig($config);
}
/**
* Test the getInstance function.
*
* @return void
*/
public function testGetInstanceFromScratch()
{
Config::destroyInstance();
$config = Config::getInstance();
$config = new Config();
$this->assertEquals(false, $config->convert);
$this->assertConfig($config);
}
@ -88,8 +57,8 @@ class ConfigTest extends BaseTest
*/
public function testSetFile()
{
Config::setFile($this->getConfigFile());
$this->assertConfig($this->config);
$config = Config::fromFile($this->getConfigFile());
$this->assertConfig($config);
}
/**
@ -100,7 +69,7 @@ class ConfigTest extends BaseTest
public function testSetFileWithMissingFile()
{
$this->expectException(ConfigException::class);
Config::setFile('foo');
Config::fromFile('foo');
}
/**
@ -111,21 +80,8 @@ class ConfigTest extends BaseTest
*/
public function testSetOptions()
{
Config::setOptions(['appName' => 'foo']);
$config = Config::getInstance();
$this->assertEquals('foo', $config->appName);
}
/**
* Test the setOptions function.
*
* @return void
* @throws ConfigException
*/
public function testSetOptionsWithoutUpdate()
{
Config::setOptions(['appName' => 'foo'], false);
$config = Config::getInstance();
$config = new Config();
$config->setOptions(['appName' => 'foo']);
$this->assertEquals('foo', $config->appName);
}
@ -137,7 +93,8 @@ class ConfigTest extends BaseTest
public function testSetOptionsWithBadYoutubedl()
{
$this->expectException(ConfigException::class);
Config::setOptions(['youtubedl' => 'foo']);
$config = new Config();
$config->setOptions(['youtubedl' => 'foo']);
}
/**
@ -148,7 +105,8 @@ class ConfigTest extends BaseTest
public function testSetOptionsWithBadPython()
{
$this->expectException(ConfigException::class);
Config::setOptions(['python' => 'foo']);
$config = new Config();
$config->setOptions(['python' => 'foo']);
}
/**
@ -159,10 +117,8 @@ class ConfigTest extends BaseTest
*/
public function testGetInstanceWithEnv()
{
Config::destroyInstance();
putenv('CONVERT=1');
Config::setFile($this->getConfigFile());
$config = Config::getInstance();
$config = Config::fromFile($this->getConfigFile());
$this->assertEquals(true, $config->convert);
putenv('CONVERT');
}

View file

@ -65,7 +65,7 @@ abstract class ControllerTest extends BaseTest
$this->container = new Container();
$this->request = Request::createFromEnvironment(Environment::mock());
$this->response = new Response();
$this->container['config'] = Config::getInstance();
$this->container['config'] = Config::fromFile($this->getConfigFile());
$this->container['locale'] = LocaleManagerFactory::create();
$this->container['view'] = ViewFactory::create($this->container, $this->request);
$this->container['logger'] = new NullLogger();

View file

@ -6,7 +6,6 @@
namespace Alltube\Test;
use Alltube\Config;
use Alltube\Exception\ConfigException;
use Alltube\Stream\ConvertedPlaylistArchiveStream;
@ -24,10 +23,10 @@ class ConvertedPlaylistArchiveStreamTest extends StreamTest
{
parent::setUp();
$config = Config::getInstance();
$downloader = $config->getDownloader();
$video = $downloader->getVideo('https://www.youtube.com/playlist?list=PL1j4Ff8cAqPu5iowaeUAY8lRgkfT4RybJ');
$video = $this->downloader->getVideo(
'https://www.youtube.com/playlist?list=PL1j4Ff8cAqPu5iowaeUAY8lRgkfT4RybJ'
);
$this->stream = new ConvertedPlaylistArchiveStream($downloader, $video);
$this->stream = new ConvertedPlaylistArchiveStream($this->downloader, $video);
}
}

View file

@ -6,7 +6,6 @@
namespace Alltube\Test;
use Alltube\Config;
use Alltube\Controller\DownloadController;
use Alltube\Exception\ConfigException;
use Alltube\Exception\DependencyException;
@ -69,11 +68,11 @@ class DownloadControllerTest extends ControllerTest
* Test the download() function with streams enabled.
*
* @return void
* @throws ConfigException
*/
public function testDownloadWithStream()
{
Config::setOptions(['stream' => true]);
$config = $this->container->get('config');
$config->setOptions(['stream' => true]);
$this->assertRequestIsOk(
'download',
@ -85,11 +84,11 @@ class DownloadControllerTest extends ControllerTest
* Test the download() function with an M3U stream.
*
* @return void
* @throws ConfigException
*/
public function testDownloadWithM3uStream()
{
Config::setOptions(['stream' => true]);
$config = $this->container->get('config');
$config->setOptions(['stream' => true]);
$this->assertRequestIsOk(
'download',
@ -105,13 +104,13 @@ class DownloadControllerTest extends ControllerTest
* Test the download() function with an RTMP stream.
*
* @return void
* @throws ConfigException
*/
public function testDownloadWithRtmpStream()
{
$this->markTestIncomplete('We need to find another RTMP video.');
Config::setOptions(['stream' => true]);
$config = $this->container->get('config');
$config->setOptions(['stream' => true]);
$this->assertRequestIsOk(
'download',
@ -123,11 +122,11 @@ class DownloadControllerTest extends ControllerTest
* Test the download() function with a remuxed video.
*
* @return void
* @throws ConfigException
*/
public function testDownloadWithRemux()
{
Config::setOptions(['remux' => true]);
$config = $this->container->get('config');
$config->setOptions(['remux' => true]);
$this->assertRequestIsOk(
'download',
@ -196,11 +195,11 @@ class DownloadControllerTest extends ControllerTest
*
* @return void
* @requires OS Linux
* @throws ConfigException
*/
public function testDownloadWithPlaylist()
{
Config::setOptions(['stream' => true]);
$config = $this->container->get('config');
$config->setOptions(['stream' => true]);
$this->assertRequestIsOk(
'download',
@ -212,11 +211,11 @@ class DownloadControllerTest extends ControllerTest
* Test the download() function with an advanced conversion.
*
* @return void
* @throws ConfigException
*/
public function testDownloadWithAdvancedConversion()
{
Config::setOptions(['convertAdvanced' => true]);
$config = $this->container->get('config');
$config->setOptions(['convertAdvanced' => true]);
$this->assertRequestIsOk(
'download',

View file

@ -6,7 +6,6 @@
namespace Alltube\Test;
use Alltube\Config;
use Alltube\Controller\FrontController;
use Alltube\Exception\ConfigException;
use Alltube\Exception\DependencyException;
@ -52,11 +51,11 @@ class FrontControllerTest extends ControllerTest
* Test the constructor with streams enabled.
*
* @return void
* @throws ConfigException
*/
public function testConstructorWithStream()
{
Config::setOptions(['stream' => true]);
$config = $this->container->get('config');
$config->setOptions(['stream' => true]);
$this->assertInstanceOf(FrontController::class, new FrontController($this->container));
}
@ -132,11 +131,11 @@ class FrontControllerTest extends ControllerTest
*
* @return void
* @requires download
* @throws ConfigException
*/
public function testInfoWithAudio()
{
Config::setOptions(['convert' => true]);
$config = $this->container->get('config');
$config->setOptions(['convert' => true]);
$this->assertRequestIsRedirect(
'info',
@ -149,11 +148,11 @@ class FrontControllerTest extends ControllerTest
*
* @return void
* @requires download
* @throws ConfigException
*/
public function testInfoWithVimeoAudio()
{
Config::setOptions(['convert' => true]);
$config = $this->container->get('config');
$config->setOptions(['convert' => true]);
// So we can test the fallback to default format
$this->assertRequestIsRedirect('info', ['url' => 'https://vimeo.com/251997032', 'audio' => true]);
@ -164,11 +163,11 @@ class FrontControllerTest extends ControllerTest
*
* @return void
* @requires download
* @throws ConfigException
*/
public function testInfoWithUnconvertedAudio()
{
Config::setOptions(['convert' => true]);
$config = $this->container->get('config');
$config->setOptions(['convert' => true]);
$this->assertRequestIsRedirect(
'info',
@ -213,11 +212,11 @@ class FrontControllerTest extends ControllerTest
*
* @return void
* @requires download
* @throws ConfigException
*/
public function testInfoWithStream()
{
Config::setOptions(['stream' => true]);
$config = $this->container->get('config');
$config->setOptions(['stream' => true]);
$this->assertRequestIsOk('info', ['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU']);
$this->assertRequestIsOk(

View file

@ -6,7 +6,6 @@
namespace Alltube\Test;
use Alltube\Config;
use Alltube\Exception\ConfigException;
use Alltube\Stream\PlaylistArchiveStream;
@ -24,10 +23,10 @@ class PlaylistArchiveStreamTest extends StreamTest
{
parent::setUp();
$config = Config::getInstance();
$downloader = $config->getDownloader();
$video = $downloader->getVideo('https://www.youtube.com/playlist?list=PL1j4Ff8cAqPu5iowaeUAY8lRgkfT4RybJ');
$video = $this->downloader->getVideo(
'https://www.youtube.com/playlist?list=PL1j4Ff8cAqPu5iowaeUAY8lRgkfT4RybJ'
);
$this->stream = new PlaylistArchiveStream($downloader, $video);
$this->stream = new PlaylistArchiveStream($this->downloader, $video);
}
}

View file

@ -6,6 +6,9 @@
namespace Alltube\Test;
use Alltube\Config;
use Alltube\Exception\ConfigException;
use Alltube\Library\Downloader;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
@ -20,6 +23,25 @@ abstract class StreamTest extends BaseTest
*/
protected $stream;
/**
* Downloader class instance.
* @var Downloader
*/
protected $downloader;
/**
* Prepare tests.
* @throws ConfigException
*/
protected function setUp(): void
{
parent::setUp();
// So ffmpeg does not spam the output with broken pipe errors.
$config = new Config(['ffmpegVerbosity' => 'fatal']);
$this->downloader = $config->getDownloader();
}
/**
* Clean variables used in tests.
*

View file

@ -7,7 +7,6 @@
namespace Alltube\Test;
use Alltube\Config;
use Alltube\Exception\ConfigException;
use Alltube\Library\Downloader;
use Alltube\Library\Exception\AlltubeLibraryException;
use Alltube\Library\Exception\PopenStreamException;
@ -39,7 +38,6 @@ class VideoStubsTest extends BaseTest
/**
* Initialize properties used by test.
* @throws ConfigException
*/
protected function setUp(): void
{
@ -48,7 +46,7 @@ class VideoStubsTest extends BaseTest
PHPMockery::mock('Alltube\Library', 'popen');
PHPMockery::mock('Alltube\Library', 'fopen');
$config = Config::getInstance();
$config = new Config();
$this->downloader = $config->getDownloader();
$this->video = $this->downloader->getVideo('https://www.youtube.com/watch?v=XJC9_JkzugE');
}

View file

@ -48,7 +48,8 @@ class VideoTest extends BaseTest
{
parent::setUp();
$config = Config::getInstance();
// So ffmpeg does not spam the output with broken pipe errors.
$config = new Config(['ffmpegVerbosity' => 'fatal']);
$this->downloader = $config->getDownloader();
$this->format = 'best';
}
@ -352,8 +353,7 @@ class VideoTest extends BaseTest
public function testGetAudioStreamFfmpegError(string $url, string $format)
{
$this->expectException(AvconvException::class);
Config::setOptions(['ffmpeg' => 'foobar']);
$config = Config::getInstance();
$config = new Config(['ffmpeg' => 'foobar']);
$downloader = $config->getDownloader();
$video = new Video($this->downloader, $url, $format, $this->format);
@ -502,8 +502,7 @@ class VideoTest extends BaseTest
public function testGetM3uStreamFfmpegError(string $url, string $format)
{
$this->expectException(AvconvException::class);
Config::setOptions(['ffmpeg' => 'foobar']);
$config = Config::getInstance();
$config = new Config(['ffmpeg' => 'foobar']);
$downloader = $config->getDownloader();
$video = new Video($downloader, $url, $format);

View file

@ -6,7 +6,6 @@
namespace Alltube\Test;
use Alltube\Config;
use Alltube\Exception\ConfigException;
use Alltube\Library\Exception\AlltubeLibraryException;
use Alltube\Stream\YoutubeChunkStream;
@ -19,17 +18,15 @@ class YoutubeChunkStreamTest extends StreamTest
{
/**
* Prepare tests.
* @throws ConfigException
* @throws AlltubeLibraryException
* @throws ConfigException
*/
protected function setUp(): void
{
parent::setUp();
$config = Config::getInstance();
$downloader = $config->getDownloader();
$video = $downloader->getVideo('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
$video = $this->downloader->getVideo('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
$this->stream = new YoutubeChunkStream($downloader->getHttpResponse($video));
$this->stream = new YoutubeChunkStream($this->downloader->getHttpResponse($video));
}
}

View file

@ -6,7 +6,6 @@
namespace Alltube\Test;
use Alltube\Config;
use Alltube\Exception\ConfigException;
use Alltube\Library\Exception\AlltubeLibraryException;
use Alltube\Stream\YoutubeStream;
@ -19,17 +18,16 @@ class YoutubeStreamTest extends StreamTest
{
/**
* Prepare tests.
* @throws ConfigException|AlltubeLibraryException
* @throws AlltubeLibraryException
* @throws ConfigException
*/
protected function setUp(): void
{
parent::setUp();
$config = Config::getInstance();
$downloader = $config->getDownloader();
$video = $downloader->getVideo('https://www.youtube.com/watch?v=dQw4w9WgXcQ', '135');
$video = $this->downloader->getVideo('https://www.youtube.com/watch?v=dQw4w9WgXcQ', '135');
$this->stream = new YoutubeStream($downloader, $video);
$this->stream = new YoutubeStream($this->downloader, $video);
}
/**