Skip to content

Commit

Permalink
Refactoring and clean up for future changes
Browse files Browse the repository at this point in the history
- Replaced interface Records with base class implementation
- Added separator constant in CompositeContainer
- Added missing tests for composite & config container
- Renamed RecordSetup to Entry

Planned changes:
- Setup method to add sub-containers (now only predefined in constructor)
- Move config integrity checks into dev enviroment subtypes
  • Loading branch information
shudd3r committed Nov 8, 2019
2 parents c895f52 + 541cd96 commit dda24e8
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 77 deletions.
8 changes: 5 additions & 3 deletions src/CompositeContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

class CompositeContainer implements ContainerInterface
{
protected const SEPARATOR = '.';

private $records;
private $containers;

Expand Down Expand Up @@ -59,8 +61,8 @@ private function inContainers(string $id): bool

private function splitId(string $id): array
{
return $id[0] === '.'
? ['.', ltrim($id, '.')]
: explode('.', $id, 2) + [false, null];
return $id[0] === static::SEPARATOR
? [static::SEPARATOR, ltrim($id, static::SEPARATOR)]
: explode(static::SEPARATOR, $id, 2) + [false, null];
}
}
25 changes: 22 additions & 3 deletions src/Records.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,29 @@
use Psr\Container\ContainerInterface;


interface Records
class Records
{
private $records;

/**
* @param Records\Record[] $records Associative (flat) array of Record entries
*/
public function __construct(array $records = [])
{
$this->records = $records;
}

/**
* Checks if Record is stored at given identifier.
*
* @param string $id
*
* @return bool
*/
public function has(string $id): bool;
public function has(string $id): bool
{
return isset($this->records[$id]);
}

/**
* Returns Record stored at given identifier.
Expand All @@ -35,5 +48,11 @@ public function has(string $id): bool;
*
* @return mixed
*/
public function get(string $id, ContainerInterface $container);
public function get(string $id, ContainerInterface $container)
{
if (!isset($this->records[$id])) {
throw new Exception\RecordNotFoundException(sprintf('Record `%s` not defined', $id));
}
return $this->records[$id]->value($container);
}
}
43 changes: 0 additions & 43 deletions src/Records/RecordCollection.php

This file was deleted.

3 changes: 2 additions & 1 deletion src/Records/TrackedRecords.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@

namespace Polymorphine\Container\Records;

use Polymorphine\Container\Records;
use Polymorphine\Container\Exception;
use Psr\Container\ContainerInterface;


class TrackedRecords extends RecordCollection
class TrackedRecords extends Records
{
private $callStack = [];

Expand Down
10 changes: 5 additions & 5 deletions src/Setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ public function container(bool $tracking = false): ContainerInterface
}

/**
* Returns RecordSetup object able to configure Container's
* Record slot for given name id.
* Returns Entry object able to configure Container's
* data slot for given name id.
*
* @param string $name
*
* @return Setup\RecordSetup
* @return Setup\Entry
*/
public function entry(string $name): Setup\RecordSetup
public function entry(string $name): Setup\Entry
{
return new Setup\RecordSetup($name, $this->collection);
return new Setup\Entry($name, $this->collection);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Setup/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function __construct(array $records)

public function records(bool $tracking = false): Records
{
return $tracking ? new Records\TrackedRecords($this->records) : new Records\RecordCollection($this->records);
return $tracking ? new Records\TrackedRecords($this->records) : new Records($this->records);
}

public function add(string $id, Records\Record $record): void
Expand Down
2 changes: 1 addition & 1 deletion src/Setup/RecordSetup.php → src/Setup/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* Write-only proxy with helper methods to instantiate and
* set Record implementations for given Container name id.
*/
class RecordSetup
class Entry
{
private $name;
private $records;
Expand Down
45 changes: 25 additions & 20 deletions tests/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,16 @@ public function testGivenContainerWithEmptyValues_HasMethodReturnsTrue()
'null' => new Record\ValueRecord(null),
'false' => new Record\ValueRecord(false)
];
$config = [
$config['cfg'] = new ConfigContainer([
'null' => null,
'false' => false
];
]);
$container = $this->builder($config, $records)->container();

$this->assertTrue($container->has('null'));
$this->assertTrue($container->has('false'));
$this->assertTrue($container->has('cfg.null'));
$this->assertTrue($container->has('cfg.false'));
}

public function testInvalidContainerIdTypeIsCastedToString()
Expand Down Expand Up @@ -188,7 +190,8 @@ public function inputScenarios()

public function testSetupContainer_ReturnsSameInstanceOfContainer()
{
$setup = $this->builder(['config' => 'value'], ['exists' => new Record\ValueRecord(true)]);
$config = ['env' => new ConfigContainer(['config' => 'value'])];
$setup = $this->builder($config, ['exists' => new Record\ValueRecord(true)]);
$container = $setup->container();
$setup->entry('not.too.late')->set(true);

Expand All @@ -212,22 +215,21 @@ public function testCallbackRecord()

public function testCompositeRecord()
{
$config = ['env' => [
'name' => 'Shudd3r',
'hello' => function ($name) { return 'Hello ' . $name . '.'; },
'polite' => 'How are you?'
]];
$config = [
'.' => new ConfigContainer(['env' => ['name' => 'Shudd3r', 'polite' => 'How are you?']]),
'cfg' => new ConfigContainer(['hello' => function ($name) { return 'Hello ' . $name . '.'; }])
];

$setup = $this->builder($config);
$setup->entry('small.talk')->compose(Example\ExampleClass::class, '.env.hello', '.env.name');
$setup->entry('small.talk')->compose(Example\ExampleClass::class, 'cfg.hello', '.env.name');
$container = $setup->container();

$expect = 'Hello Shudd3r.';
$this->assertSame($expect, $container->get('small.talk')->beNice());

// Decorated record
$setup = $this->builder($config);
$setup->entry('small.talk')->compose(Example\ExampleClass::class, '.env.hello', '.env.name');
$setup->entry('small.talk')->compose(Example\ExampleClass::class, 'cfg.hello', '.env.name');
$setup->entry('small.talk')->compose(Example\DecoratingExampleClass::class, 'small.talk', '.env.polite');
$container = $setup->container();

Expand All @@ -237,7 +239,7 @@ public function testCompositeRecord()
// Decorated Again
$setup = $this->builder($config);
$setup->entry('ask.football')->set('Have you seen that ridiculous display last night?');
$setup->entry('small.talk')->compose(Example\ExampleClass::class, '.env.hello', '.env.name');
$setup->entry('small.talk')->compose(Example\ExampleClass::class, 'cfg.hello', '.env.name');
$setup->entry('small.talk')->compose(Example\DecoratingExampleClass::class, 'small.talk', '.env.polite');
$setup->entry('small.talk')->compose(Example\DecoratingExampleClass::class, 'small.talk', 'ask.football');
$container = $setup->container();
Expand All @@ -257,7 +259,8 @@ public function testCompositeForUndefinedDecoratedDependency_ThrowsException()

public function testCreateMethodRecord()
{
$setup = $this->builder(['one' => 'first', 'two' => 'second', 'three' => 'third']);
$config['.'] = new ConfigContainer(['one' => 'first', 'two' => 'second', 'three' => 'third']);
$setup = $this->builder($config);
$setup->entry('factory')->set(new Example\Factory());
$setup->entry('product')->create('factory', 'create', '.one', '.two', '.three');
$container = $setup->container();
Expand All @@ -267,8 +270,9 @@ public function testCreateMethodRecord()

public function testConfigsCanBeReadWithPath()
{
$data = ['key1' => ['nested' => ['double' => 'nested value']], 'key2' => 'value2'];
$container = $this->builder(['env' => $data])->container();
$data = ['key1' => ['nested' => ['double' => 'nested value']], 'key2' => 'value2'];
$config['.'] = new ConfigContainer(['env' => $data]);
$container = $this->builder($config)->container();

$this->assertSame($data['key1']['nested']['double'], $container->get('.env.key1.nested.double'));
$this->assertSame($data['key1']['nested'], $container->get('.env.key1.nested'));
Expand All @@ -290,8 +294,8 @@ public function testConfigsCanBeReadWithPath()
*/
public function testGetMissingConfigRecord_ThrowsException(string $undefinedPath)
{
$data = ['key1' => ['nested' => ['double' => 'nested value']], 'key2' => 'value2'];
$container = $this->builder($data)->container();
$config['.'] = new ConfigContainer(['key1' => ['nested' => ['double' => 'nested value']], 'key2' => 'value2']);
$container = $this->builder($config)->container();

$this->assertFalse($container->has($undefinedPath));
$this->expectException(Exception\RecordNotFoundException::class);
Expand All @@ -300,7 +304,7 @@ public function testGetMissingConfigRecord_ThrowsException(string $undefinedPath

public function undefinedPaths(): array
{
return [['.env.key1.nested.value'], ['.env.key1.something'], ['.env.whatever'], ['.notEnv']];
return [['.key1.nested.value'], ['.key1.something'], ['.whatever'], ['notEnv']];
}

public function testUsingConfigKeyIndicatorDoesntMatterIfConfigNotPresent()
Expand Down Expand Up @@ -342,7 +346,8 @@ public function testIndirectCircularCall_ThrowsException()

public function testMultipleCallsAreNotCircular()
{
$setup = $this->builder(['config' => 'value']);
$config['.'] = new ConfigContainer(['config' => 'value']);
$setup = $this->builder($config);
$setup->entry('ref')->invoke(function (ContainerInterface $c) {
return $c->get('ref.multiple') . ':' . $c->get('ref.multiple') . ':' . $c->get('.config');
});
Expand Down Expand Up @@ -391,8 +396,8 @@ public function testCallStackIsAddedToContainerExceptionMessage()
$container->get('C');
}

private function builder(array $config = [], array $records = [])
private function builder(array $configs = [], array $records = [])
{
return new Setup($records, $config ? ['.' => new ConfigContainer($config)] : []);
return new Setup($records, $configs);
}
}

0 comments on commit dda24e8

Please sign in to comment.