Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 83 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,95 @@ It also promises to be immutable after first read.

## Usage

### Load config from file

We support writing your config in php files

Example:
```php
<?php

// config.php

return [
'config-key' => 'value',
'nested' => [
'key' => 'nested-value'
'bool-key' => false,
],
];
```

$config = new \Stefna\Config\FileConfig('path-to-php-config.php');
```php
$config = new \Stefna\Config\FileConfig('path-to-php/config.php');
// config file is not read until it's needed

$config->getBool('boolKey');
$config->getBool('nested.bool-key') === false;
$config->getString('config-key') === 'value';
```

### Load multiple files into config

```php
<?php

// common.php

return [
'config-key' => 'value',
'nested' => [
'key' => 'nested-value'
'bool-key' => false,
],
];
```
```php
<?php

// production.php

return [
'config-key' => 'production-value',
'nested' => [
'extra-key' => 42,
],
];
```

```php
$config = new \Stefna\Config\FileCollectionConfig('path-to-php/');
$config->addFile('common.php');
$config->addFile('production.php');

// config files is not read until it's needed

$config->getInt('nested.extra-key') === 42;
$config->getString('config-key') === 'product-value';
```

### Mutable config

We do provide a mutable config that allows you to override values in the "root" config
this is meant to be used when testing applications but still allow the "root" configuration to stay immutable


```php
$rootConfig = new \Stefna\Config\FileCollectionConfig('path-to-php/');
$rootConfig->addFile('common.php');
$rootConfig->addFile('production.php');

$config = new \Stefna\Config\MutableConfig($rootConfig);

$config->setConfigValue('config-key', 'overridden-value');

$config->getString('config-key') === 'overridden-value';

$config->resetConfigValue('config-key');

$config->getString('config-key') === 'production-value';
```


## Contribute

We are always happy to receive bug/security reports and bug/security fixes
Expand Down
33 changes: 33 additions & 0 deletions src/MutableConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php declare(strict_types=1);

namespace Stefna\Config;

final class MutableConfig implements Config
{
use GetConfigTrait;

/** @var array<string, mixed> */
private array $config = [];

public function __construct(
private readonly Config $rootConfig,
) {}

public function getRawValue(string $key): mixed
{
if (isset($this->config[$key])) {
return $this->config[$key];
}
return $this->rootConfig->get($key);
}

public function setConfigValue(string $key, mixed $value): void
{
$this->config[$key] = $value;
}

public function resetConfigValue(string $key): void
{
unset($this->config[$key]);
}
}
147 changes: 147 additions & 0 deletions tests/AbstractConfigTestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php declare(strict_types=1);

namespace Stefna\Config\Tests;

use PHPUnit\Framework\TestCase;
use Stefna\Config\ArrayConfig;
use Stefna\Config\Config;
use Stefna\Config\Tests\Stub\TestStub;

abstract class AbstractConfigTestCase extends TestCase
{
public function testGetArrayConfigAsConfigObject(): void
{
$config = $this->getConfig();
$obj = $config->getArrayAsObject('testArray', ArrayConfig::class);

$this->assertInstanceOf(ArrayConfig::class, $obj);
$this->assertSame(1, $obj->getInt('random'));
}

public function testGetArrayObject(): void
{
$config = $this->getConfig();

$obj = $config->getArrayAsObject('testArray', TestStub::class);

$this->assertInstanceOf(TestStub::class, $obj);
$this->assertSame(1, $obj->random);
}

public function testGetArrayObjectWithInvalidClass(): void
{
$config = $this->getConfig();

$this->expectException(\BadMethodCallException::class);

$config->getArrayAsObject('testArray', \ArrayObject::class);
}

public function testGetArray(): void
{
$config = $this->getConfig();

$arr = $config->getArray('testArray');

$this->assertIsArray($arr);
$this->assertSame('1', $arr['random']);
}

public function testGetArrayWithDefaultValue(): void
{
$config = $this->getConfig();

$arr = $config->getArray('not-found', ['number' => 1]);

$this->assertIsArray($arr);
$this->assertSame(1, $arr['number']);
}

public function testGetArrayWithInvalidValueReturnsEmptyArray(): void
{
$config = $this->getConfig();

$arr = $config->getArray('testString');
$this->assertEmpty($arr);
}

public function testGetArrayNotFoundEmptyArray(): void
{
$config = $this->getConfig();

$arr = $config->getArray('not-found');
$this->assertEmpty($arr);
}

public function testGet(): void
{
$config = $this->getConfig();

$this->assertSame('string', $config->get('testString'));
}

public function testGetWithDefault(): void
{
$config = $this->getConfig();

$this->assertSame(1, $config->get('not-found', 1));
}

public function testGetNestedValueByDotKey(): void
{
$config = $this->getConfig();

$this->assertSame(1, $config->getInt('deep.nesting.int'));
$this->assertSame('test', $config->getString('deep.nesting.string'));
}

public function testGetNestedValueByDotKeyNotFound(): void
{
$config = $this->getConfig();

$this->assertNull($config->getInt('deep.nesting.not-found.int'));
}

public function testGetNestedValueHasLowerPriorityThanExactMatch(): void
{
$config = $this->getConfig();

$this->assertSame(1, $config->get('nesting.test.value'));
}

public function testDotKeyReturnEmptyOnExtraDots(): void
{
$config = $this->getConfig();

$this->assertNull($config->get('nesting.'));
$this->assertNull($config->get('.nesting'));
}

protected function getDefaultArrayConfig(): ArrayConfig
{
return new ArrayConfig([
'testString' => 'string',
'testNumberAsString' => '43',
'testNumber' => 42,
'testBool' => true,
'testBoolAsString' => 'on',
'testArray' => [
'random' => '1',
],
'deep' => [
'nesting' => [
'int' => 1,
'string' => 'test',
],
],
'nesting.test.value' => 1,
'nesting' => [
'test' => [
'value' => 2,
],
],
]);
}

abstract protected function getConfig(): Config;
}
Loading