*/ public array $addedItems; /** * @var array */ public array $removedItems; /** * @var array */ public array $unchangedItems; /** * @var array */ public array $meta; /** * @param array $addedItems * @param array $removedItems * @param array $unchangedItems * @param array $meta */ public function __construct( string $key, string $label, DiffRowStatus $status, mixed $oldValue = null, mixed $newValue = null, bool $isListLike = false, array $addedItems = [], array $removedItems = [], array $unchangedItems = [], array $meta = [], ) { if (trim($key) === '') { throw new InvalidArgumentException('DiffRow key must be a non-empty string.'); } if (trim($label) === '') { throw new InvalidArgumentException('DiffRow label must be a non-empty string.'); } $this->key = $key; $this->label = $label; $this->status = $status; $this->oldValue = $oldValue; $this->newValue = $newValue; $this->isListLike = $isListLike; $this->addedItems = array_values($addedItems); $this->removedItems = array_values($removedItems); $this->unchangedItems = array_values($unchangedItems); $this->meta = $this->normalizeMeta($meta); } /** * @param array $meta * @return array */ private function normalizeMeta(array $meta): array { $normalized = []; foreach ($meta as $key => $value) { if (! is_string($key) || trim($key) === '') { continue; } $normalized[$key] = $this->normalizeMetaValue($value); } return $normalized; } private function normalizeMetaValue(mixed $value): mixed { if ($value === null || is_scalar($value)) { return $value; } if ($value instanceof BackedEnum) { return $value->value; } if ($value instanceof Stringable) { return (string) $value; } if (! is_array($value)) { return null; } $normalized = []; foreach ($value as $key => $item) { if (! is_int($key) && ! is_string($key)) { continue; } $normalized[$key] = $this->normalizeMetaValue($item); } return array_is_list($normalized) ? array_values($normalized) : $normalized; } }