From 98e3e22896380671f74ddf2bb02a58305eae005f Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 20 Oct 2018 08:00:33 +0200 Subject: [PATCH] Moved global functions to handle array paths to a wrapper class --- module/Common/functions/functions.php | 39 --------- .../Common/src/Collection/PathCollection.php | 67 +++++++++++++++ .../test/Collection/PathCollectionTest.php | 82 +++++++++++++++++++ .../src/Model/CustomizableAppConfig.php | 19 +++-- 4 files changed, 159 insertions(+), 48 deletions(-) create mode 100644 module/Common/src/Collection/PathCollection.php create mode 100644 module/Common/test/Collection/PathCollectionTest.php diff --git a/module/Common/functions/functions.php b/module/Common/functions/functions.php index b2c5d307..e28e4fb2 100644 --- a/module/Common/functions/functions.php +++ b/module/Common/functions/functions.php @@ -4,11 +4,8 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Common; use const JSON_ERROR_NONE; -use function array_key_exists; -use function array_shift; use function getenv; use function in_array; -use function is_array; use function json_last_error; use function json_last_error_msg; use function strtolower; @@ -62,39 +59,3 @@ function json_decode(string $json, int $depth = 512, int $options = 0): array return $data; } - -function array_path_exists(array $path, array $array): bool -{ - // As soon as a step is not found, the path does not exist - $step = array_shift($path); - if (! array_key_exists($step, $array)) { - return false; - } - - // Once the path is empty, we have found all the parts in the path - if (empty($path)) { - return true; - } - - // If current value is not an array, then we have not found the path - $newArray = $array[$step]; - if (! is_array($newArray)) { - return false; - } - - return array_path_exists($path, $newArray); -} - -function array_get_path(array $path, array $array) -{ - do { - $step = array_shift($path); - if (! is_array($array) || ! array_key_exists($step, $array)) { - return null; - } - - $array = $array[$step]; - } while (! empty($path)); - - return $array; -} diff --git a/module/Common/src/Collection/PathCollection.php b/module/Common/src/Collection/PathCollection.php new file mode 100644 index 00000000..f63102e6 --- /dev/null +++ b/module/Common/src/Collection/PathCollection.php @@ -0,0 +1,67 @@ +array = $array; + } + + public function pathExists(array $path): bool + { + return $this->checkPathExists($path, $this->array); + } + + private function checkPathExists(array $path, array $array): bool + { + // As soon as a step is not found, the path does not exist + $step = array_shift($path); + if (! array_key_exists($step, $array)) { + return false; + } + + // Once the path is empty, we have found all the parts in the path + if (empty($path)) { + return true; + } + + // If current value is not an array, then we have not found the path + $newArray = $array[$step]; + if (! is_array($newArray)) { + return false; + } + + return $this->checkPathExists($path, $newArray); + } + + /** + * @return mixed + */ + public function getValueInPath(array $path) + { + $array = $this->array; + + do { + $step = array_shift($path); + if (! is_array($array) || ! array_key_exists($step, $array)) { + return null; + } + + $array = $array[$step]; + } while (! empty($path)); + + return $array; + } +} diff --git a/module/Common/test/Collection/PathCollectionTest.php b/module/Common/test/Collection/PathCollectionTest.php new file mode 100644 index 00000000..54f8c9a2 --- /dev/null +++ b/module/Common/test/Collection/PathCollectionTest.php @@ -0,0 +1,82 @@ +collection = new PathCollection([ + 'foo' => [ + 'bar' => [ + 'baz' => 'Hello world!', + ], + ], + 'something' => [], + 'another' => [ + 'one' => 'Shlink', + ], + ]); + } + + /** + * @test + * @dataProvider providePaths + */ + public function pathExistsReturnsExpectedValue(array $path, bool $expected) + { + $this->assertEquals($expected, $this->collection->pathExists($path)); + } + + public function providePaths(): array + { + return [ + [[], false], + [['boo'], false], + [['foo', 'nop'], false], + [['another', 'one', 'nop'], false], + [['foo'], true], + [['foo', 'bar'], true], + [['foo', 'bar', 'baz'], true], + [['something'], true], + ]; + } + + /** + * @test + * @dataProvider providePathsWithValue + */ + public function getValueInPathReturnsExpectedValue(array $path, $expected) + { + $this->assertEquals($expected, $this->collection->getValueInPath($path)); + } + + public function providePathsWithValue(): array + { + return [ + [[], null], + [['boo'], null], + [['foo', 'nop'], null], + [['another', 'one', 'nop'], null], + [['foo'], [ + 'bar' => [ + 'baz' => 'Hello world!', + ], + ]], + [['foo', 'bar'], [ + 'baz' => 'Hello world!', + ]], + [['foo', 'bar', 'baz'], 'Hello world!'], + [['something'], []], + ]; + } +} diff --git a/module/Installer/src/Model/CustomizableAppConfig.php b/module/Installer/src/Model/CustomizableAppConfig.php index 2e298f42..a882446c 100644 --- a/module/Installer/src/Model/CustomizableAppConfig.php +++ b/module/Installer/src/Model/CustomizableAppConfig.php @@ -3,13 +3,12 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Installer\Model; +use Shlinkio\Shlink\Common\Collection\PathCollection; use Shlinkio\Shlink\Installer\Config\Plugin\ApplicationConfigCustomizer; use Shlinkio\Shlink\Installer\Config\Plugin\DatabaseConfigCustomizer; use Shlinkio\Shlink\Installer\Config\Plugin\LanguageConfigCustomizer; use Shlinkio\Shlink\Installer\Config\Plugin\UrlShortenerConfigCustomizer; use Zend\Stdlib\ArraySerializableInterface; -use function Shlinkio\Shlink\Common\array_get_path; -use function Shlinkio\Shlink\Common\array_path_exists; final class CustomizableAppConfig implements ArraySerializableInterface { @@ -118,12 +117,14 @@ final class CustomizableAppConfig implements ArraySerializableInterface public function exchangeArray(array $array): void { + $pathCollection = new PathCollection($array); + $this->setApp($this->mapExistingPathsToKeys([ ApplicationConfigCustomizer::SECRET => ['app_options', 'secret_key'], ApplicationConfigCustomizer::DISABLE_TRACK_PARAM => ['app_options', 'disable_track_param'], ApplicationConfigCustomizer::CHECK_VISITS_THRESHOLD => ['delete_short_urls', 'check_visits_threshold'], ApplicationConfigCustomizer::VISITS_THRESHOLD => ['delete_short_urls', 'visits_threshold'], - ], $array)); + ], $pathCollection)); $this->setDatabase($this->mapExistingPathsToKeys([ DatabaseConfigCustomizer::DRIVER => ['entity_manager', 'connection', 'driver'], @@ -132,27 +133,27 @@ final class CustomizableAppConfig implements ArraySerializableInterface DatabaseConfigCustomizer::NAME => ['entity_manager', 'connection', 'dbname'], DatabaseConfigCustomizer::HOST => ['entity_manager', 'connection', 'host'], DatabaseConfigCustomizer::PORT => ['entity_manager', 'connection', 'port'], - ], $array)); + ], $pathCollection)); $this->setLanguage($this->mapExistingPathsToKeys([ LanguageConfigCustomizer::DEFAULT_LANG => ['translator', 'locale'], LanguageConfigCustomizer::CLI_LANG => ['cli', 'locale'], - ], $array)); + ], $pathCollection)); $this->setUrlShortener($this->mapExistingPathsToKeys([ UrlShortenerConfigCustomizer::SCHEMA => ['url_shortener', 'domain', 'schema'], UrlShortenerConfigCustomizer::HOSTNAME => ['url_shortener', 'domain', 'hostname'], UrlShortenerConfigCustomizer::CHARS => ['url_shortener', 'shortcode_chars'], UrlShortenerConfigCustomizer::VALIDATE_URL => ['url_shortener', 'validate_url'], - ], $array)); + ], $pathCollection)); } - private function mapExistingPathsToKeys(array $map, array $config): array + private function mapExistingPathsToKeys(array $map, PathCollection $pathCollection): array { $result = []; foreach ($map as $key => $path) { - if (array_path_exists($path, $config)) { - $result[$key] = array_get_path($path, $config); + if ($pathCollection->pathExists($path)) { + $result[$key] = $pathCollection->getValueInPath($path); } }