Skip to content

Commit

Permalink
Merge e10de60 into 3d1b1b3
Browse files Browse the repository at this point in the history
  • Loading branch information
weierophinney committed Nov 5, 2019
2 parents 3d1b1b3 + e10de60 commit 0082770
Show file tree
Hide file tree
Showing 28 changed files with 1,419 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.phpunit.result.cache
/composer.lock
/docs/html/
/vendor/
Expand Down
4 changes: 0 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ env:

matrix:
include:
- php: 5.3
dist: precise
- php: 5.4
- php: 5.5
- php: 5.6
- php: 7.0
- php: 7.1
Expand Down
16 changes: 10 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
"forum": "https://discourse.laminas.dev/"
},
"require": {
"php": "^5.3 || ^7.0"
"php": "^5.6 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.1"
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1"
},
"autoload": {
"files": [
Expand All @@ -34,15 +34,19 @@
"test/classes.php"
],
"psr-4": {
"LaminasTest\\ZendFrameworkBridge\\": "test//",
"Apigility\\": "test//TestAsset//Apigility//",
"Expressive\\": "test//TestAsset//Expressive//",
"Laminas\\": "test//TestAsset//Laminas//"
"LaminasTest\\ZendFrameworkBridge\\": "test/",
"LaminasTest\\ZendFrameworkBridge\\TestAsset\\": "test/TestAsset/classes/",
"Apigility\\": "test/TestAsset/Apigility/",
"Expressive\\": "test/TestAsset/Expressive/",
"Laminas\\": "test/TestAsset/Laminas/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
},
"laminas": {
"module": "Laminas\\ZendFrameworkBridge"
}
},
"config": {
Expand Down
379 changes: 379 additions & 0 deletions config/replacements.php

Large diffs are not rendered by default.

208 changes: 208 additions & 0 deletions src/ConfigPostProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
<?php
/**
* @see https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
* @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
* @license https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
*/

namespace Laminas\ZendFrameworkBridge;

class ConfigPostProcessor
{
/** @var array String keys => string values */
private $exactReplacements = [
'zend-expressive' => 'expressive',
'zf-apigility' => 'apigility',
];

/** @var Replacements */
private $replacements;

/** @var callable[] */
private $rulesets;

public function __construct()
{
$this->replacements = new Replacements();

// Define the rulesets for replacements.
// Each rulest receives the value being rewritten, and the key, if any.
// It then returns either null (no match), or a callable (match).
// A returned callable is then used to perform the replacement.
$this->rulesets = [
// Exact values
function ($value) {
return is_string($value) && isset($this->exactReplacements[$value])
? [$this, 'replaceExactValue']
: null;
},

// Aliases
function ($value, $key) {
return $key === 'aliases' && is_array($value)
? [$this, 'replaceDependencyAliases']
: null;
},

// Array values
function ($value, $key) {
return null !== $key && is_array($value)
? [$this, '__invoke']
: null;
},
];
}

/**
* @return array
*/
public function __invoke(array $config)
{
$rewritten = [];

foreach ($config as $key => $value) {
$newKey = is_string($key) ? $this->replace($key) : $key;
$newValue = $this->replace($value, $newKey);

// Key does not already exist and/or is not an array value
if (! array_key_exists($newKey, $rewritten) || ! is_array($rewritten[$newKey])) {
// Do not overwrite existing values with null values
$rewritten[$newKey] = array_key_exists($newKey, $rewritten) && null === $newValue
? $rewritten[$newKey]
: $newValue;
continue;
}

// New value is null; nothing to do.
if (null === $newValue) {
continue;
}

// Key already exists as an array value, but $value is not an array
if (! is_array($newValue)) {
$rewritten[$newKey][] = $newValue;
continue;
}

// Key already exists as an array value, and $value is also an array
$rewritten[$newKey] = static::merge($rewritten[$newKey], $newValue);
}

return $rewritten;
}

/**
* Perform substitutions as needed on an individual value.
*
* The $key is provided to allow fine-grained selection of rewrite rules.
*
* @param mixed $value
* @param null|int|string $key
* @return mixed
*/
private function replace($value, $key = null)
{
$rewriteRule = $this->replacementRuleMatch($value, $key);
return $rewriteRule($value);
}

/**
* Merge two arrays together.
*
* If an integer key exists in both arrays, the value from the second array
* will be appended to the first array. If both values are arrays, they are
* merged together, else the value of the second array overwrites the one
* of the first array.
*
* Based on zend-stdlib Zend\Stdlib\ArrayUtils::merge
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
*
* @param array $a
* @param array $b
* @return array
*/
public static function merge(array $a, array $b)
{
foreach ($b as $key => $value) {
if (! isset($a[$key]) && ! array_key_exists($key, $a)) {
$a[$key] = $value;
continue;
}

if (null === $value && array_key_exists($key, $a)) {
// Leave as-is if value from $b is null
continue;
}

if (is_int($key)) {
$a[] = $value;
continue;
}

if (is_array($value) && is_array($a[$key])) {
$a[$key] = static::merge($a[$key], $value);
continue;
}

$a[$key] = $value;
}

return $a;
}

/**
* @param mixed $value
* @param null|int|string $key
* @return callable Callable to invoke with value
*/
private function replacementRuleMatch($value, $key = null)
{
foreach ($this->rulesets as $ruleset) {
$result = $ruleset($value, $key);
if (is_callable($result)) {
return $result;
}
}
return [$this, 'fallbackReplacement'];
}

/**
* Replace a value using the translation table, if the value is a string.
*
* @param mixed $value
* @return mixed
*/
private function fallbackReplacement($value)
{
return is_string($value)
? $this->replacements->replace($value)
: $value;
}

/**
* Replace a value matched exactly.
*
* @param mixed $value
* @return mixed
*/
private function replaceExactValue($value)
{
return $this->exactReplacements[$value];
}

/**
* Rewrite dependency aliases array
*
* In this case, we want to keep the alias as-is, but rewrite the target.
*
* @param array $value
* @return array
*/
private function replaceDependencyAliases(array $aliases)
{
foreach ($aliases as $alias => $target) {
$aliases[$alias] = $this->replacements->replace($target);
}
return $aliases;
}
}
53 changes: 53 additions & 0 deletions src/Module.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
/**
* @see https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
* @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
* @license https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
*/

namespace Laminas\ZendFrameworkBridge;

use Laminas\ModuleManager\Listener\ConfigMergerInterface;
use Laminas\ModuleManager\ModuleEvent;
use Laminas\ModuleManager\ModuleManager;

class Module
{
/**
* Initialize the module.
*
* Type-hinting deliberately omitted to allow unit testing
* without dependencies on packages that do not exist yet.
*
* @param ModuleManager $moduleManager
*/
public function init($moduleManager)
{
$moduleManager
->getEventManager()
->attach('mergeConfig', [$this, 'onMergeConfig']);
}

/**
* Perform substitutions in the merged configuration.
*
* Rewrites keys and values matching known ZF classes, namespaces, and
* configuration keys to their Laminas equivalents.
*
* Type-hinting deliberately omitted to allow unit testing
* without dependencies on packages that do not exist yet.
*
* @param ModuleEvent $moduleEvent
*/
public function onMergeConfig($event)
{
/** @var ConfigMergerInterface */
$configMerger = $event->getConfigListener();
$processor = new ConfigPostProcessor();
$configMerger->setMergedConfig(
$processor(
$configMerger->getMergedConfig($returnAsObject = false)
)
);
}
}
31 changes: 31 additions & 0 deletions src/Replacements.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/**
* @see https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
* @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
* @license https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
*/

namespace Laminas\ZendFrameworkBridge;

class Replacements
{
/** @var string[] */
private $replacements;

public function __construct(array $additionalReplacements = [])
{
$this->replacements = array_merge(
require __DIR__ . '/../config/replacements.php',
$additionalReplacements
);
}

/**
* @param string $value
* @return string
*/
public function replace($value)
{
return strtr($value, $this->replacements);
}
}
41 changes: 41 additions & 0 deletions test/ConfigPostProcessorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
/**
* @see https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
* @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
* @license https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
*/

namespace LaminasTest\ZendFrameworkBridge;

use Laminas\ZendFrameworkBridge\ConfigPostProcessor;
use PHPUnit\Framework\TestCase;

class ConfigPostProcessorTest extends TestCase
{
/**
* @return iterable
*/
public function configurations()
{
yield 'Acelaya Expressive Slim Router' => ['ExpressiveSlimRouterConfig.php'];
yield 'mwop.net App module config' => ['MwopNetAppConfig.php'];
yield 'cyclical aliasing' => ['CyclicalAliasing.php'];
yield 'unknown Expressive config' => ['UnknownExpressiveConfiguration.php'];
yield 'equivalent key merging' => ['MergeEquivalentKeys.php'];
}

/**
* @dataProvider configurations
* @param string $configFile
*/
public function testRewritesNestedKeys($configFile)
{
$configLocation = sprintf('%s/TestAsset/ConfigPostProcessor/%s', __DIR__, $configFile);
$expectedResultLocation = $configLocation . '.out';
$config = require $configLocation;
$expected = require $expectedResultLocation;
$processor = new ConfigPostProcessor();

$this->assertSame($expected, $processor($config));
}
}

0 comments on commit 0082770

Please sign in to comment.