Skip to content

Commit

Permalink
feat: Add possibility to recursive merge data in Context
Browse files Browse the repository at this point in the history
  • Loading branch information
Theo D committed Mar 4, 2024
1 parent b0913f6 commit 8288444
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,7 @@
* Add a `yaml_dump()` function to dump any PHP value to a YAML string
* Add a `yaml_parse()` function to parse a YAML string to a PHP value
* Remove the default timeout of 60 seconds from the Context
* Add a `recursive` parameter to the `withData()` method of `Context` to allow recursive merging for nested arrays

## 0.13.1 (2024-02-27)

Expand Down
30 changes: 26 additions & 4 deletions examples/context.php
Expand Up @@ -21,17 +21,38 @@ function defaultContext(): Context
'name' => 'my_default',
'production' => false,
'foo' => 'bar',
'nested' => [
'merge' => [
'key' => [
'value' => 'should keep this',
'replaced' => 'should be replaced',
],
'another' => 'should keep',
],
'another' => 'should keep',
],
]);
}

#[AsContext(name: 'production')]
function productionContext(): Context
{
return defaultContext()
->withData([
'name' => 'production',
'production' => true,
])
->withData(
[
'name' => 'production',
'production' => true,
'nested' => [
'merge' => [
'key' => [
'replaced' => 'replaced value',
'new' => 'new value',
],
],
],
],
recursive: true
)
;
}

Expand Down Expand Up @@ -83,6 +104,7 @@ function contextInfo(): void
echo 'Production? ' . (variable('production', false) ? 'yes' : 'no') . "\n";
echo "verbosity: {$context->verbosityLevel->value}\n";
echo 'context: ' . variable('foo', 'N/A') . "\n";
echo 'nested merge recursive: ' . json_encode(variable('nested', []), \JSON_THROW_ON_ERROR) . "\n";
}

/**
Expand Down
45 changes: 42 additions & 3 deletions src/Context.php
Expand Up @@ -45,11 +45,29 @@ public function __debugInfo()
];
}

/** @param array<(int|string), mixed> $data */
public function withData(array $data, bool $keepExisting = true): self
/**
* @param array<(int|string), mixed> $data
*
* @throws \Exception
*/
public function withData(array $data, bool $keepExisting = true, bool $recursive = true): self
{
if (false === $keepExisting && true === $recursive) {
throw new \Exception('You cannot use the recursive option without keeping the existing data');
}

if ($keepExisting) {
if ($recursive) {
/* @var array<(int|string), mixed> */
$data = $this->arrayMergeRecursiveDistinct($this->data, $data);
} else {
/* @var array<(int|string), mixed> */
$data = array_merge($this->data, $data);
}
}

return new self(
$keepExisting ? array_merge($this->data, $data) : $data,
$data,
$this->environment,
$this->currentDirectory,
$this->tty,
Expand Down Expand Up @@ -257,4 +275,25 @@ public function offsetUnset(mixed $offset): void
{
throw new \LogicException('Context is immutable');
}

/**
* @param array<(int|string), mixed> $array1
* @param array<(int|string), mixed> $array2
*
* @return array<(int|string), mixed>
*/
private function arrayMergeRecursiveDistinct(array $array1, array $array2): array
{
/** @var array<(int|string), mixed> $merged */
$merged = $array1;
foreach ($array2 as $key => $value) {
if (\is_array($value) && isset($merged[$key]) && \is_array($merged[$key])) {
$merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value);
} else {
$merged[$key] = $value;
}
}

return $merged;
}
}
Expand Up @@ -2,3 +2,4 @@ context name: dynamic
Production? no
verbosity: 1
context: baz
nested merge recursive: []
Expand Up @@ -2,3 +2,4 @@ context name: my_default
Production? no
verbosity: 2
context: bar
nested merge recursive: {"merge":{"key":{"value":"should keep this","replaced":"should be replaced"},"another":"should keep"},"another":"should keep"}
Expand Up @@ -2,3 +2,4 @@ context name: path
Production? yes
verbosity: 1
context: bar
nested merge recursive: []
Expand Up @@ -2,3 +2,4 @@ context name: production
Production? yes
verbosity: 1
context: bar
nested merge recursive: {"merge":{"key":{"value":"should keep this","replaced":"replaced value","new":"new value"},"another":"should keep"},"another":"should keep"}
Expand Up @@ -2,3 +2,4 @@ context name: run
Production? no
verbosity: 1
context: no defined
nested merge recursive: []
1 change: 1 addition & 0 deletions tests/Examples/Generated/ContextContextTest.php.output.txt
Expand Up @@ -2,3 +2,4 @@ context name: my_default
Production? no
verbosity: 1
context: bar
nested merge recursive: {"merge":{"key":{"value":"should keep this","replaced":"should be replaced"},"another":"should keep"},"another":"should keep"}
Expand Up @@ -2,4 +2,5 @@ context name: dynamic
Production? no
verbosity: -1
context: bar
nested merge recursive: []
bar

0 comments on commit 8288444

Please sign in to comment.