isAssociative($data)) { throw new UnexpectedValueException('Only associative arrays are allowed; lists are not allowed'); } $result = []; $this->recusiveEncoding($data, $result, ''); return $result; } public function supportsEncoding($format) { return 'docgen' === $format; } private function canonicalizeKey(string $path, string $key): string { return '' === $path ? $key : $path . '_' . $key; } private function isAssociative(array $data) { $keys = array_keys($data); return array_keys($keys) !== $keys; } private function recusiveEncoding(array $data, array &$result, $path) { if ($this->isAssociative($data)) { foreach ($data as $key => $value) { if (is_array($value)) { $this->recusiveEncoding($value, $result, $this->canonicalizeKey($path, $key)); } else { $result[$this->canonicalizeKey($path, $key)] = $value; } } } else { foreach ($data as $elem) { if (!$this->isAssociative($elem)) { throw new UnexpectedValueException(sprintf('Embedded loops are not allowed. See data under %s path', $path)); } $sub = []; $this->recusiveEncoding($elem, $sub, ''); $result[$path][] = $sub; } } } }