Skip to content

Instantly share code, notes, and snippets.

@dominikzogg
Last active March 9, 2018 11:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dominikzogg/ccda5aeafbac8e6f292ee3235430f107 to your computer and use it in GitHub Desktop.
Save dominikzogg/ccda5aeafbac8e6f292ee3235430f107 to your computer and use it in GitHub Desktop.
<?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