Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/Contracts/ConfigWriterContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,22 @@ public function preview($key, $value);
* @return string
*/
public function previewMany($configNamespace, array $values);

/**
* Replaces multiple configuration values in a namespace, overwriting existing values including function calls.
*
* @param string $configNamespace The configuration namespace.
* @param array $values The key/value pairs to replace.
* @return bool
*/
public function replaceMany(string $configNamespace, array $values): bool;

/**
* Applies many replacements to a source configuration document and returns the modified document without writing.
*
* @param string $configNamespace The root configuration namespace.
* @param array $values The key/value mapping of all replacements.
* @return string
*/
public function previewReplaceMany(string $configNamespace, array $values): string;
}
46 changes: 46 additions & 0 deletions src/LaravelConfigWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,52 @@ public function writeMany($configNamespace, array $values)
return true;
}

/**
* Replaces multiple configuration values, overwriting existing values including function calls.
*
* Unlike writeMany(), which preserves function calls (e.g. env()) by default, replaceMany()
* performs a direct node swap for each key regardless of the existing value type.
*
* @param string $configNamespace The configuration namespace.
* @param array $values The key/value pairs to replace.
* @return bool
*
* @throws ConfigNotFoundException
* @throws ConfigNotWriteableException
* @throws GuardedConfigurationMutationException
*/
public function replaceMany(string $configNamespace, array $values): bool
{
$wrapper = $this->edit($configNamespace);

foreach ($values as $key => $value) {
$wrapper->replace($key, $value);
}

return $wrapper->save();
}

/**
* Applies many replacements to a source configuration document and returns the modified document without writing.
*
* @param string $configNamespace The root configuration namespace.
* @param array $values The key/value mapping of all replacements.
* @return string
*
* @throws ConfigNotFoundException
* @throws GuardedConfigurationMutationException
*/
public function previewReplaceMany(string $configNamespace, array $values): string
{
$wrapper = $this->edit($configNamespace);

foreach ($values as $key => $value) {
$wrapper->replace($key, $value);
}

return $wrapper->preview();
}

/**
* Checks all requested changes against any restricted configuration levels.
*
Expand Down
23 changes: 23 additions & 0 deletions tests/FuncCallReplacementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@ public function testReplacingExistingFuncCallWithDifferentFuncCall(): void
* ConfigWriter::ignoreFunctionCalls(false) actually takes effect when
* going through the edit()->set()->save() path.
*/
/**
* Confirms that issue #29 is NOT closed by PR #39.
*
* With ignoreFunctions=true (default, used by writeMany), plain values cannot replace
* existing FuncCall values — the FuncCall is preserved. Closing issue #29 would require
* a dedicated API change (e.g. using replace() instead of update()).
*/
public function testIssue29FuncCallValuesAreStillPreservedWhenPassingPlainValues(): void
{
$updater = new ConfigUpdater(); // ignoreFunctions=true by default — same path as writeMany
$updater->open(__DIR__.'/configs/issue29.php');
$updater->update([
'enabled' => true,
'route' => 'my-cp',
'start_page' => 'collections/pages',
]);

$expected = Transformer::normalizeLineEndings(
file_get_contents(__DIR__.'/expected/issue29.php')
);
$this->assertEquals($expected, $updater->getDocument());
}

public function testGetUpdaterPassesIgnoreFunctionsToConfigUpdater(): void
{
// Copy the fixture before constructing LaravelConfigWriter — it scans configPath() on construction.
Expand Down
76 changes: 76 additions & 0 deletions tests/ReplaceManyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace Stillat\Proteus\Tests;

use Stillat\Proteus\ConfigUpdater;
use Stillat\Proteus\Document\Transformer;
use Stillat\Proteus\LaravelConfigWriter;

class ReplaceManyTest extends ProteusTestCase
{
public function testReplaceManyMechanismViaConfigUpdater(): void
{
$updater = new ConfigUpdater();
$updater->open(__DIR__.'/configs/issue29.php');

foreach (['enabled' => true, 'route' => 'my-cp', 'start_page' => 'collections/pages'] as $k => $v) {
$updater->replace($k, $v);
}

$expected = Transformer::normalizeLineEndings(
file_get_contents(__DIR__.'/expected/replaceMany_issue29.php')
);
$this->assertEquals($expected, $updater->getDocument());
}

public function testReplaceManyWritesToDisk(): void
{
$configPath = $this->app->configPath();
$fixture = $configPath.'/issue29_replace.php';
copy(__DIR__.'/configs/issue29.php', $fixture);

try {
$writer = new LaravelConfigWriter($this->app, $this->app['config']);
$writer->replaceMany('issue29_replace', [
'enabled' => true,
'route' => 'my-cp',
'start_page' => 'collections/pages',
]);

$expected = Transformer::normalizeLineEndings(
file_get_contents(__DIR__.'/expected/replaceMany_issue29.php')
);
$this->assertEquals($expected, Transformer::normalizeLineEndings(file_get_contents($fixture)));
} finally {
@unlink($fixture);
}
}

public function testPreviewReplaceManyDoesNotWriteToDisk(): void
{
$configPath = $this->app->configPath();
$fixture = $configPath.'/issue29_preview.php';
$originalContent = file_get_contents(__DIR__.'/configs/issue29.php');
file_put_contents($fixture, $originalContent);

try {
$writer = new LaravelConfigWriter($this->app, $this->app['config']);
$document = $writer->previewReplaceMany('issue29_preview', [
'enabled' => true,
'route' => 'my-cp',
'start_page' => 'collections/pages',
]);

$expected = Transformer::normalizeLineEndings(
file_get_contents(__DIR__.'/expected/replaceMany_issue29.php')
);
$this->assertEquals($expected, Transformer::normalizeLineEndings($document));
$this->assertEquals(
Transformer::normalizeLineEndings($originalContent),
Transformer::normalizeLineEndings(file_get_contents($fixture))
);
} finally {
@unlink($fixture);
}
}
}
7 changes: 7 additions & 0 deletions tests/configs/issue29.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

return [
'enabled' => env('CP_ENABLED', true),
'route' => env('CP_ROUTE', 'cp'),
'start_page' => 'dashboard',
];
7 changes: 7 additions & 0 deletions tests/expected/issue29.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

return [
'enabled' => env('CP_ENABLED', true),
'route' => env('CP_ROUTE', 'cp'),
'start_page' => 'collections/pages',
];
7 changes: 7 additions & 0 deletions tests/expected/replaceMany_issue29.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

return [
'enabled' => true,
'route' => 'my-cp',
'start_page' => 'collections/pages',
];