From a60df996c99baf31f99bca2c10678f8b6396d1b6 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 10:59:08 +0200 Subject: [PATCH 01/12] Begin adding an experimental config converter command --- .../src/MonorepoDevToolsServiceProvider.php | 1 + .../DevTools/src/RefactorConfigCommand.php | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 monorepo/DevTools/src/RefactorConfigCommand.php diff --git a/monorepo/DevTools/src/MonorepoDevToolsServiceProvider.php b/monorepo/DevTools/src/MonorepoDevToolsServiceProvider.php index 0ca2d214b15..39e6292436c 100644 --- a/monorepo/DevTools/src/MonorepoDevToolsServiceProvider.php +++ b/monorepo/DevTools/src/MonorepoDevToolsServiceProvider.php @@ -17,6 +17,7 @@ public function boot(): void { $this->commands([ MonorepoReleaseCommand::class, + RefactorConfigCommand::class, ]); } } diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php new file mode 100644 index 00000000000..dbfae8c3a42 --- /dev/null +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -0,0 +1,58 @@ +argument('format'); + if (! in_array($format, self::FORMATS)) { + $this->error('Invalid format. Supported formats: '.implode(', ', self::FORMATS)); + + return 1; + } + + $this->gray(' > Migrating configuration to '.$format); + + match ($format) { + 'yaml' => $this->migrateToYaml(), + }; + + $this->info('All done!'); + + return 0; + } + + protected function migrateToYaml(): void + { + // todo if file exists, add backup + + $config = config('hyde'); + + $yaml = Yaml::dump($config); + + // todo diff out defaults? + + file_put_contents(Hyde::path('hyde.yml'), $yaml); + } +} From 3a489b0115d6f517dccb6d0596dc46fd3eebe499 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 11:36:05 +0200 Subject: [PATCH 02/12] Parse data --- .../DevTools/src/RefactorConfigCommand.php | 63 +++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index dbfae8c3a42..91c6983093f 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -5,9 +5,23 @@ namespace Hyde\MonorepoDevTools; use Hyde\Hyde; +use Hyde\Enums\Feature; +use Illuminate\Support\Str; use Symfony\Component\Yaml\Yaml; use Hyde\Console\Concerns\Command; - +use Hyde\Framework\Features\Blogging\Models\PostAuthor; +use Hyde\Framework\Features\Metadata\MetadataElementContract; + +use function copy; +use function config; +use function substr; +use function collect; +use function implode; +use function in_array; +use function is_array; +use function is_string; +use function file_exists; +use function str_starts_with; use function file_put_contents; /** @@ -45,14 +59,55 @@ public function handle(): int protected function migrateToYaml(): void { - // todo if file exists, add backup + if (file_exists(Hyde::path('hyde.yml')) && ! file_exists(Hyde::path('hyde.yml.bak'))) { + copy(Hyde::path('hyde.yml'), Hyde::path('hyde.yml.bak')); + } $config = config('hyde'); + $config = $this->serializePhpData($config); - $yaml = Yaml::dump($config); + $yaml = Yaml::dump($config, 16, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); - // todo diff out defaults? + // Todo: Diff out defaults? (unless with argument) file_put_contents(Hyde::path('hyde.yml'), $yaml); } + + protected function serializePhpData(array $config): array + { + return collect($config)->mapWithKeys(function ($value, $key) { + if (is_array($value)) { + return [$key => $this->serializePhpData($value)]; + } + + return $this->serializePhpValue($value, $key); + })->toArray(); + } + + protected function serializePhpValue(mixed $value, string|int $key): array + { + if ($value instanceof Feature) { + return [$key => Str::kebab($value->name)]; + } + + if (is_string($key) && str_starts_with($key, 'Hyde\Pages\\')) { + return [Str::kebab(substr($key, 11)) => $value]; + } + + if ($value instanceof MetadataElementContract) { + // We don't have deserialization logic for this (yet?) + return [$key => $value->__toString()]; + } + + if ($value instanceof PostAuthor) { + // Not fully supported in v1 + return [$key => [ + 'username' => $value->username, + 'name' => $value->name, + 'website' => $value->website, + ]]; + } + + return [$key => $value]; + } } From 40a40f0caff255aa0182676e3bb31ee9a76f0c2b Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 11:38:00 +0200 Subject: [PATCH 03/12] Try and rollback --- .../DevTools/src/RefactorConfigCommand.php | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index 91c6983093f..8613976ff39 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -5,6 +5,7 @@ namespace Hyde\MonorepoDevTools; use Hyde\Hyde; +use Throwable; use Hyde\Enums\Feature; use Illuminate\Support\Str; use Symfony\Component\Yaml\Yaml; @@ -15,6 +16,7 @@ use function copy; use function config; use function substr; +use function unlink; use function collect; use function implode; use function in_array; @@ -63,14 +65,23 @@ protected function migrateToYaml(): void copy(Hyde::path('hyde.yml'), Hyde::path('hyde.yml.bak')); } - $config = config('hyde'); - $config = $this->serializePhpData($config); + try { + $config = config('hyde'); + $config = $this->serializePhpData($config); - $yaml = Yaml::dump($config, 16, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); + $yaml = Yaml::dump($config, 16, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); - // Todo: Diff out defaults? (unless with argument) + // Todo: Diff out defaults? (unless with argument) - file_put_contents(Hyde::path('hyde.yml'), $yaml); + file_put_contents(Hyde::path('hyde.yml'), $yaml); + } catch (Throwable $exception) { + $this->error('Failed to migrate configuration: '.$exception->getMessage()); + $this->warn('Rolling back changes...'); + copy(Hyde::path('hyde.yml.bak'), Hyde::path('hyde.yml')); + unlink(Hyde::path('hyde.yml.bak')); + + return; + } } protected function serializePhpData(array $config): array From 7c08e2c428ad5389b7217187dbaac9c41462d8bb Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 11:48:41 +0200 Subject: [PATCH 04/12] Smarter backup --- monorepo/DevTools/src/RefactorConfigCommand.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index 8613976ff39..e979c2372de 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -61,8 +61,13 @@ public function handle(): int protected function migrateToYaml(): void { + $usesGit = file_exists(Hyde::path('.git')); + if (file_exists(Hyde::path('hyde.yml')) && ! file_exists(Hyde::path('hyde.yml.bak'))) { copy(Hyde::path('hyde.yml'), Hyde::path('hyde.yml.bak')); + if (! $usesGit) { + $this->warn("You're not using Git for version control, so a backup of your configuration has been created at hyde.yml.bak."); + } } try { @@ -81,6 +86,10 @@ protected function migrateToYaml(): void unlink(Hyde::path('hyde.yml.bak')); return; + } finally { + if ($usesGit && file_exists(Hyde::path('hyde.yml.bak'))) { + unlink(Hyde::path('hyde.yml.bak')); + } } } From b94145f8ced133105d843c66b7dc81832c64d2bb Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 11:52:12 +0200 Subject: [PATCH 05/12] Throw exception --- monorepo/DevTools/src/RefactorConfigCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index e979c2372de..b83ab5345a7 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -85,7 +85,7 @@ protected function migrateToYaml(): void copy(Hyde::path('hyde.yml.bak'), Hyde::path('hyde.yml')); unlink(Hyde::path('hyde.yml.bak')); - return; + throw $exception; } finally { if ($usesGit && file_exists(Hyde::path('hyde.yml.bak'))) { unlink(Hyde::path('hyde.yml.bak')); From 53a989fd8187d9efbac87d0f016ec84e98248b56 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 11:54:59 +0200 Subject: [PATCH 06/12] Diff out defaults --- monorepo/DevTools/src/RefactorConfigCommand.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index b83ab5345a7..44644297a8e 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -23,6 +23,7 @@ use function is_array; use function is_string; use function file_exists; +use function array_udiff; use function str_starts_with; use function file_put_contents; @@ -72,12 +73,16 @@ protected function migrateToYaml(): void try { $config = config('hyde'); + + $default = require Hyde::vendorPath('config/hyde.php'); + + // Todo: Add argument to not diff out defaults + $config = array_udiff($config, $default, fn ($a, $b) => $a === $b ? 0 : 1); + $config = $this->serializePhpData($config); $yaml = Yaml::dump($config, 16, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); - // Todo: Diff out defaults? (unless with argument) - file_put_contents(Hyde::path('hyde.yml'), $yaml); } catch (Throwable $exception) { $this->error('Failed to migrate configuration: '.$exception->getMessage()); From 62b99d45efded5b4754ee1813da0b5c950f68a46 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 12:07:08 +0200 Subject: [PATCH 07/12] Smarter diffing --- .../DevTools/src/RefactorConfigCommand.php | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index 44644297a8e..8b23bfad16f 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -23,7 +23,6 @@ use function is_array; use function is_string; use function file_exists; -use function array_udiff; use function str_starts_with; use function file_put_contents; @@ -77,7 +76,7 @@ protected function migrateToYaml(): void $default = require Hyde::vendorPath('config/hyde.php'); // Todo: Add argument to not diff out defaults - $config = array_udiff($config, $default, fn ($a, $b) => $a === $b ? 0 : 1); + $config = $this->diffConfig($config, $default); $config = $this->serializePhpData($config); @@ -135,4 +134,42 @@ protected function serializePhpValue(mixed $value, string|int $key): array return [$key => $value]; } + + // Remove any default values from the config by iterating the root array keys and comparing the values + protected function diffConfig(array $config, array $default): array + { + $new = []; + + foreach ($config as $key => $value) { + if (is_array($value) && isset($default[$key])) { + if ($value === $default[$key]) { + continue; + } + } + + if (isset($default[$key]) && $value === $default[$key]) { + continue; + } + + $new[$key] = $value; + } + + return $this->arrayFilterRecurse($new); + } + + protected function arrayFilterRecurse(array $input): array + { + foreach ($input as $key => &$value) { + if (is_array($value)) { + $value = $this->arrayFilterRecurse($value); + if (empty($value)) { + unset($input[$key]); + } + } elseif (blank($value)) { + unset($input[$key]); + } + } + + return $input; + } } From a2c492c506761bf9443dd51e8057b2e4d54c0fd8 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 12:09:04 +0200 Subject: [PATCH 08/12] Don't run if there exists a file Makes it unpredictable when rerunning --- .../DevTools/src/RefactorConfigCommand.php | 40 +++++-------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index 8b23bfad16f..79a754f927b 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -5,7 +5,7 @@ namespace Hyde\MonorepoDevTools; use Hyde\Hyde; -use Throwable; +use RuntimeException; use Hyde\Enums\Feature; use Illuminate\Support\Str; use Symfony\Component\Yaml\Yaml; @@ -13,10 +13,8 @@ use Hyde\Framework\Features\Blogging\Models\PostAuthor; use Hyde\Framework\Features\Metadata\MetadataElementContract; -use function copy; use function config; use function substr; -use function unlink; use function collect; use function implode; use function in_array; @@ -61,40 +59,22 @@ public function handle(): int protected function migrateToYaml(): void { - $usesGit = file_exists(Hyde::path('.git')); - - if (file_exists(Hyde::path('hyde.yml')) && ! file_exists(Hyde::path('hyde.yml.bak'))) { - copy(Hyde::path('hyde.yml'), Hyde::path('hyde.yml.bak')); - if (! $usesGit) { - $this->warn("You're not using Git for version control, so a backup of your configuration has been created at hyde.yml.bak."); - } + if (file_exists(Hyde::path('hyde.yml')) || file_exists(Hyde::path('hyde.yaml'))) { + throw new RuntimeException('Configuration already exists in YAML format.'); } - try { - $config = config('hyde'); - - $default = require Hyde::vendorPath('config/hyde.php'); + $config = config('hyde'); - // Todo: Add argument to not diff out defaults - $config = $this->diffConfig($config, $default); + $default = require Hyde::vendorPath('config/hyde.php'); - $config = $this->serializePhpData($config); + // Todo: Add argument to not diff out defaults + $config = $this->diffConfig($config, $default); - $yaml = Yaml::dump($config, 16, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); + $config = $this->serializePhpData($config); - file_put_contents(Hyde::path('hyde.yml'), $yaml); - } catch (Throwable $exception) { - $this->error('Failed to migrate configuration: '.$exception->getMessage()); - $this->warn('Rolling back changes...'); - copy(Hyde::path('hyde.yml.bak'), Hyde::path('hyde.yml')); - unlink(Hyde::path('hyde.yml.bak')); + $yaml = Yaml::dump($config, 16, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); - throw $exception; - } finally { - if ($usesGit && file_exists(Hyde::path('hyde.yml.bak'))) { - unlink(Hyde::path('hyde.yml.bak')); - } - } + file_put_contents(Hyde::path('hyde.yml'), $yaml); } protected function serializePhpData(array $config): array From ce3c2b3ab3dc8c624836e5dab42dc98358cad42e Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 12:17:24 +0200 Subject: [PATCH 09/12] Add experimental marker --- monorepo/DevTools/src/RefactorConfigCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index 79a754f927b..58af193168c 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -26,6 +26,7 @@ /** * @internal This class is internal to the hydephp/develop monorepo. + * @experimental https://github.com/hydephp/develop/pull/1833 */ class RefactorConfigCommand extends Command { From c5eaba8775f396b43ec0249fac82b39c35c789b1 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 12:22:54 +0200 Subject: [PATCH 10/12] Loose comparison --- monorepo/DevTools/src/RefactorConfigCommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index 58af193168c..f452648fce7 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -128,7 +128,8 @@ protected function diffConfig(array $config, array $default): array } } - if (isset($default[$key]) && $value === $default[$key]) { + // Loose comparison + if (isset($default[$key]) && $value == $default[$key]) { continue; } From 961e45175f5c11bc260a3f30fa6e5b131fb17070 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 12:23:50 +0200 Subject: [PATCH 11/12] Don't save empty config --- monorepo/DevTools/src/RefactorConfigCommand.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index f452648fce7..d4d7a7ca64c 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -75,6 +75,11 @@ protected function migrateToYaml(): void $yaml = Yaml::dump($config, 16, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); + if ($yaml === '[]') { + $this->warn("You don't seem to have any configuration to migrate."); + return; + } + file_put_contents(Hyde::path('hyde.yml'), $yaml); } From 92a64b316ca4c8441bc57cb32cfc5a3e9df659c3 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 12 Jul 2024 12:26:08 +0200 Subject: [PATCH 12/12] Refactor and cleanup --- .../DevTools/src/RefactorConfigCommand.php | 107 +++++++++++------- 1 file changed, 66 insertions(+), 41 deletions(-) diff --git a/monorepo/DevTools/src/RefactorConfigCommand.php b/monorepo/DevTools/src/RefactorConfigCommand.php index d4d7a7ca64c..927b26d5a26 100644 --- a/monorepo/DevTools/src/RefactorConfigCommand.php +++ b/monorepo/DevTools/src/RefactorConfigCommand.php @@ -26,63 +26,81 @@ /** * @internal This class is internal to the hydephp/develop monorepo. + * * @experimental https://github.com/hydephp/develop/pull/1833 */ class RefactorConfigCommand extends Command { + protected const SUPPORTED_FORMATS = ['yaml']; + /** @var string */ protected $signature = 'refactor:config {format : The new configuration format}'; /** @var string */ protected $description = 'Migrate the configuration to a different format.'; - protected const FORMATS = ['yaml']; - public function handle(): int { $format = $this->argument('format'); - if (! in_array($format, self::FORMATS)) { - $this->error('Invalid format. Supported formats: '.implode(', ', self::FORMATS)); + if (! in_array($format, self::SUPPORTED_FORMATS)) { + $this->error('Invalid format. Supported formats: '.implode(', ', self::SUPPORTED_FORMATS)); return 1; } - $this->gray(' > Migrating configuration to '.$format); + $this->gray(" > Migrating configuration to $format"); - match ($format) { + return match ($format) { 'yaml' => $this->migrateToYaml(), }; + } + + protected function migrateToYaml(): int + { + $this->ensureYamlConfigDoesNotExist(); + + $config = $this->getConfigDiff(); + + if (empty($config)) { + $this->warn("You don't seem to have any configuration to migrate."); + + return 0; + } + + $serializedConfig = $this->serializePhpData($config); + $yaml = $this->dumpConfigToYaml($serializedConfig); + + file_put_contents(Hyde::path('hyde.yml'), $yaml); $this->info('All done!'); return 0; } - protected function migrateToYaml(): void + protected function ensureYamlConfigDoesNotExist(): void { if (file_exists(Hyde::path('hyde.yml')) || file_exists(Hyde::path('hyde.yaml'))) { throw new RuntimeException('Configuration already exists in YAML format.'); } + } + protected function getConfigDiff(): array + { $config = config('hyde'); - $default = require Hyde::vendorPath('config/hyde.php'); - // Todo: Add argument to not diff out defaults - $config = $this->diffConfig($config, $default); - - $config = $this->serializePhpData($config); - - $yaml = Yaml::dump($config, 16, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); - - if ($yaml === '[]') { - $this->warn("You don't seem to have any configuration to migrate."); - return; - } + return $this->diffConfig($config, $default); + } - file_put_contents(Hyde::path('hyde.yml'), $yaml); + protected function dumpConfigToYaml(array $config): string + { + return Yaml::dump($config, 16, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); } + /** + * @param array $config + * @return array + */ protected function serializePhpData(array $config): array { return collect($config)->mapWithKeys(function ($value, $key) { @@ -94,6 +112,11 @@ protected function serializePhpData(array $config): array })->toArray(); } + /** + * @param mixed $value + * @param string|int $key + * @return array + */ protected function serializePhpValue(mixed $value, string|int $key): array { if ($value instanceof Feature) { @@ -105,45 +128,47 @@ protected function serializePhpValue(mixed $value, string|int $key): array } if ($value instanceof MetadataElementContract) { - // We don't have deserialization logic for this (yet?) return [$key => $value->__toString()]; } if ($value instanceof PostAuthor) { - // Not fully supported in v1 - return [$key => [ - 'username' => $value->username, - 'name' => $value->name, - 'website' => $value->website, - ]]; + return [$key => $this->serializePostAuthor($value)]; } return [$key => $value]; } - // Remove any default values from the config by iterating the root array keys and comparing the values + protected function serializePostAuthor(PostAuthor $author): array + { + return [ + 'username' => $author->username, + 'name' => $author->name, + 'website' => $author->website, + ]; + } + + /** + * @param array $config + * @param array $default + * @return array + */ protected function diffConfig(array $config, array $default): array { - $new = []; + $diff = []; foreach ($config as $key => $value) { - if (is_array($value) && isset($default[$key])) { - if ($value === $default[$key]) { - continue; - } + if (! isset($default[$key]) || $value != $default[$key]) { + $diff[$key] = $value; } - - // Loose comparison - if (isset($default[$key]) && $value == $default[$key]) { - continue; - } - - $new[$key] = $value; } - return $this->arrayFilterRecurse($new); + return $this->arrayFilterRecurse($diff); } + /** + * @param array $input + * @return array + */ protected function arrayFilterRecurse(array $input): array { foreach ($input as $key => &$value) {