Skip to content

Commit

Permalink
Merge pull request #10312 from creative-commoners/pulls/4.11/injector
Browse files Browse the repository at this point in the history
ENH Allow multiple backtick variables in a single value
  • Loading branch information
GuySartorelli authored May 12, 2022
2 parents 62bf312 + 6a779d0 commit 0866317
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 10 deletions.
7 changes: 5 additions & 2 deletions docs/en/00_Getting_Started/03_Environment_Management.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,16 @@ Environment::setEnv('API_KEY', 'AABBCCDDEEFF012345');

### Using environment variables in config

To use environment variables in `.yaml` configs you can reference them using backticks.
To use environment variables in `.yaml` configs you can reference them using backticks. You can have multiple
environment variables within a single value, though the overall value must start and end with backticks.

```yaml
SilverStripe\Core\Injector\Injector:
MyServiceClass:
properties:
MyProperty: '`ENV_VAR_HERE`'
MyProperty: '`ENV_VAR_ONE`'
MultiValueProperty: '`ENV_VAR_ONE`:`ENV_VAR_TWO`'
ThisWillNotSubstitute: 'lorem `REGULAR_TEXT` ipsum'
```
[info]
Expand Down
31 changes: 23 additions & 8 deletions src/Core/Injector/Injector.php
Original file line number Diff line number Diff line change
Expand Up @@ -524,16 +524,31 @@ public function convertServiceProperty($value)
}

// Evaluate constants surrounded by back ticks
if (preg_match('/^`(?<name>[^`]+)`$/', $value ?? '', $matches)) {
$envValue = Environment::getEnv($matches['name']);
if ($envValue !== false) {
$value = $envValue;
} elseif (defined($matches['name'] ?? '')) {
$value = constant($matches['name'] ?? '');
} else {
$value = null;
$hasBacticks = false;
$allMissing = true;
// $value must start and end with backticks, though there can be multiple
// things being subsituted within $value e.g. "`VAR_ONE`:`VAR_TWO`:`VAR_THREE`"
if (preg_match('/^`.+`$/', $value ?? '')) {
$hasBacticks = true;
preg_match_all('/`(?<name>[^`]+)`/', $value, $matches);
foreach ($matches['name'] as $name) {
$envValue = Environment::getEnv($name);
$val = '';
if ($envValue !== false) {
$val = $envValue;
} elseif (defined($name)) {
$val = constant($name);
}
$value = str_replace("`$name`", $val, $value);
if ($val) {
$allMissing = false;
}
}
}
// silverstripe sometimes explictly expects a null value rather than just an empty string
if ($hasBacticks && $allMissing && $value === '') {
return null;
}

return $value;
}
Expand Down
27 changes: 27 additions & 0 deletions tests/php/Core/Injector/InjectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace SilverStripe\Core\Tests\Injector;

use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Environment;
use SilverStripe\Core\Injector\Factory;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Injector\InjectorNotFoundException;
Expand Down Expand Up @@ -815,6 +816,32 @@ public function testConvertServicePropertyOnCreate()
$this->assertInstanceOf(OtherTestObject::class, $item->property->property);
}

/**
* @dataProvider provideConvertServicePropertyBackTicks
*/
public function testConvertServicePropertyBackTicks($value, $expected)
{
Environment::setEnv('INJECTOR_TEST_CSP_A', 'ABC');
Environment::setEnv('INJECTOR_TEST_CSP_B', 'DEF');
Environment::setEnv('INJECTOR_TEST_CSP_C', 'GHI');
$actual = Injector::inst()->convertServiceProperty($value);
$this->assertSame($expected, $actual);
}

public function provideConvertServicePropertyBackTicks()
{
return [
['`INJECTOR_TEST_CSP_A`', 'ABC'],
['`INJECTOR_TEST_CSP_A`:`INJECTOR_TEST_CSP_B`', 'ABC:DEF'],
['`INJECTOR_TEST_CSP_A` some text `INJECTOR_TEST_CSP_B`', 'ABC some text DEF'],
['`INJECTOR_TEST_CSP_A``INJECTOR_TEST_CSP_B`', 'ABCDEF'],
['`INJECTOR_TEST_CSP_A`:`INJECTOR_TEST_CSP_B``INJECTOR_TEST_CSP_C`', 'ABC:DEFGHI'],
['`INJECTOR_TEST_CSP_A`:`INJECTOR_TEST_CSP_X`', 'ABC:'],
['`INJECTOR_TEST_CSP_X`', null],
['lorem `INJECTOR_TEST_CSP_A` ipsum', 'lorem `INJECTOR_TEST_CSP_A` ipsum'],
];
}

public function testNamedServices()
{
$injector = new Injector();
Expand Down

0 comments on commit 0866317

Please sign in to comment.