public function renderArray($array) { $result = parent::renderArray($array); // if $array is a simple associative array, remove the JSON root array that is added by renderDataTable if (!empty($array) && Piwik::isAssociativeArray($array) && !Piwik::isMultiDimensionalArray($array)) { $result = substr($result, 1, strlen($result) - 2); } return $result; }
public function renderArray($array) { if (Piwik::isMultiDimensionalArray($array)) { $jsonRenderer = Renderer::factory('json'); $jsonRenderer->setTable($array); $result = $jsonRenderer->render(); return $this->applyJsonpIfNeeded($result); } $result = $this->renderDataTable($array); // if $array is a simple associative array, remove the JSON root array that is added by renderDataTable if (!empty($array) && Piwik::isAssociativeArray($array) && !Piwik::isMultiDimensionalArray($array)) { $result = substr($result, 1, strlen($result) - 2); } return $result; }
/** * @dataProvider getIsAssociativeArrayTestCases */ public function testIsAssociativeArray($array, $expected) { $this->assertEquals($expected, Piwik::isAssociativeArray($array)); }
/** * Returns true if an array should be wrapped before rendering. This is used to * mimic quirks in the old rendering logic (for backwards compatibility). The * specific meaning of 'wrap' is left up to the Renderer. For XML, this means a * new <row> node. For JSON, this means wrapping in an array. * * In the old code, arrays were added to new DataTable instances, and then rendered. * This transformation wrapped associative arrays except under certain circumstances, * including: * - single element (ie, array('nb_visits' => 0)) (not wrapped for some renderers) * - empty array (ie, array()) * - array w/ arrays/DataTable instances as values (ie, * array('name' => 'myreport', * 'reportData' => new DataTable()) * OR array('name' => 'myreport', * 'reportData' => array(...)) ) * * @param array $array * @param bool $wrapSingleValues Whether to wrap array('key' => 'value') arrays. Some * renderers wrap them and some don't. * @param bool|null $isAssociativeArray Whether the array is associative or not. * If null, it is determined. * @return bool */ protected static function shouldWrapArrayBeforeRendering($array, $wrapSingleValues = true, $isAssociativeArray = null) { if (empty($array)) { return false; } if ($isAssociativeArray === null) { $isAssociativeArray = Piwik::isAssociativeArray($array); } $wrap = true; if ($isAssociativeArray) { // we don't wrap if the array has one element that is a value $firstValue = reset($array); if (!$wrapSingleValues && count($array) === 1 && (!is_array($firstValue) && !is_object($firstValue))) { $wrap = false; } else { foreach ($array as $value) { if (is_array($value) || is_object($value)) { $wrap = false; break; } } } } else { $wrap = false; } return $wrap; }
/** * Renders an array as XML. * * @param array $array The array to render. * @param string $prefixLines The string to prefix each line in the output. * @return string */ private function renderArray($array, $prefixLines) { $isAssociativeArray = Piwik::isAssociativeArray($array); // check if array contains arrays, and if not wrap the result in an extra <row> element // (only check if this is the root renderArray call) // NOTE: this is for backwards compatibility. before, array's were added to a new DataTable. // if the array had arrays, they were added as multiple rows, otherwise it was treated as // one row. removing will change API output. $wrapInRow = $prefixLines === "\t" && self::shouldWrapArrayBeforeRendering($array, $wrapSingleValues = false, $isAssociativeArray); // render the array $result = ""; if ($wrapInRow) { $result .= "{$prefixLines}<row>\n"; $prefixLines .= "\t"; } foreach ($array as $key => $value) { // based on the type of array & the key, determine how this node will look if ($isAssociativeArray) { $keyIsInvalidXmlElement = is_numeric($key) || is_numeric($key[0]); if ($keyIsInvalidXmlElement) { $prefix = "<row key=\"{$key}\">"; $suffix = "</row>"; $emptyNode = "<row key=\"{$key}\"/>"; } else { if (strpos($key, '=') !== false) { list($keyAttributeName, $key) = explode('=', $key, 2); $prefix = "<row {$keyAttributeName}=\"{$key}\">"; $suffix = "</row>"; $emptyNode = "<row {$keyAttributeName}=\"{$key}\">"; } else { $prefix = "<{$key}>"; $suffix = "</{$key}>"; $emptyNode = "<{$key} />"; } } } else { $prefix = "<row>"; $suffix = "</row>"; $emptyNode = "<row/>"; } // render the array item if (is_array($value)) { $result .= $prefixLines . $prefix . "\n"; $result .= $this->renderArray($value, $prefixLines . "\t"); $result .= $prefixLines . $suffix . "\n"; } else { if ($value instanceof DataTable || $value instanceof Map) { if ($value->getRowsCount() == 0) { $result .= $prefixLines . $emptyNode . "\n"; } else { $result .= $prefixLines . $prefix . "\n"; if ($value instanceof Map) { $result .= $this->renderDataTableMap($value, $this->getArrayFromDataTable($value), $prefixLines); } else { if ($value instanceof Simple) { $result .= $this->renderDataTableSimple($this->getArrayFromDataTable($value), $prefixLines); } else { $result .= $this->renderDataTable($this->getArrayFromDataTable($value), $prefixLines); } } $result .= $prefixLines . $suffix . "\n"; } } else { $xmlValue = self::formatValueXml($value); if (strlen($xmlValue) != 0) { $result .= $prefixLines . $prefix . $xmlValue . $suffix . "\n"; } else { $result .= $prefixLines . $emptyNode . "\n"; } } } } if ($wrapInRow) { $result .= substr($prefixLines, 0, strlen($prefixLines) - 1) . "</row>\n"; } return $result; }