Skip to content

Commit

Permalink
add ConfiguresAppFromConfigManager
Browse files Browse the repository at this point in the history
  • Loading branch information
klimov-paul committed May 26, 2023
1 parent 42d60fa commit 8ea7fda
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 5 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "yii1tech/config",
"description": "Provides support for Yii2 application runtime configuration",
"description": "Provides support for Yii1 application runtime configuration",
"keywords": ["yii1", "configuration", "config", "runtime", "persistent", "database"],
"license": "BSD-3-Clause",
"support": {
Expand Down
107 changes: 107 additions & 0 deletions src/ConfiguresAppFromConfigManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

namespace yii1tech\config;

use CApplication;
use CBehavior;
use CEvent;
use CLogger;
use LogicException;
use Yii;

/**
* Configures (re-configures) application using data acquired from configuration manager.
*
* Application configuration example:
*
* ```php
* [
* 'behaviors' => [
* 'configFromManagerBehavior' => [
* 'class' => yii1tech\config\ConfiguresAppFromConfigManager::class,
* ],
* // ...
* ],
* 'components' => [
* 'appConfigManager' => [
* 'class' => yii1tech\config\Manager::class,
* 'items' => [
* // ...
* ],
* ],
* // ...
* ],
* // ...
* ];
* ```
*
* @see \yii1tech\config\Manager
*
* @mixin \CApplication
*
* @author Paul Klimov <[email protected]>
* @since 1.0
*/
class ConfiguresAppFromConfigManager extends CBehavior
{
/**
* @var \yii1tech\config\Manager|string config manager instance or its ID inside application components.
*/
public $configManager = 'appConfigManager';

/**
* @param \CApplication $app application instance to be configured.
* @return \yii1tech\config\Manager config manager instance.
* @throws \LogicException on failure
*/
protected function getConfigManager(CApplication $app)
{
if (is_object($this->configManager)) {
return $this->configManager;
}

$configManager = $app->getComponent($this->configManager);
if (!is_object($configManager)) {
throw new LogicException('Application component "' . $this->configManager . '" is missing.');
}

return $configManager;
}

/**
* {@inheritdoc}
*/
public function events(): array
{
return [
'onBeginRequest' => 'beginRequest',
];
}

/**
* This event raises before {@link CApplication}.
* It update {@link CApplication::params} with database data.
* @param CEvent $event event object.
*/
public function beginRequest(CEvent $event): void
{
$this->configureApplication($event->sender);
}

/**
* Updates application configuration from config manager.
* @param \CApplication $app application instance to be configured.
*/
protected function configureApplication(CApplication $app): void
{
try {
$app->configure($this->getConfigManager($app)->fetchConfig());
} catch (\Exception $exception) {
// application can be run before the persistent storage is ready, for example: before the first DB migration applied
Yii::log(
'"' . get_class($this) . '" is unable to update application configuration from config manager:' . $exception->getMessage(),
CLogger::LEVEL_WARNING
);
}
}
}
6 changes: 4 additions & 2 deletions src/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* ```php
* [
* 'components' => [
* 'configManager' => [
* 'appConfigManager' => [
* 'class' => yii1tech\config\Manager::class,
* 'items' => [
* 'appName' => [
Expand All @@ -36,8 +36,9 @@
* ],
* ],
* ],
* ...
* // ...
* ],
* // ...
* ];
* ```
*
Expand All @@ -51,6 +52,7 @@
*
* @see \yii1tech\config\Item
* @see \yii1tech\config\Storage
* @see \yii1tech\config\ConfiguresAppFromConfigManager
*
* @property array[]|\yii1tech\config\Item[]|string[] $items public alias of {@see _items}.
* @property \yii1tech\config\Storage|array $storage public alias of {@see _storage}.
Expand Down
47 changes: 47 additions & 0 deletions src/StorageArray.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace yii1tech\config;

/**
* StorageArray uses internal array for the config storage.
*
* This class can be useful in unit tests.
*
* @author Paul Klimov <[email protected]>
* @since 1.0
*/
class StorageArray extends Storage
{
/**
* @var array stored data.
*/
protected $data = [];

/**
* {@inheritdoc}
*/
public function save(array $values): bool
{
$this->data = array_merge($this->data, $values);

return true;
}

/**
* {@inheritdoc}
*/
public function get(): array
{
return $this->data;
}

/**
* {@inheritdoc}
*/
public function clear(): bool
{
$this->data = [];

return true;
}
}
66 changes: 66 additions & 0 deletions tests/ConfiguresAppFromConfigManagerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace yii1tech\config\test;

use Yii;
use yii1tech\config\ConfiguresAppFromConfigManager;
use yii1tech\config\Manager;
use yii1tech\config\StorageArray;

class ConfiguresAppFromConfigManagerTest extends TestCase
{
protected function createConfigManager(): Manager
{
return (new Manager())
->setStorage($this->createStorage())
->setItems([
'appName' => [
'path' => 'name',
],
'dateFormat' => [
'path' => 'components.format.dateFormat',
],
'existingParam' => [
'path' => 'params.param1',
],
'newParam' => [
'path' => 'params.paramNew',
],
]);
}

protected function createStorage(): StorageArray
{
$storage = new StorageArray();

$storage->save([
'appName' => 'app-name-override',
'dateFormat' => 'date-format-override',
'existingParam' => 'param1-override',
'newParam' => 'param-new-value',
]);

return $storage;
}

public function testConfigureApplication(): void
{
$app = Yii::app();

$app->setComponent('appConfigManager', $this->createConfigManager());

$behavior = new ConfiguresAppFromConfigManager();

$app->attachBehavior('test', $behavior);

$app->run();

$this->assertSame('app-name-override', $app->name);

$this->assertSame('param1-override', $app->params['param1']);
$this->assertSame('param2-value', $app->params['param2']);
$this->assertSame('param-new-value', $app->params['paramNew']);

$this->assertSame('date-format-override', $app->getFormat()->dateFormat);
}
}
14 changes: 14 additions & 0 deletions tests/DummyApplication.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace yii1tech\config\test;

class DummyApplication extends \CApplication
{
/**
* {@inheritdoc}
*/
public function processRequest()
{
// do nothing
}
}
75 changes: 75 additions & 0 deletions tests/StorageArrayTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

namespace yii1tech\config\test;

use yii1tech\config\StorageArray;

class StorageArrayTest extends TestCase
{
/**
* @var \Illuminatech\Config\StorageDb test storage.
*/
protected $storage;

/**
* {@inheritdoc}
*/
public function setUp(): void
{
parent::setUp();

$this->storage = new StorageArray();
}

public function testSave()
{
$values = [
'test.name' => 'Test name',
'test.title' => 'Test title',
];

$this->storage->save($values);

$returnedValues = $this->storage->get();

$this->assertEquals($values, $returnedValues);
}

/**
* @depends testSave
*/
public function testUpdate()
{
$values = [
'test.name' => 'Origin name',
'test.title' => 'Origin title',
];

$this->storage->save($values);

$this->storage->save([
'test.title' => 'Updated title'
]);

$returnedValues = $this->storage->get();

$this->assertSame('Updated title', $returnedValues['test.title']);
$this->assertSame('Origin name', $returnedValues['test.name']);
}

/**
* @depends testSave
*/
public function testClear()
{
$values = [
'test.name' => 'Test name',
'test.title' => 'Test title',
];

$this->storage->save($values);
$this->storage->clear();

$this->assertEmpty($this->storage->get());
}
}
10 changes: 8 additions & 2 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace yii1tech\config\test;

use CConsoleApplication;
use CMap;
use Yii;

Expand Down Expand Up @@ -32,7 +31,7 @@ protected function tearDown(): void
* @param array $config The application configuration, if needed
* @param string $appClass name of the application class to create
*/
protected function mockApplication($config = [], $appClass = CConsoleApplication::class)
protected function mockApplication($config = [], $appClass = DummyApplication::class)
{
Yii::setApplication(null);

Expand All @@ -47,7 +46,14 @@ protected function mockApplication($config = [], $appClass = CConsoleApplication
'cache' => [
'class' => \CDummyCache::class,
],
'format' => [
'dateFormat' => 'Y-m-d',
],
],
'params' => [
'param1' => 'param1-value',
'param2' => 'param2-value',
]
], $config));
}

Expand Down

0 comments on commit 8ea7fda

Please sign in to comment.