Last active
March 9, 2018 11:52
-
-
Save dominikzogg/ccda5aeafbac8e6f292ee3235430f107 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$old = [ | |
'name' => 'Old name', | |
'active' => true, | |
'description' => 'This is a description', | |
'items' => [ | |
[ | |
'name' => 'Old item name', | |
'active' => true, | |
], | |
], | |
]; | |
$new = [ | |
'name' => 'new name', | |
'active' => true, | |
'categories' => [1, 2], | |
'items' => [ | |
[ | |
'name' => 'Old item name', | |
'active' => false, | |
], | |
[ | |
'name' => 'New item name', | |
'active' => true, | |
], | |
], | |
]; | |
$changes = getChanges($old, $new); | |
echo '<pre>'; | |
echo json_encode($changes, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); | |
print_r(applyChanges($old, $changes)); | |
function getChanges(array $old, array $new, string $path = ''): array | |
{ | |
$changes = []; | |
foreach ($new as $key => $newValue) { | |
if (isset($old[$key])) { | |
$oldValue = $old[$key]; | |
if ($oldValue !== $newValue) { | |
if (is_array($oldValue) && is_array($newValue)) { | |
foreach (getChanges($oldValue, $newValue, $path.'/'.$key) as $change) { | |
$changes[] = $change; | |
} | |
} else { | |
$changes[] = ['op' => 'replace', 'path' => $path.'/'.$key, 'value' => $newValue]; | |
} | |
} | |
} else { | |
$changes[] = ['op' => 'add', 'path' => $path.'/'.$key, 'value' => $newValue]; | |
} | |
unset($old[$key]); | |
} | |
foreach ($old as $key => $oldValue) { | |
$changes[] = ['op' => 'remove', 'path' => $path.'/'.$key]; | |
} | |
return $changes; | |
} | |
function applyChanges(array $old, array $changes): array | |
{ | |
foreach ($changes as $change) { | |
switch ($change['op']) { | |
case 'add': | |
replace($old, $change['path'], $change['value']); | |
break; | |
case 'replace': | |
replace($old, $change['path'], $change['value']); | |
break; | |
case 'remove': | |
remove($old, $change['path']); | |
} | |
} | |
return $old; | |
} | |
function add(array &$data, string $path, $value) | |
{ | |
$pathParts = explode('/', trim($path, '/')); | |
$lastPart = array_pop($pathParts); | |
$reference = &$data; | |
foreach ($pathParts as $pathPart) { | |
if ($pathPart === (string) (int) $pathPart) { | |
$pathPart = (int) $pathPart; | |
} | |
if (!isset($reference[$pathPart])) { | |
$reference[$pathPart] = []; | |
} | |
$reference = &$reference[$pathPart]; | |
} | |
if (is_array($value) && is_array($reference[$lastPart])) { | |
$reference[$lastPart] = array_replace_recursive($reference[$lastPart], $value); | |
} else { | |
$reference[$lastPart] = $value; | |
} | |
} | |
function replace(array &$data, string $path, $value) | |
{ | |
$pathParts = explode('/', trim($path, '/')); | |
$lastPart = array_pop($pathParts); | |
$reference = &$data; | |
foreach ($pathParts as $pathPart) { | |
if ($pathPart === (string) (int) $pathPart) { | |
$pathPart = (int) $pathPart; | |
} | |
if (!isset($reference[$pathPart])) { | |
$reference[$pathPart] = []; | |
} | |
$reference = &$reference[$pathPart]; | |
} | |
$reference[$lastPart] = $value; | |
} | |
function remove(array &$data, string $path) | |
{ | |
$pathParts = explode('/', trim($path, '/')); | |
$lastPart = array_pop($pathParts); | |
$reference = &$data; | |
foreach ($pathParts as $pathPart) { | |
if ($pathPart === (string) (int) $pathPart) { | |
$pathPart = (int) $pathPart; | |
} | |
if (!isset($reference[$pathPart])) { | |
return; | |
} | |
} | |
unset($reference[$lastPart]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment