Skip to content

Commit

Permalink
Merge pull request #2 from sirn-se/v1.2
Browse files Browse the repository at this point in the history
V1.2
  • Loading branch information
sirn-se committed Apr 17, 2024
2 parents 1fa022b + 581ec84 commit 98d8708
Show file tree
Hide file tree
Showing 16 changed files with 177 additions and 24 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ $merged = $config->merge($additional);

A number of configuration readers are available.

### The `DataReader` class

The `Phrity\Config\DataReader` takes input as associative array, object, or null.

```php
$reader = new Phrity\Config\DataReader();
$config = $reader->createConfiguration(data: ['a' => 23]);
```

### The `JsonReader` class

The `Phrity\Config\JsonReader` parses provided JSON string.
Expand Down Expand Up @@ -131,6 +140,7 @@ The `Phrity\Config\ConfigurationFactory` provides shortcuts to create and merge
```php
$factory = new Phrity\Config\ConfigurationFactory();

$configData = $factory->fromData(data: ['a' => 23]);
$configJson = $factory->fromJson(json: '{"a": 23}');
$configJsonFile = $factory->fromJsonFile(path: 'path/to/config.json');
$configYaml = $factory->fromYaml(yaml: 'n: 23');
Expand All @@ -139,6 +149,7 @@ $configEnv = $factory->fromEnv();
$configEnvFile = $factory->fromEnvFile('.env');

$configMerged = $factory->merge(
$configData,
$configJson,
$configJsonFile,
$configYaml,
Expand All @@ -153,5 +164,6 @@ $configMerged = $factory->merge(

| Version | PHP | |
| --- | --- | --- |
| `1.2` | `^8.1` | Reader (data), all file-readers get `optional` option |
| `1.1` | `^8.1` | Readers (yaml, env-file) |
| `1.0` | `^8.1` | Interface, implementation, readers (json, json-file, yaml-file, env), factory |
10 changes: 7 additions & 3 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Configuration implements ConfigurationInterface
{
use AccessorTrait;

private object $config;
protected object $config;


/* ---------- Public methods ----------------------------------------------------------------------------------- */
Expand Down Expand Up @@ -61,6 +61,10 @@ public function merge(ConfigurationInterface $config): self
return new self($this->merger($this->config, $config->jsonSerialize()));
}

/**
* Return as anonymous onject.
* @return As object
*/
public function jsonSerialize(): object
{
return $this->config;
Expand All @@ -69,7 +73,7 @@ public function jsonSerialize(): object

/* ---------- Private helper methods --------------------------------------------------------------------------- */

private function normalize(mixed $data): mixed
protected function normalize(mixed $data): mixed
{
if (is_scalar($data)) {
return $data;
Expand All @@ -87,7 +91,7 @@ private function normalize(mixed $data): mixed
return (object)$changed;
}

private function merger(object $d1, object $d2)
protected function merger(object $d1, object $d2)
{
$changed = clone $d1;
array_walk($d2, function (mixed $value, string $key) use ($changed) {
Expand Down
28 changes: 20 additions & 8 deletions src/ConfigurationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

class ConfigurationFactory
{
private string $class;
private string $prefix;
protected string $class;
protected string $prefix;


/* ---------- Public methods ----------------------------------------------------------------------------------- */
Expand All @@ -16,15 +16,21 @@ public function __construct(string $class = Configuration::class, string $prefix
$this->prefix = $prefix;
}

public function fromData(object|array|null $data): ConfigurationInterface
{
$reader = new DataReader(class: $this->class);
return $reader->createConfiguration(data: $data);
}

public function fromJson(string $json): ConfigurationInterface
{
$reader = new JsonReader(class: $this->class);
return $reader->createConfiguration(json: $json);
}

public function fromJsonFile(string $path): ConfigurationInterface
public function fromJsonFile(string $path, bool $optional = false): ConfigurationInterface
{
$reader = new JsonFileReader(class: $this->class, prefix: $this->prefix);
$reader = new JsonFileReader(class: $this->class, prefix: $this->prefix, optional: $optional);
return $reader->createConfiguration(path: $path);
}

Expand All @@ -34,9 +40,9 @@ public function fromYaml(string $yaml): ConfigurationInterface
return $reader->createConfiguration(yaml: $yaml);
}

public function fromYamlFile(string $path): ConfigurationInterface
public function fromYamlFile(string $path, bool $optional = false): ConfigurationInterface
{
$reader = new YamlFileReader(class: $this->class, prefix: $this->prefix);
$reader = new YamlFileReader(class: $this->class, prefix: $this->prefix, optional: $optional);
return $reader->createConfiguration(path: $path);
}

Expand All @@ -49,9 +55,15 @@ public function fromEnv(string|null $separator = null, array|null $match = null)
public function fromEnvFile(
string $path,
string|null $separator = null,
array|null $match = null
array|null $match = null,
bool $optional = false,
): ConfigurationInterface {
$reader = new EnvFileReader(class: $this->class, prefix: $this->prefix, separator: $separator);
$reader = new EnvFileReader(
class: $this->class,
prefix: $this->prefix,
separator: $separator,
optional: $optional
);
return $reader->createConfiguration(path: $path, match: $match);
}

Expand Down
18 changes: 18 additions & 0 deletions src/DataReader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Phrity\Config;

class DataReader implements ReaderInterface
{
protected string $class;

public function __construct(string $class = Configuration::class)
{
$this->class = $class;
}

public function createConfiguration(object|array|null $data = null): ConfigurationInterface
{
return new $this->class($data ?? []);
}
}
11 changes: 8 additions & 3 deletions src/EnvFileReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,31 @@ class EnvFileReader implements ReaderInterface
use FileTrait;
use TreeTrait;

private string $class;
private Dotenv $parser;
protected string $class;
protected Dotenv $parser;

public function __construct(
string $class = Configuration::class,
string $prefix = '',
string|null $separator = null
string|null $separator = null,
bool $optional = false,
) {
if (!class_exists(Dotenv::class)) {
throw new ReaderException("Dependency 'symfony/dotenv' not installed, can not read .env file.");
}
$this->class = $class;
$this->separator = $separator;
$this->prefix = $prefix;
$this->optional = $optional;
$this->parser = new Dotenv();
}

public function createConfiguration(string $path = '.env', array|null $match = null): ConfigurationInterface
{
$content = $this->readFile($path);
if (is_null($content)) {
return new $this->class();
}
try {
$env = array_change_key_case($this->parser->parse($content));
if (!is_null($match)) {
Expand Down
2 changes: 1 addition & 1 deletion src/EnvReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class EnvReader implements ReaderInterface
{
use TreeTrait;

private string $class;
protected string $class;

public function __construct(string $class = Configuration::class, string|null $separator = null)
{
Expand Down
8 changes: 6 additions & 2 deletions src/FileTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@

trait FileTrait
{
private string $prefix = '';
protected string $prefix = '';
protected bool $optional = false;

public function readFile(string $path): string
public function readFile(string $path): string|null
{
$file = "{$this->prefix}{$path}";
if (!is_file($file)) {
if ($this->optional) {
return null;
}
throw new ReaderException("File '{$file}' not found.");
}
if (!is_readable($file)) {
Expand Down
11 changes: 9 additions & 2 deletions src/JsonFileReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,22 @@ class JsonFileReader extends JsonReader implements ReaderInterface
{
use FileTrait;

public function __construct(string $class = Configuration::class, string $prefix = '')
{
public function __construct(
string $class = Configuration::class,
string $prefix = '',
bool $optional = false,
) {
parent::__construct($class);
$this->prefix = $prefix;
$this->optional = $optional;
}

public function createConfiguration(string $path = 'config.json'): ConfigurationInterface
{
$content = $this->readFile($path);
if (is_null($content)) {
return new $this->class();
}
return parent::createConfiguration($content);
}
}
2 changes: 1 addition & 1 deletion src/JsonReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class JsonReader implements ReaderInterface
{
private string $class;
protected string $class;

public function __construct(string $class = Configuration::class)
{
Expand Down
11 changes: 9 additions & 2 deletions src/YamlFileReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,22 @@ class YamlFileReader extends YamlReader implements ReaderInterface
{
use FileTrait;

public function __construct(string $class = Configuration::class, string $prefix = '')
{
public function __construct(
string $class = Configuration::class,
string $prefix = '',
bool $optional = false,
) {
parent::__construct($class);
$this->prefix = $prefix;
$this->optional = $optional;
}

public function createConfiguration(string $path = 'config.yaml'): ConfigurationInterface
{
$content = $this->readFile($path);
if (is_null($content)) {
return new $this->class();
}
return parent::createConfiguration($content);
}
}
4 changes: 2 additions & 2 deletions src/YamlReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

class YamlReader implements ReaderInterface
{
private string $class;
private Parser $parser;
protected string $class;
protected Parser $parser;

public function __construct(string $class = Configuration::class)
{
Expand Down
18 changes: 18 additions & 0 deletions tests/ConfigurationFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ public function testConfigurationFactory(): void
$this->assertInstanceOf(ConfigurationFactory::class, $factory);
}

public function testFromData(): void
{
$factory = new ConfigurationFactory();
$config = $factory->fromData(['a' => 23]);
$this->assertInstanceOf(ConfigurationInterface::class, $config);
}

public function testFromJson(): void
{
$factory = new ConfigurationFactory();
Expand Down Expand Up @@ -64,6 +71,17 @@ public function testFactoryClass(): void
$this->assertInstanceOf(TestConfiguration::class, $config);
}

public function testOptional(): void
{
$factory = new ConfigurationFactory();
$config = $factory->fromJsonFile(path: 'no/file/here', optional: true);
$this->assertInstanceOf(ConfigurationInterface::class, $config);
$config = $factory->fromYamlFile(path: 'no/file/here', optional: true);
$this->assertInstanceOf(ConfigurationInterface::class, $config);
$config = $factory->fromEnvFile(path: 'no/file/here', optional: true);
$this->assertInstanceOf(ConfigurationInterface::class, $config);
}

public function testMerge(): void
{
$factory = new ConfigurationFactory();
Expand Down
45 changes: 45 additions & 0 deletions tests/DataReaderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace Phrity\Config;

use PHPUnit\Framework\TestCase;
use Phrity\Config\Test\TestConfiguration;

class DataReaderTest extends TestCase
{
public function setUp(): void
{
$GLOBALS['class_exists'] = true;
$GLOBALS['is_readable'] = true;
}

public function testDataReader(): void
{
$reader = new DataReader();
$this->assertInstanceOf(DataReader::class, $reader);
$this->assertInstanceOf(ReaderInterface::class, $reader);

$config = $reader->createConfiguration();
$this->assertInstanceOf(Configuration::class, $config);
}

public function testDataReaderParse(): void
{
$json = '{"A": "A", "B": "B"}';
$reader = new DataReader();
$config = $reader->createConfiguration(data: ['a' => 'A', 'b' => 'B']);
$this->assertEquals((object)[
'a' => 'A',
'b' => 'B'
], $config->jsonSerialize());
}

public function testDataReaderClass(): void
{
$reader = new DataReader(class: TestConfiguration::class);
$config = $reader->createConfiguration();
$this->assertInstanceOf(TestConfiguration::class, $config);
}
}
7 changes: 7 additions & 0 deletions tests/EnvFileReaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ public function testEnvFileReaderPath(): void
], $config->jsonSerialize());
}

public function testEnvFileOptional(): void
{
$reader = new EnvFileReader(optional: true);
$config = $reader->createConfiguration(path: 'no/file/here');
$this->assertEquals((object)[], $config->jsonSerialize());
}

public function testFileNotFound(): void
{
$reader = new EnvFileReader();
Expand Down
7 changes: 7 additions & 0 deletions tests/JsonFileReaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ public function testJsonFileReaderClass(): void
$this->assertInstanceOf(TestConfiguration::class, $config);
}

public function testJsonFileOptional(): void
{
$reader = new JsonFileReader(optional: true);
$config = $reader->createConfiguration(path: 'no/file/here');
$this->assertEquals((object)[], $config->jsonSerialize());
}

public function testFileNotFound(): void
{
$reader = new JsonFileReader();
Expand Down

0 comments on commit 98d8708

Please sign in to comment.