Skip to content

Commit

Permalink
Closes #40 (test passes), fixes #50 and #51.
Browse files Browse the repository at this point in the history
  - Dependency solver was removed (it wasnt done).
  - Timezone issue with testing solved.
  - Tests for Issue #40 don't display the expected bug.
  - Fixes #50 and #51
  • Loading branch information
Alexandre Gaigalas committed Feb 11, 2015
1 parent ba4138e commit 2b9cd2a
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 148 deletions.
54 changes: 17 additions & 37 deletions README.md
Expand Up @@ -6,12 +6,7 @@
[![Total Downloads](https://img.shields.io/packagist/dt/respect/config.svg?style=flat-square)](https://packagist.org/packages/respect/config)
[![License](https://img.shields.io/packagist/l/respect/config.svg?style=flat-square)](https://packagist.org/packages/respect/config)

A powerful, small, deadly simple configurator and dependency injection container made to be easy. Featuring:

* INI configuration files only. Simpler than YAML, XML or JSON (see samples below).
* Uses the same native, fast parser that powers php.ini.
* Extends the INI configuration with a custom dialect.
* Implements lazy loading for object instances.
A tiny, fully featured dependency injection container as a DSL.

## Installation

Expand All @@ -22,11 +17,15 @@ You can install it using [Composer](http://getcomposer.org).
composer require respect/config
```

Works on PHP 5.3 and 5.4 only.
## What is a DSL?

DSLs are Domain Specific Languages, small languages implemented for specific
domains. Respect\Config is an **internal DSL** hosted on the INI format to
hold dependency injection containers.

# Feature Guide
## Feature Guide

## Variable Expanding
### Variable Expanding

myconfig.ini:

Expand All @@ -46,7 +45,7 @@ echo $c->db_dsn; //mysql:host=localhost;dbname=my_database

Note that this works only for variables without ini [sections].

## Sequences
### Sequences

myconfig.ini:

Expand Down Expand Up @@ -77,7 +76,7 @@ $c = new Container('myconfig.ini');
print_r($c->allowed_users); //array('foo', 'bar', 'baz')
````

## Constant Evaluation
### Constant Evaluation

myconfig.ini:

Expand All @@ -87,7 +86,7 @@ error_mode = PDO::ERRMODE_EXCEPTION

Needless to say that this would work on sequences too.

## Instances
### Instances

Using sections

Expand Down Expand Up @@ -119,7 +118,7 @@ $c = new Container('myconfig.ini');
echo get_class($c->something); //DateTime
````

## Callbacks
### Callbacks

myconfig.ini:

Expand All @@ -143,7 +142,7 @@ $c->connection = function() use($c) {
echo get_class($c->connection); //PDO
````

## Instance Passing
### Instance Passing

myconfig.ini:

Expand All @@ -165,7 +164,7 @@ echo get_class($c->myClass->myProperty); //DateTime

Obviously, this works on sequences too.

## Instance Constructor Parameters
### Instance Constructor Parameters

Parameter names by reflection:

Expand Down Expand Up @@ -195,7 +194,7 @@ myconfig.ini:
connection PDO = ["mysql:host=localhost;dbname=my_database", "my_user", "my_pass"]
````

## Instantiation by Static Factory Methods
### Instantiation by Static Factory Methods

myconfig.ini:

Expand All @@ -204,7 +203,7 @@ myconfig.ini:
createFromFormat[] = [Y-m-d H:i:s, 2000-01-01 00:00:01]
````

## Instance Method Calls
### Instance Method Calls

myconfig.ini:

Expand All @@ -217,30 +216,11 @@ setAttribute = [PDO::ATTR_ERRMODE, PDO::ATTR_EXCEPTION]
exec[] = "SET NAMES UTF-8"
````

## Instance Properties
### Instance Properties

myconfig.ini:

````ini
[something stdClass]
foo = "bar"
````

# Known Limitations

* Variable expanding only works for unsectioned keys.
* Empty strings, zeros and null are not properly treated yet.
* Constructors with non-null default parameter values may not work properly yet.
* The only way to use magic methods is to call them explicitly with __call
* Circular references haven't been tested and may not work
* May not work properly with the following conditions:
* Static and normal methods with the same names within the same class
* Methods and properties with same names within the same class
* Methods and properties with same names as constructor parameters

Luckly, most of these limitations are known to be PHP bad practices. Keep up the
good work and you'll never face them.

# License Information

See [LICENSE](LICENSE) file.
63 changes: 6 additions & 57 deletions library/Respect/Config/Container.php
Expand Up @@ -92,11 +92,7 @@ protected function configure()
}

if (file_exists($configurator)) {
if (is_file($configurator)) {
return $this->loadFile($configurator);
} elseif (is_dir($configurator)) {
return $this->loadFileMultiple($configurator, scandir($configurator));
}
return $this->loadFile($configurator);
}

if (is_string($configurator)) {
Expand Down Expand Up @@ -133,54 +129,6 @@ public function loadString($configurator)
return $this->loadArray($iniData);
}

public function loadFileMultiple($folder, array $configurators)
{
return $this->loadStringMultiple(
array_map(
'file_get_contents',
array_filter(
array_map(
function ($v) use ($folder) {
return $folder.DIRECTORY_SEPARATOR.$v;
},
$configurators
),
'is_file'
)
)
);
}

public function loadStringMultiple(array $configurators)
{
uasort($configurators, function ($first, $second) {
preg_match_all('#\[([^] ]+)\]#', $first, $usedOnFirst);
preg_match_all('#\[([^] ]+)\]#', $second, $usedOnSecond);
preg_match_all('#\[([^]]+) [^]]+\]#', $first, $declaredOnFirst);
preg_match_all('#\[([^]]+) [^]]+\]#', $second, $declaredOnSecond);

$usedOnFirst = array_unique($usedOnFirst[1]);
$usedOnSecond = array_unique($usedOnSecond[1]);
$declaredOnFirst = array_unique($declaredOnFirst[1]);
$declaredOnSecond = array_unique($declaredOnSecond[1]);

$usedByFirstDeclaredBySecond = array_intersect($usedOnFirst, $declaredOnSecond);
$usedBySecondDeclaredByFirst = array_intersect($usedOnSecond, $declaredOnFirst);

$usagesFirst = count($usedByFirstDeclaredBySecond);
$usagesSecond = count($usedBySecondDeclaredByFirst);

if ($usagesFirst == $usagesSecond) {
return 0;
} else {
return $usagesFirst < $usagesSecond ? -1 : 1;
}
});
foreach ($configurators as $c) {
$this->loadString($c);
}
}

public function loadFile($configurator)
{
$iniData = parse_ini_file($configurator, true);
Expand Down Expand Up @@ -292,15 +240,16 @@ protected function parseInstantiator($key, $value)

protected function parseValue($value)
{
if (is_array($value)) {
if ($value instanceof Instantiator) {
return $value;
} elseif (is_array($value)) {
return $this->parseSubValues($value);
} elseif (empty($value)) {
return;
return null;
} else {
return $this->parseSingleValue($value);
}
}

protected function hasCompleteBrackets($value)
{
return false !== strpos($value, '[') && false !== strpos($value, ']');
Expand Down Expand Up @@ -334,7 +283,7 @@ protected function matchSequence(&$value)

protected function matchReference(&$value)
{
if (preg_match('/^\[(\w+)+\]$/', $value, $match)) {
if (preg_match('/^\[([[:alnum:]\\\\]+)\]$/', $value, $match)) {
return (boolean) ($value = $match[1]);
}
}
Expand Down
5 changes: 5 additions & 0 deletions library/Respect/Config/Instantiator.php
Expand Up @@ -121,6 +121,11 @@ public function setParam($name, $value)
$this->params[$name] = $value;
}

public function getParams()
{
return $this->params;
}

protected function cleanupParams(array $params)
{
while (null === end($params)) {
Expand Down
77 changes: 24 additions & 53 deletions tests/library/Respect/Config/ContainerTest.php
Expand Up @@ -49,16 +49,6 @@ public function testLoadFile()
$this->assertEquals('bat', $c->getItem('baz'));
}

public function testLoadFileMultiple() {
$c = new Container('multiple');
$this->assertTrue(isset($c->foo));
$this->assertEquals('bar', $c->getItem('foo'));
$this->assertEquals('bat', $c->getItem('baz'));
$this->assertTrue(isset($c->panda));
$this->assertEquals('happy', $c->getItem('panda'));
$this->assertEquals('panda', $c->getItem('happy'));
}

/**
* @expectedException InvalidArgumentException
* @expectedExceptionMessage Invalid input. Must be a valid file or array
Expand Down Expand Up @@ -258,7 +248,7 @@ public function testClosureWithLoadedFile()
INI;
$c = new Container($ini);
$c->panda = function() { return 'ok'; };
$this->assertEquals('ok', $c->getItem('panda', false));
$this->assertEquals('ok', $c->getItem('panda', false));
}

public function testLazyLoadinessOnMultipleConfigLevels()
Expand Down Expand Up @@ -304,52 +294,24 @@ public function testPascutti()
$c->pdo = new \PDO('sqlite::memory:');
$this->assertSame($c->pdo, $c->db->c);
}
public function testDependencies()
{
$ini1 = <<<INI
[bar stdClass]
value = bar
INI;
$ini2 = <<<INI
[foo stdClass]
bar = [bar]
value = foo
INI;
$c = new Container;
$c->loadStringMultiple(array($ini1, $ini2));
$this->assertEquals('bar', $c->foo->bar->value);
$c = new Container;
$c->loadStringMultiple(array($ini2, $ini1));
$this->assertEquals('bar', $c->foo->bar->value);
}
public function testDependenciesDeep()

public function testPascuttiTypeHintIssue40()
{
$ini1 = <<<INI
[bar stdClass]
value = bar
[bat stdClass]
value = bat
INI;
$ini2 = <<<INI
[foo stdClass]
bar = [bar]
value = foo
value2 = [bar]
INI;
$ini3 = <<<INI
[deep stdClass]
value1 = [foo]
$GLOBALS['_MERD_'] = false;
$ini = <<<INI
[now DateTime]
[typed Respect\Config\TypeHintWowMuchType]
date = [now];
INI;
$c = new Container;
$c->loadStringMultiple(array($ini1, $ini2, $ini3));
$this->assertEquals('bar', $c->foo->bar->value);
$this->assertEquals('foo', $c->deep->value1->value);
$c = new Container;
$c->loadStringMultiple(array($ini2, $ini3, $ini1));
$this->assertEquals('bar', $c->foo->bar->value);
$this->assertEquals('foo', $c->deep->value1->value);
$c = new Container;
$c->loadArray(parse_ini_string($ini, true));
$this->assertInstanceOf(
'Respect\Config\TypeHintWowMuchType',
$c->typed
);
}

public function testLockedContainer()
{
$ini = <<<INI
Expand Down Expand Up @@ -458,3 +420,12 @@ public function __construct($con) {
}
}


class TypeHintWowMuchType {
public $d;
public function __construct(\DateTime $date) {
$this->d = $date;
}
}


3 changes: 2 additions & 1 deletion tests/library/Respect/Config/InstantiatorTest.php
Expand Up @@ -15,9 +15,10 @@ public function testStaticMethodConstructor()

public function testConstructorParamNames()
{
date_default_timezone_set('UTC');
$i = new Instantiator('DateTime');
$i->setParam('time', 'now');
$i->setParam('timezone', $tz = new \DateTimeZone('America/Sao_Paulo'));
$i->setParam('timezone', $tz = new \DateTimeZone('UTC'));
$s = $i->getInstance();
$this->assertEquals('DateTime', get_class($s));
$this->assertEquals($tz, $s->getTimezone());
Expand Down

0 comments on commit 2b9cd2a

Please sign in to comment.