Skip to content

Commit 9c7791d

Browse files
author
Sam Rapaport
authored
Merge pull request #22 from samrap/0.3
0.3
2 parents 2b7f20c + 2eb7639 commit 9c7791d

4 files changed

Lines changed: 175 additions & 14 deletions

File tree

phpunit.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
syntaxCheck="false">
1212
<testsuites>
1313
<testsuite name="Gestalt Test Suite">
14-
<directory suffix=".php">./tests/</directory>
15-
<exclude>./tests/config</exclude>
14+
<directory suffix="Test.php">./tests/</directory>
1615
</testsuite>
1716
</testsuites>
1817
</phpunit>

readme.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,50 @@ Gestalt is a simple and elegant PHP package for managing your framework's config
1313
### Features
1414
- **Lightweight:** Gestalt is built to be lightweight. No dependencies, no bloat, just an object-oriented wrapper around your framework's configuration.
1515
- **Powerful:** Who said lightweight means powerless? Gestalt has a small footprint but packs a mean punch. Just take a look at its [Custom Loaders](https://github.com/samrap/gestalt-docs/blob/master/loaders.md) and [Observers](https://github.com/samrap/gestalt-docs/blob/master/observers.md) and you'll see for yourself.
16-
- **Flexible:** Developers like to do things _our_ way. Gestalt gives you the flexibility to integrate seamlessly with how you store your configuration values.
17-
- **Expressive syntax**: With its clean, collection-like syntax, code artisans will feel right at home. Not to worry messy developers, you'll like it too!
16+
- **Flexible:** Developers like to do things _our_ way. Gestalt gives you the flexibility to integrate seamlessly with your application.
17+
- **Expressive syntax**: With its clean, collection-like syntax, code artisans will feel right at home. Messy developers will like it too!
18+
19+
### Examples
20+
21+
The following are just a few of the features Gestalt has to offer. [Visit the docs](https://github.com/samrap/gestalt-docs) for more on installation, usage, and features.
22+
23+
**Basic Usage** ([Learn More](https://github.com/samrap/gestalt-docs/blob/master/introduction.md))
24+
25+
```php
26+
$config = new Configuration([
27+
'app' => [
28+
'debug' => true,
29+
'version' => '1.0',
30+
],
31+
]);
32+
33+
// Get values using dot notation or ArrayAccess.
34+
$config->get('app.debug');
35+
$config['app'];
36+
37+
// Add values using dot notation or ArrayAccess.
38+
$config->add('app.locale', 'en');
39+
$config['mail'] = ['driver' => 'MailMonkey'];
40+
```
41+
42+
**Custom Loading** ([Learn More](https://github.com/samrap/gestalt-docs/blob/master/loaders.md))
43+
44+
```php
45+
$config = Configuration::load(new JsonFileLoader);
46+
47+
$config->get('app.debug');
48+
```
49+
50+
**Observers** ([Learn More](https://github.com/samrap/gestalt-docs/blob/master/observers.md))
51+
52+
```php
53+
$config = new Configuration($values);
54+
55+
$config->attach(new StatefulObserver);
56+
57+
// Notifies the StatefulObserver that the
58+
// Configuration has been updated.
59+
$config->set('app.debug', false);
60+
```
1861

1962
Interested? [Check out the docs](https://github.com/samrap/gestalt-docs) to see all of the features in action!

src/Gestalt/Configuration.php

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Gestalt;
44

5+
use Closure;
56
use ArrayAccess;
67
use Traversable;
78
use Gestalt\Util\Observable;
@@ -35,9 +36,25 @@ public function __construct($items = [])
3536
$this->original = $this->items;
3637
}
3738

39+
/**
40+
* Create a new Configuration with the given loader.
41+
*
42+
* @param \Gestalt\Loaders\LoaderInterface|\Closure $loader
43+
* @return \Gestalt\Collection
44+
*/
45+
public static function load($loader)
46+
{
47+
if ($loader instanceof Closure) {
48+
return new self($loader());
49+
} elseif ($loader instanceof LoaderInterface) {
50+
return new self($loader->load());
51+
}
52+
}
53+
3854
/**
3955
* Create a Configuration instance from a LoaderInterface's `load` method.
4056
*
57+
* @deprecated 1.0.0 Replaced with more flexible `load` method.
4158
* @param \Gestalt\Loaders\LoaderInterface $loader
4259
* @return \Gestalt\Configuration
4360
*/
@@ -80,10 +97,11 @@ public function all()
8097
/**
8198
* Get a configuration item.
8299
*
83-
* @param string $key
100+
* @param string $key
101+
* @param mixed $default
84102
* @return mixed
85103
*/
86-
public function get($key)
104+
public function get($key, $default = null)
87105
{
88106
if ($this->exists($key)) {
89107
return $this->items[$key];
@@ -95,7 +113,7 @@ public function get($key)
95113
if (is_array($result) && array_key_exists($piece, $result)) {
96114
$result = $result[$piece];
97115
} else {
98-
return;
116+
return $default;
99117
}
100118
}
101119

@@ -202,6 +220,8 @@ public function remove($key)
202220
}
203221

204222
unset($section[array_shift($keys)]);
223+
224+
$this->notify();
205225
}
206226

207227
/**
@@ -216,6 +236,28 @@ public function reset()
216236
return $this;
217237
}
218238

239+
/**
240+
* Modify a chunk of the Configuration within the specified prefix.
241+
*
242+
* @param string $prefix
243+
* @param \Closure $callback
244+
* @return void
245+
*/
246+
public function prefix($prefix, $callback)
247+
{
248+
$partial = new self($this->get($prefix));
249+
250+
// We will pass the newly created "partial" Configuration object to the
251+
// callback so that it can be used within the given prefix.
252+
$callback($partial);
253+
254+
// We want to make sure that any changes made to the prefixed object are
255+
// reflected in this object, so we will swap it with the partial.
256+
$this->set($prefix, $partial->all());
257+
258+
unset($partial);
259+
}
260+
219261
/**
220262
* Add or modify an item in the configuration.
221263
*
@@ -225,7 +267,7 @@ public function reset()
225267
*/
226268
public function offsetSet($offset, $value)
227269
{
228-
$this->add($offset, $value);
270+
$this->set($offset, $value);
229271
}
230272

231273
/**

tests/ConfigurationTest.php

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ class ConfigurationTest extends TestCase
66
{
77
public function test_get_method_gets_item()
88
{
9-
$c = new Configuration($this->getConfigurationItems());
9+
$c = new Configuration(['debug' => true]);
1010

11-
$this->assertArrayHasKey('debug', $c->get('app'));
11+
$this->assertTrue($c->get('debug'));
1212
}
1313

1414
public function test_get_method_gets_item_with_dot_notation()
@@ -20,12 +20,18 @@ public function test_get_method_gets_item_with_dot_notation()
2020
$this->assertEquals('gestalt', $c->get('database.drivers.mysql.database'));
2121
}
2222

23+
public function test_get_method_returns_default_value_if_item_isnt_present()
24+
{
25+
$c = new Configuration;
26+
27+
$this->assertEquals(123, $c->get('foo', 123));
28+
}
29+
2330
public function test_all_method_gets_all_items()
2431
{
25-
$items = $this->getConfigurationItems();
2632
$c = new Configuration($this->getConfigurationItems());
2733

28-
$this->assertEquals($items, $c->all());
34+
$this->assertEquals($this->getConfigurationItems(), $c->all());
2935
}
3036

3137
public function test_exists_method_verifies_existance()
@@ -120,7 +126,14 @@ public function test_for_ArrayAccess_implementation()
120126
{
121127
$c = new Configuration($this->getConfigurationItems());
122128

123-
$this->assertArrayHasKey('version', $c['app']);
129+
$this->assertArrayHasKey('debug', $c['app']);
130+
$this->assertTrue($c['app.debug']);
131+
132+
$c['app.debug'] = false;
133+
$this->assertEquals(false, $c['app.debug']);
134+
135+
unset($c['app.debug']);
136+
$this->assertNull($c['app.debug']);
124137
}
125138

126139
public function test_instantiation_from_different_types()
@@ -152,7 +165,10 @@ public function test_reset_method_resets_changes()
152165

153166
public function test_configuration_is_observable()
154167
{
155-
$this->assertInstanceOf('Gestalt\Util\Observable', new Configuration($this->getConfigurationItems()));
168+
$this->assertInstanceOf(
169+
'Gestalt\Util\Observable',
170+
new Configuration($this->getConfigurationItems())
171+
);
156172
}
157173

158174
public function test_configuration_notifies_observers_on_add()
@@ -177,6 +193,17 @@ public function test_configuration_notifies_observers_on_set()
177193
$c->set('foo', 123);
178194
}
179195

196+
public function test_configuration_notifies_observers_on_remove()
197+
{
198+
$c = new Configuration($this->getConfigurationItems());
199+
200+
$c->attach($this->getObserver());
201+
$c->attach($this->getObserver());
202+
203+
// If the mocked observers aren't notified, an error will be thrown.
204+
$c->remove('app.version');
205+
}
206+
180207
public function test_configuration_does_not_notify_observers_on_reset()
181208
{
182209
$c = new Configuration($this->getConfigurationItems());
@@ -188,4 +215,54 @@ public function test_configuration_does_not_notify_observers_on_reset()
188215
// if the reset method notifies observers, we will get an error.
189216
$c->reset();
190217
}
218+
219+
public function test_create_method_creates_configuration_from_closure_loader()
220+
{
221+
$values = $this->getConfigurationItems();
222+
$c = Configuration::load(function () use ($values) {
223+
return $values;
224+
});
225+
226+
$this->assertEquals('1.0', $c->get('app.version'));
227+
}
228+
229+
public function test_create_method_creates_configuration_from_class_loader()
230+
{
231+
$loader = Mockery::mock('\Gestalt\Loaders\LoaderInterface');
232+
$loader->shouldReceive('load')->andReturn($this->getConfigurationItems());
233+
$c = Configuration::load($loader);
234+
235+
$this->assertEquals('1.0', $c->get('app.version'));
236+
}
237+
238+
public function test_prefix_method_gets_prefixed_configuration()
239+
{
240+
$testval = null;
241+
242+
$c = new Configuration($this->getConfigurationItems());
243+
$c->prefix('database.drivers.mysql', function ($partial) use (&$testval) {
244+
$testval = $partial->get('database');
245+
});
246+
247+
$this->assertEquals($c->get('database.drivers.mysql.database'), $testval);
248+
}
249+
250+
public function test_prefix_method_modifies_prefixed_configuration()
251+
{
252+
$c = new Configuration($this->getConfigurationItems());
253+
$c->prefix('database.drivers.mysql', function ($partial) {
254+
$partial->set('username', 'bonnie');
255+
$partial->set('password', 'martini');
256+
$partial->add('salt', 'pepper');
257+
});
258+
259+
$this->assertEquals([
260+
'database' => 'gestalt',
261+
'username' => 'bonnie',
262+
'password' => 'martini',
263+
'salt' => 'pepper',
264+
], $c->get('database.drivers.mysql'));
265+
266+
$this->assertTrue($c->get('app.debug'));
267+
}
191268
}

0 commit comments

Comments
 (0)