Skip to content

Commit

Permalink
Added YAML configuration reader (#271)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbyoung committed Jun 29, 2023
1 parent 65c50fe commit 07b8417
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 1 deletion.
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -39,7 +39,8 @@
},
"require": {
"php": "^8.2",
"symfony/dotenv": "^6.1"
"symfony/dotenv": "^6.1",
"symfony/yaml": "^6.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.5",
Expand Down
46 changes: 46 additions & 0 deletions src/Configuration/YamlConfigurationFileReader.php
@@ -0,0 +1,46 @@
<?php

/**
* Aphiria
*
* @link https://www.aphiria.com
* @copyright Copyright (C) 2023 David Young
* @license https://github.com/aphiria/aphiria/blob/1.x/LICENSE.md
*/

declare(strict_types=1);

namespace Aphiria\Application\Configuration;

use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;

/**
* Defines the configuration reader that reads YAML files
*
*/
class YamlConfigurationFileReader implements IConfigurationFileReader
{
/**
* @inheritdoc
*/
public function readConfiguration(string $path, string $pathDelimiter = '.'): IConfiguration
{
if (!\file_exists($path)) {
throw new InvalidConfigurationFileException("$path does not exist");
}

try {
$hashTable = Yaml::parseFile($path);

if (!\is_array($hashTable) || \array_is_list($hashTable)) {
throw new InvalidConfigurationFileException("YAML in $path does not parse to an associative array");
}
} catch (ParseException $ex) {
throw new InvalidConfigurationFileException("Invalid YAML in $path");
}

/** @var array<string, mixed> $hashTable */
return new HashTableConfiguration($hashTable, $pathDelimiter);
}
}
71 changes: 71 additions & 0 deletions tests/Configuration/YamlConfigurationFileReaderTest.php
@@ -0,0 +1,71 @@
<?php

/**
* Aphiria
*
* @link https://www.aphiria.com
* @copyright Copyright (C) 2023 David Young
* @license https://github.com/aphiria/aphiria/blob/1.x/LICENSE.md
*/

declare(strict_types=1);

namespace Aphiria\Application\Tests\Configuration;

use Aphiria\Application\Configuration\InvalidConfigurationFileException;
use Aphiria\Application\Configuration\YamlConfigurationFileReader;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;

class YamlConfigurationFileReaderTest extends TestCase
{
private YamlConfigurationFileReader $reader;

protected function setUp(): void
{
$this->reader = new YamlConfigurationFileReader();
}

public function testEmptyPathDelimiterThrowsException(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Path delimiter cannot be empty');
/** @psalm-suppress InvalidArgument Purposely testing an empty path delimiter */
$this->reader->readConfiguration(__DIR__ . '/files/configuration.yaml', '');
}

public function testReadingConfigurationCreatesConfigurationFromContentsOfYamlFile(): void
{
$configuration = $this->reader->readConfiguration(__DIR__ . '/files/configuration.yaml');
$this->assertSame('bar', $configuration->getString('foo'));
}

public function testReadingConfigurationWithCustomDelimiterAllowsAccessWithThatDelimiter(): void
{
$configuration = $this->reader->readConfiguration(__DIR__ . '/files/configuration-delimiter.yaml', ':');
$this->assertSame('baz', $configuration->getString('foo:bar'));
}

public function testReadingInvalidYamlThrowsException(): void
{
$path = __DIR__ . '/files/invalid-configuration.yaml';
$this->expectException(InvalidConfigurationFileException::class);
$this->expectExceptionMessage("Invalid YAML in $path");
$this->reader->readConfiguration($path);
}

public function testReadingNonExistentPathThrowsException(): void
{
$this->expectException(InvalidConfigurationFileException::class);
$this->expectExceptionMessage('/doesnotexist does not exist');
$this->reader->readConfiguration('/doesnotexist');
}

public function testReadingYamlThatDoesNotMapToAssociativeArrayThrowsException(): void
{
$path = __DIR__ . '/files/non-hash-table.yaml';
$this->expectException(InvalidConfigurationFileException::class);
$this->expectExceptionMessage("YAML in $path does not parse to an associative array");
$this->reader->readConfiguration($path);
}
}
2 changes: 2 additions & 0 deletions tests/Configuration/files/configuration-delimiter.yaml
@@ -0,0 +1,2 @@
foo:
bar: baz
1 change: 1 addition & 0 deletions tests/Configuration/files/configuration.yaml
@@ -0,0 +1 @@
foo: bar
1 change: 1 addition & 0 deletions tests/Configuration/files/invalid-configuration.yaml
@@ -0,0 +1 @@
":
1 change: 1 addition & 0 deletions tests/Configuration/files/non-hash-table.yaml
@@ -0,0 +1 @@
foo

0 comments on commit 07b8417

Please sign in to comment.