Skip to content

Commit d74d2da

Browse files
authored
Merge pull request #97 from weierophinney/feature/configure-replacements
Allow configuration of additional replacements
2 parents f53849b + a1479a9 commit d74d2da

File tree

4 files changed

+200
-4
lines changed

4 files changed

+200
-4
lines changed

README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,52 @@ Run the following to install this library:
4444
$ composer require laminas/laminas-zendframework-bridge
4545
```
4646

47+
## Configuration
48+
49+
- Since 1.6.0
50+
51+
You may provide additional replacements for the configuration post processor.
52+
This is particularly useful if your application uses third-party components that include class names that the post processor otherwise rewrites, and which you want to never rewrite.
53+
54+
Configuration is via the following structure:
55+
56+
```php
57+
return [
58+
'laminas-zendframework-bridge' => [
59+
'replacements' => [
60+
'to-replace' => 'replacement',
61+
// ...
62+
],
63+
],
64+
];
65+
```
66+
67+
As an example, if your configuration included the following dependency mapping:
68+
69+
```php
70+
return [
71+
'controller_plugins' => [
72+
'factories' => [
73+
'customZendFormBinder' => \CustomZendFormBinder\Controller\Plugin\Factory\BinderPluginFactory::class,
74+
],
75+
],
76+
];
77+
```
78+
79+
And you wanted the two strings that contain the verbiage `ZendForm` to remain untouched, you could define the following replacements mapping:
80+
81+
```php
82+
return [
83+
'laminas-zendframework-bridge' => [
84+
'replacements' => [
85+
// Never rewrite!
86+
'customZendFormBinder' => 'customZendFormBinder',
87+
'CustomZendFormBinder' => 'CustomZendFormBinder',
88+
],
89+
],
90+
];
91+
```
92+
4793
## Support
4894

4995
* [Issues](https://github.com/laminas/laminas-zendframework-bridge/issues/)

psalm-baseline.xml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="4.21.0@d8bec4c7aaee111a532daec32fb09de5687053d1">
2+
<files psalm-version="4.9.3@4c262932602b9bbab5020863d1eb22d49de0dbf4">
33
<file src="config/replacements.php">
44
<DuplicateArrayKey occurrences="3">
55
<code>'ZendAcl' =&gt; 'LaminasAcl'</code>
@@ -8,7 +8,10 @@
88
</DuplicateArrayKey>
99
</file>
1010
<file src="src/Autoloader.php">
11-
<MixedArgumentTypeCoercion occurrences="2"/>
11+
<MixedArgumentTypeCoercion occurrences="2">
12+
<code>RewriteRules::namespaceReverse()</code>
13+
<code>RewriteRules::namespaceRewrite()</code>
14+
</MixedArgumentTypeCoercion>
1215
</file>
1316
<file src="src/ConfigPostProcessor.php">
1417
<InvalidArgument occurrences="1">
@@ -59,7 +62,7 @@
5962
<MixedArrayTypeCoercion occurrences="1">
6063
<code>$aliases[$name]</code>
6164
</MixedArrayTypeCoercion>
62-
<MixedAssignment occurrences="25">
65+
<MixedAssignment occurrences="27">
6366
<code>$a[$key]</code>
6467
<code>$a[$key]</code>
6568
<code>$a[]</code>
@@ -75,9 +78,11 @@
7578
<code>$key</code>
7679
<code>$name</code>
7780
<code>$newKey</code>
81+
<code>$newValue</code>
7882
<code>$notIn[]</code>
7983
<code>$result</code>
8084
<code>$rewritten[$key]</code>
85+
<code>$rewritten[$key]</code>
8186
<code>$rewritten[$newKey]</code>
8287
<code>$rewritten[$newKey][]</code>
8388
<code>$serviceInstance</code>

src/ConfigPostProcessor.php

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Laminas\ZendFrameworkBridge;
44

5+
use RuntimeException;
6+
57
use function array_intersect_key;
68
use function array_key_exists;
79
use function array_pop;
@@ -35,6 +37,7 @@ class ConfigPostProcessor
3537

3638
public function __construct()
3739
{
40+
// This value will be reset during __invoke(); setting here to prevent Psalm errors.
3841
$this->replacements = new Replacements();
3942

4043
/* Define the rulesets for replacements.
@@ -96,9 +99,16 @@ function ($value, array $keys) {
9699
*/
97100
public function __invoke(array $config, array $keys = [])
98101
{
99-
$rewritten = [];
102+
$this->replacements = $this->initializeReplacements($config);
103+
$rewritten = [];
100104

101105
foreach ($config as $key => $value) {
106+
// Do not rewrite configuration for the bridge
107+
if ($key === 'laminas-zendframework-bridge') {
108+
$rewritten[$key] = $value;
109+
continue;
110+
}
111+
102112
// Determine new key from replacements
103113
$newKey = is_string($key) ? $this->replace($key, $keys) : $key;
104114

@@ -423,4 +433,32 @@ private function replaceDependencyServices(array $config)
423433

424434
return $config;
425435
}
436+
437+
private function initializeReplacements(array $config): Replacements
438+
{
439+
$replacements = $config['laminas-zendframework-bridge']['replacements'] ?? [];
440+
if (! is_array($replacements)) {
441+
throw new RuntimeException(sprintf(
442+
'Invalid laminas-zendframework-bridge.replacements configuration;'
443+
. ' value MUST be an array; received %s',
444+
is_object($replacements) ? get_class($replacements) : gettype($replacements)
445+
));
446+
}
447+
448+
foreach ($replacements as $lookup => $replacement) {
449+
if (
450+
! is_string($lookup)
451+
|| ! is_string($replacement)
452+
|| preg_match('/^\s*$/', $lookup)
453+
|| preg_match('/^\s*$/', $replacement)
454+
) {
455+
throw new RuntimeException(
456+
'Invalid lookup or replacement in laminas-zendframework-bridge.replacements configuration;'
457+
. ' all keys and values MUST be non-empty strings.'
458+
);
459+
}
460+
}
461+
462+
return new Replacements($replacements);
463+
}
426464
}

test/ConfigPostProcessorTest.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Laminas\ZendFrameworkBridge\ConfigPostProcessor;
66
use PHPUnit\Framework\TestCase;
7+
use RuntimeException;
78
use stdClass;
89

910
use function sprintf;
@@ -137,4 +138,110 @@ public function invalidServiceManagerConfiguration()
137138
],
138139
];
139140
}
141+
142+
public function testWillUseReplacementsFromConfigurationWhenPresent(): void
143+
{
144+
$config = [
145+
'laminas-zendframework-bridge' => [
146+
'replacements' => [
147+
'MyFoo' => 'YourFoo',
148+
'MyBar' => 'SomeBar',
149+
],
150+
],
151+
'dependencies' => [
152+
'factories' => [
153+
'MyFoo' => 'MyBar',
154+
'Zend\Cache\MyClass' => 'My\Factory\For\Caching',
155+
'ShouldNotRewrite' => 'My\Factory\ShouldNotRewrite',
156+
],
157+
],
158+
];
159+
160+
$expected = [
161+
'laminas-zendframework-bridge' => [
162+
'replacements' => [
163+
'MyFoo' => 'YourFoo',
164+
'MyBar' => 'SomeBar',
165+
],
166+
],
167+
'dependencies' => [
168+
'factories' => [
169+
'YourFoo' => 'SomeBar',
170+
'Laminas\Cache\MyClass' => 'My\Factory\For\Caching',
171+
'ShouldNotRewrite' => 'My\Factory\ShouldNotRewrite',
172+
],
173+
'aliases' => [
174+
'MyFoo' => 'YourFoo',
175+
'Zend\Cache\MyClass' => 'Laminas\Cache\MyClass',
176+
],
177+
],
178+
];
179+
180+
$processor = new ConfigPostProcessor();
181+
$result = $processor($config);
182+
183+
$this->assertEquals($expected, $result);
184+
}
185+
186+
/** @psalm-return iterable<string, array{0: array, 1: string}> */
187+
public function invalidReplacementsConfiguration(): iterable
188+
{
189+
yield 'non-array-value' => [
190+
['laminas-zendframework-bridge' => ['replacements' => new stdClass()]],
191+
'MUST be an array',
192+
];
193+
194+
yield 'empty-key' => [
195+
['laminas-zendframework-bridge' => ['replacements' => [
196+
'' => 'Laminas\FooBar',
197+
]]],
198+
'MUST be non-empty strings',
199+
];
200+
201+
yield 'whitespace-key' => [
202+
['laminas-zendframework-bridge' => ['replacements' => [
203+
" \t\n" => 'Laminas\FooBar',
204+
]]],
205+
'MUST be non-empty strings',
206+
];
207+
208+
yield 'integer-key' => [
209+
['laminas-zendframework-bridge' => ['replacements' => [
210+
1 => 'Laminas\FooBar',
211+
]]],
212+
'MUST be non-empty strings',
213+
];
214+
215+
yield 'non-string-value' => [
216+
['laminas-zendframework-bridge' => ['replacements' => [
217+
'Zend' => new stdClass(),
218+
]]],
219+
'MUST be non-empty strings',
220+
];
221+
222+
yield 'empty-value' => [
223+
['laminas-zendframework-bridge' => ['replacements' => [
224+
'Zend' => '',
225+
]]],
226+
'MUST be non-empty strings',
227+
];
228+
229+
yield 'whitespace-value' => [
230+
['laminas-zendframework-bridge' => ['replacements' => [
231+
'Zend' => " \t\n",
232+
]]],
233+
'MUST be non-empty strings',
234+
];
235+
}
236+
237+
/** @dataProvider invalidReplacementsConfiguration */
238+
public function testInvalidReplacementsConfigurationWillResultInExceptions(
239+
array $config,
240+
string $expectedExceptionMessage
241+
): void {
242+
$processor = new ConfigPostProcessor();
243+
$this->expectException(RuntimeException::class);
244+
$this->expectExceptionMessage($expectedExceptionMessage);
245+
$processor($config);
246+
}
140247
}

0 commit comments

Comments
 (0)