diff --git a/src/Integrations/Divi/Design/PresetDiff.php b/src/Integrations/Divi/Design/PresetDiff.php new file mode 100644 index 0000000..e10ab9f --- /dev/null +++ b/src/Integrations/Divi/Design/PresetDiff.php @@ -0,0 +1,125 @@ +}> + */ + public static function between(PresetBook $before, PresetBook $after): array + { + $old = $before->data(); + $new = $after->data(); + $rows = []; + foreach ([PresetScope::MODULE, PresetScope::GROUP] as $kind) { + $names = array_unique(array_merge(array_keys($old[$kind] ?? []), array_keys($new[$kind] ?? []))); + sort($names); + foreach ($names as $name) { + $was = $old[$kind][$name] ?? ['default' => '', 'items' => []]; + $is = $new[$kind][$name] ?? ['default' => '', 'items' => []]; + array_push($rows, ...self::items($kind, (string) $name, $was['items'], $is['items'])); + array_push($rows, ...self::defaults($kind, (string) $name, $was, $is)); + } + } + + return $rows; + } + + /** + * @param array> $was + * @param array> $is + * @return list> + */ + private static function items(string $kind, string $scope, array $was, array $is): array + { + $ids = array_unique(array_merge(array_keys($was), array_keys($is))); + sort($ids); + $rows = []; + foreach ($ids as $id) { + $key = (string) $id; + $before = $was[$key] ?? null; + $after = $is[$key] ?? null; + if ($before === null || $after === null) { + $rows[] = self::row($kind, $scope, $key, $after ?? $before, $before === null ? 'added' : 'removed'); + continue; + } + $fields = self::changedFields($before, $after); + if ($fields !== []) { + $rows[] = self::row($kind, $scope, $key, $after, 'changed') + ['fields' => $fields]; + } + } + + return $rows; + } + + /** + * @param array{default: string, items: array>} $was + * @param array{default: string, items: array>} $is + * @return list> + */ + private static function defaults(string $kind, string $scope, array $was, array $is): array + { + if ($was['default'] === $is['default']) { + return []; + } + if ($is['default'] === '') { + $gone = $was['items'][$was['default']] ?? null; + + return [self::row($kind, $scope, $was['default'], $gone, 'default_cleared')]; + } + + $item = $is['items'][$is['default']] ?? null; + + return [self::row($kind, $scope, $is['default'], $item, 'default_set')]; + } + + /** + * @param array $before + * @param array $after + * @return list + */ + private static function changedFields(array $before, array $after): array + { + $keys = array_diff(array_unique(array_merge(array_keys($before), array_keys($after))), self::DERIVED); + $fields = []; + foreach ($keys as $key) { + $was = $before[$key] ?? null; + $is = $after[$key] ?? null; + if ($was != $is) { // phpcs:ignore Universal.Operators.StrictComparisons + $fields[] = (string) $key; + } + } + sort($fields); + + return $fields; + } + + /** + * @param array|null $item + * @return array{kind: string, scope: string, id: string, name: string, action: string} + */ + private static function row(string $kind, string $scope, string $id, ?array $item, string $action): array + { + return [ + 'kind' => $kind, + 'scope' => $scope, + 'id' => $id, + 'name' => is_string($item['name'] ?? null) ? $item['name'] : $id, + 'action' => $action, + ]; + } +} diff --git a/tests/Unit/Integrations/Divi/Design/PresetDiffTest.php b/tests/Unit/Integrations/Divi/Design/PresetDiffTest.php new file mode 100644 index 0000000..c01d4b9 --- /dev/null +++ b/tests/Unit/Integrations/Divi/Design/PresetDiffTest.php @@ -0,0 +1,49 @@ +items($button)['aaaaaaaaaa']; + $changed['attrs'] = ['button' => ['x' => 2]]; + $changed['updated'] = 99; + $changed['styleAttrs'] = ['ignored' => true]; + $after = $before + ->with($button, $changed) + ->with($button, ['id' => 'eeeeeeeeee', 'name' => 'Neu', 'attrs' => []]) + ->withDefault($button, 'eeeeeeeeee') + ->without($button, 'bbbbbbbbbb') + ->withDefault($text, ''); + + self::assertSame([ + ['kind' => 'module', 'scope' => 'divi/button', 'id' => 'aaaaaaaaaa', 'name' => 'CTA primär', + 'action' => 'changed', 'fields' => ['attrs']], + ['kind' => 'module', 'scope' => 'divi/button', 'id' => 'bbbbbbbbbb', 'name' => 'Doppelt', + 'action' => 'removed'], + ['kind' => 'module', 'scope' => 'divi/button', 'id' => 'eeeeeeeeee', 'name' => 'Neu', 'action' => 'added'], + ['kind' => 'module', 'scope' => 'divi/button', 'id' => 'eeeeeeeeee', 'name' => 'Neu', + 'action' => 'default_set'], + ['kind' => 'module', 'scope' => 'divi/text', 'id' => 'dddddddddd', 'name' => 'Fließtext', + 'action' => 'default_cleared'], + ], PresetDiff::between($before, $after)); + } +}