public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true) { // validation of requested $period & $date if ($period == 'range') { // load days in the range $period = 'day'; } if (!Period::isMultiplePeriod($date, $period)) { throw new Exception("Row evolutions can not be processed with this combination of \\'date\\' and \\'period\\' parameters."); } $label = ResponseBuilder::unsanitizeLabelParameter($label); $labels = Piwik::getArrayFromApiParameter($label); $metadata = $this->getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $idGoal); $dataTable = $this->loadRowEvolutionDataFromAPI($metadata, $idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $idGoal); if (empty($labels)) { $labels = $this->getLabelsFromDataTable($dataTable, $labels); $dataTable = $this->enrichRowAddMetadataLabelIndex($labels, $dataTable); } if (count($labels) != 1) { $data = $this->getMultiRowEvolution($dataTable, $metadata, $apiModule, $apiAction, $labels, $column, $legendAppendMetric, $labelUseAbsoluteUrl); } else { $data = $this->getSingleRowEvolution($idSite, $dataTable, $metadata, $apiModule, $apiAction, $labels[0], $labelUseAbsoluteUrl); } return $data; }
/** * Creates a new Period instance with a period ID and {@link Date} instance. * * _Note: This method cannot create {@link Period\Range} periods._ * * @param string $strPeriod `"day"`, `"week"`, `"month"`, `"year"`, `"range"`. * @param Date|string $date A date within the period or the range of dates. * @throws Exception If `$strPeriod` is invalid. * @return \Piwik\Period */ public static function factory($strPeriod, $date) { if (is_string($date)) { if (Period::isMultiplePeriod($date, $strPeriod) || $strPeriod == 'range') { return new Range($strPeriod, $date); } $date = Date::factory($date); } switch ($strPeriod) { case 'day': return new Day($date); break; case 'week': return new Week($date); break; case 'month': return new Month($date); break; case 'year': return new Year($date); break; default: $message = Piwik::translate('General_ExceptionInvalidPeriod', array($strPeriod, 'day, week, month, year, range')); throw new Exception($message); break; } }
/** * Returns true if it is likely that the data for this report has been purged and if the * user should be told about that. * * In order for this function to return true, the following must also be true: * - The data table for this report must either be empty or not have been fetched. * - The period of this report is not a multiple period. * - The date of this report must be older than the delete_reports_older_than config option. * @param DataTableInterface $dataTable * @return bool */ public static function hasReportBeenPurged($dataTable) { $strPeriod = Common::getRequestVar('period', false); $strDate = Common::getRequestVar('date', false); if (false !== $strPeriod && false !== $strDate && (is_null($dataTable) || !empty($dataTable) && $dataTable->getRowsCount() == 0)) { // if range, only look at the first date if ($strPeriod == 'range') { $idSite = Common::getRequestVar('idSite', ''); if (intval($idSite) != 0) { $site = new Site($idSite); $timezone = $site->getTimezone(); } else { $timezone = 'UTC'; } $period = new Range('range', $strDate, $timezone); $reportDate = $period->getDateStart(); } elseif (Period::isMultiplePeriod($strDate, $strPeriod)) { // if a multiple period, this function is irrelevant return false; } else { // otherwise, use the date as given $reportDate = Date::factory($strDate); } $reportYear = $reportDate->toString('Y'); $reportMonth = $reportDate->toString('m'); if (static::shouldReportBePurged($reportYear, $reportMonth)) { return true; } } return false; }
/** * Returns datatable describing the number of visits for each day of the week. * * @param string $idSite The site ID. Cannot refer to multiple sites. * @param string $period The period type: day, week, year, range... * @param string $date The start date of the period. Cannot refer to multiple dates. * @param bool|string $segment The segment. * @throws Exception * @return DataTable */ public function getByDayOfWeek($idSite, $period, $date, $segment = false) { Piwik::checkUserHasViewAccess($idSite); // metrics to query $metrics = Metrics::getVisitsMetricNames(); unset($metrics[Metrics::INDEX_MAX_ACTIONS]); // disabled for multiple dates if (Period::isMultiplePeriod($date, $period)) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple dates."); } // get metric data for every day within the supplied period $oPeriod = Period\Factory::makePeriodFromQueryParams(Site::getTimezoneFor($idSite), $period, $date); $dateRange = $oPeriod->getDateStart()->toString() . ',' . $oPeriod->getDateEnd()->toString(); $archive = Archive::build($idSite, 'day', $dateRange, $segment); // disabled for multiple sites if (count($archive->getParams()->getIdSites()) > 1) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple sites."); } $dataTable = $archive->getDataTableFromNumeric($metrics)->mergeChildren(); // if there's no data for this report, don't bother w/ anything else if ($dataTable->getRowsCount() == 0) { return $dataTable; } // group by the day of the week (see below for dayOfWeekFromDate function) $dataTable->filter('GroupBy', array('label', __NAMESPACE__ . '\\dayOfWeekFromDate')); // create new datatable w/ empty rows, then add calculated datatable $rows = array(); foreach (array(1, 2, 3, 4, 5, 6, 7) as $day) { $rows[] = array('label' => $day, 'nb_visits' => 0); } $result = new DataTable(); $result->addRowsFromSimpleArray($rows); $result->addDataTable($dataTable); // set day of week integer as metadata $result->filter('ColumnCallbackAddMetadata', array('label', 'day_of_week')); // translate labels $result->filter('ColumnCallbackReplace', array('label', __NAMESPACE__ . '\\translateDayOfWeek')); // set datatable metadata for period start & finish $result->setMetadata('date_start', $oPeriod->getDateStart()); $result->setMetadata('date_end', $oPeriod->getDateEnd()); return $result; }
/** * Creates a new Period instance with a period ID and {@link Date} instance. * * _Note: This method cannot create {@link Period\Range} periods._ * * @param string $period `"day"`, `"week"`, `"month"`, `"year"`, `"range"`. * @param Date|string $date A date within the period or the range of dates. * @param Date|string $timezone Optional timezone that will be used only when $period is 'range' or $date is 'last|previous' * @throws Exception If `$strPeriod` is invalid. * @return \Piwik\Period */ public static function build($period, $date, $timezone = 'UTC') { self::checkPeriodIsEnabled($period); if (is_string($date)) { if (Period::isMultiplePeriod($date, $period) || $period == 'range') { return new Range($period, $date, $timezone); } $date = Date::factory($date); } switch ($period) { case 'day': return new Day($date); break; case 'week': return new Week($date); break; case 'month': return new Month($date); break; case 'year': return new Year($date); break; } }
/** * Returns `true` if this instance will request a single DataTable, `false` if requesting * more than one. * * @return bool */ public function isRequestingSingleDataTable() { $requestArray = $this->request->getRequestArray() + $_GET + $_POST; $date = Common::getRequestVar('date', null, 'string', $requestArray); $period = Common::getRequestVar('period', null, 'string', $requestArray); $idSite = Common::getRequestVar('idSite', null, 'string', $requestArray); if (Period::isMultiplePeriod($date, $period) || strpos($idSite, ',') !== false || $idSite == 'all') { return false; } return true; }
/** * Returns a new Archive instance that will query archive data for the given set of * sites and periods, using an optional Segment. * * This method uses data that is found in query parameters, so the parameters to this * function can be string values. * * If you want to create an Archive instance with an array of Period instances, use * {@link Archive::factory()}. * * @param string|int|array $idSites A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`), * or `'all'`. * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'` * @param Date|string $strDate 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()} * or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD'). * @param bool|false|string $segment Segment definition or false if no segment should be used. {@link Piwik\Segment} * @param bool|false|string $_restrictSitesToLogin Used only when running as a scheduled task. * @param bool $skipAggregationOfSubTables Whether the archive, when it is processed, should also aggregate all sub-tables * @return Archive */ public static function build($idSites, $period, $strDate, $segment = false, $_restrictSitesToLogin = false, $skipAggregationOfSubTables = false) { $websiteIds = Site::getIdSitesFromIdSitesString($idSites, $_restrictSitesToLogin); if (Period::isMultiplePeriod($strDate, $period)) { $oPeriod = Factory::build($period, $strDate); $allPeriods = $oPeriod->getSubperiods(); } else { $timezone = count($websiteIds) == 1 ? Site::getTimezoneFor($websiteIds[0]) : false; $oPeriod = Factory::makePeriodFromQueryParams($timezone, $period, $strDate); $allPeriods = array($oPeriod); } $segment = new Segment($segment, $websiteIds); $idSiteIsAll = $idSites == self::REQUEST_ALL_WEBSITES_FLAG; $isMultipleDate = Period::isMultiplePeriod($strDate, $period); return Archive::factory($segment, $allPeriods, $websiteIds, $idSiteIsAll, $isMultipleDate, $skipAggregationOfSubTables); }
private function makeSureToWorkOnFirstLevelDataTable($table) { if (!array_key_exists('idSubtable', $this->request)) { return $table; } $firstLevelReport = $this->findFirstLevelReport(); if (empty($firstLevelReport)) { // it is not a subtable report $module = $this->apiModule; $action = $this->apiMethod; } else { $module = $firstLevelReport->getModule(); $action = $firstLevelReport->getAction(); } $request = $this->request; /** @var \Piwik\Period $period */ $period = $table->getMetadata('period'); if (!empty($period)) { // we want a dataTable, not a dataTable\map if (Period::isMultiplePeriod($request['date'], $request['period']) || 'range' == $period->getLabel()) { $request['date'] = $period->getRangeString(); $request['period'] = 'range'; } else { $request['date'] = $period->getDateStart()->toString(); $request['period'] = $period->getLabel(); } } $table = $this->callApiAndReturnDataTable($module, $action, $request); if ($table instanceof DataTable\Map) { $table = $table->mergeChildren(); } return $table; }
/** * @param array $reports * @param array $info * @return mixed */ public function getReportMetadata(&$reports, $info) { $idSites = $info['idSites']; // If only one website is selected, we add the Graph URL if (count($idSites) != 1) { return; } $idSite = reset($idSites); // in case API.getReportMetadata was not called with date/period we use sane defaults if (empty($info['period'])) { $info['period'] = 'day'; } if (empty($info['date'])) { $info['date'] = 'today'; } // need two sets of period & date, one for single period graphs, one for multiple periods graphs if (Period::isMultiplePeriod($info['date'], $info['period'])) { $periodForMultiplePeriodGraph = $info['period']; $dateForMultiplePeriodGraph = $info['date']; $periodForSinglePeriodGraph = 'range'; $dateForSinglePeriodGraph = $info['date']; } else { $periodForSinglePeriodGraph = $info['period']; $dateForSinglePeriodGraph = $info['date']; $piwikSite = new Site($idSite); if ($periodForSinglePeriodGraph == 'range') { // for period=range, show the configured sub-periods $periodForMultiplePeriodGraph = Config::getInstance()->General['graphs_default_period_to_plot_when_period_range']; $dateForMultiplePeriodGraph = $dateForSinglePeriodGraph; } else { if ($info['period'] == 'day' || !Config::getInstance()->General['graphs_show_evolution_within_selected_period']) { // for period=day, always show the last n days // if graphs_show_evolution_within_selected_period=false, show the last n periods $periodForMultiplePeriodGraph = $periodForSinglePeriodGraph; $dateForMultiplePeriodGraph = Range::getRelativeToEndDate($periodForSinglePeriodGraph, 'last' . self::GRAPH_EVOLUTION_LAST_PERIODS, $dateForSinglePeriodGraph, $piwikSite); } else { // if graphs_show_evolution_within_selected_period=true, show the days within the period // (except if the period is day, see above) $periodForMultiplePeriodGraph = 'day'; $period = PeriodFactory::build($info['period'], $info['date']); $start = $period->getDateStart()->toString(); $end = $period->getDateEnd()->toString(); $dateForMultiplePeriodGraph = $start . ',' . $end; } } } $token_auth = Common::getRequestVar('token_auth', false); $segment = Request::getRawSegmentFromRequest(); /** @var Scheduler $scheduler */ $scheduler = StaticContainer::getContainer()->get('Piwik\\Scheduler\\Scheduler'); $isRunningTask = $scheduler->isRunningTask(); // add the idSubtable if it exists $idSubtable = Common::getRequestVar('idSubtable', false); $urlPrefix = "index.php?"; foreach ($reports as &$report) { $reportModule = $report['module']; $reportAction = $report['action']; $reportUniqueId = $reportModule . '_' . $reportAction; $parameters = array(); $parameters['module'] = 'API'; $parameters['method'] = 'ImageGraph.get'; $parameters['idSite'] = $idSite; $parameters['apiModule'] = $reportModule; $parameters['apiAction'] = $reportAction; if (!empty($token_auth)) { $parameters['token_auth'] = $token_auth; } // Forward custom Report parameters to the graph URL if (!empty($report['parameters'])) { $parameters = array_merge($parameters, $report['parameters']); } if (empty($report['dimension'])) { $parameters['period'] = $periodForMultiplePeriodGraph; $parameters['date'] = $dateForMultiplePeriodGraph; } else { $parameters['period'] = $periodForSinglePeriodGraph; $parameters['date'] = $dateForSinglePeriodGraph; } if ($idSubtable !== false) { $parameters['idSubtable'] = $idSubtable; } if (!empty($_GET['_restrictSitesToLogin']) && $isRunningTask) { $parameters['_restrictSitesToLogin'] = $_GET['_restrictSitesToLogin']; } if (!empty($segment)) { $parameters['segment'] = $segment; } $report['imageGraphUrl'] = $urlPrefix . Url::getQueryStringFromParameters($parameters); // thanks to API.getRowEvolution, reports with dimensions can now be plotted using an evolution graph // however, most reports with a fixed set of dimension values are excluded // this is done so Piwik Mobile and Scheduled Reports do not display them $reportWithDimensionsSupportsEvolution = empty($report['constantRowsCount']) || in_array($reportUniqueId, self::$CONSTANT_ROW_COUNT_REPORT_EXCEPTIONS); $reportSupportsEvolution = !in_array($reportUniqueId, self::$REPORTS_DISABLED_EVOLUTION_GRAPH); if ($reportSupportsEvolution && $reportWithDimensionsSupportsEvolution) { $parameters['period'] = $periodForMultiplePeriodGraph; $parameters['date'] = $dateForMultiplePeriodGraph; $report['imageGraphEvolutionUrl'] = $urlPrefix . Url::getQueryStringFromParameters($parameters); } } }
/** * @param array $reports * @param array $info * @return mixed */ public function getReportMetadata(&$reports, $info) { $idSites = $info['idSites']; // If only one website is selected, we add the Graph URL if (count($idSites) != 1) { return; } $idSite = reset($idSites); // in case API.getReportMetadata was not called with date/period we use sane defaults if (empty($info['period'])) { $info['period'] = 'day'; } if (empty($info['date'])) { $info['date'] = 'today'; } // need two sets of period & date, one for single period graphs, one for multiple periods graphs if (Period::isMultiplePeriod($info['date'], $info['period'])) { $periodForMultiplePeriodGraph = $info['period']; $dateForMultiplePeriodGraph = $info['date']; $periodForSinglePeriodGraph = 'range'; $dateForSinglePeriodGraph = $info['date']; } else { $periodForSinglePeriodGraph = $info['period']; $dateForSinglePeriodGraph = $info['date']; $piwikSite = new Site($idSite); if ($periodForSinglePeriodGraph == 'range') { $periodForMultiplePeriodGraph = Config::getInstance()->General['graphs_default_period_to_plot_when_period_range']; $dateForMultiplePeriodGraph = $dateForSinglePeriodGraph; } else { $periodForMultiplePeriodGraph = $periodForSinglePeriodGraph; $dateForMultiplePeriodGraph = Range::getRelativeToEndDate($periodForSinglePeriodGraph, 'last' . self::GRAPH_EVOLUTION_LAST_PERIODS, $dateForSinglePeriodGraph, $piwikSite); } } $token_auth = Common::getRequestVar('token_auth', false); $urlPrefix = "index.php?"; foreach ($reports as &$report) { $reportModule = $report['module']; $reportAction = $report['action']; $reportUniqueId = $reportModule . '_' . $reportAction; $parameters = array(); $parameters['module'] = 'API'; $parameters['method'] = 'ImageGraph.get'; $parameters['idSite'] = $idSite; $parameters['apiModule'] = $reportModule; $parameters['apiAction'] = $reportAction; if (!empty($token_auth)) { $parameters['token_auth'] = $token_auth; } // Forward custom Report parameters to the graph URL if (!empty($report['parameters'])) { $parameters = array_merge($parameters, $report['parameters']); } if (empty($report['dimension'])) { $parameters['period'] = $periodForMultiplePeriodGraph; $parameters['date'] = $dateForMultiplePeriodGraph; } else { $parameters['period'] = $periodForSinglePeriodGraph; $parameters['date'] = $dateForSinglePeriodGraph; } // add the idSubtable if it exists $idSubtable = Common::getRequestVar('idSubtable', false); if ($idSubtable !== false) { $parameters['idSubtable'] = $idSubtable; } if (!empty($_GET['_restrictSitesToLogin']) && TaskScheduler::isTaskBeingExecuted()) { $parameters['_restrictSitesToLogin'] = $_GET['_restrictSitesToLogin']; } $report['imageGraphUrl'] = $urlPrefix . Url::getQueryStringFromParameters($parameters); // thanks to API.getRowEvolution, reports with dimensions can now be plotted using an evolution graph // however, most reports with a fixed set of dimension values are excluded // this is done so Piwik Mobile and Scheduled Reports do not display them $reportWithDimensionsSupportsEvolution = empty($report['constantRowsCount']) || in_array($reportUniqueId, self::$CONSTANT_ROW_COUNT_REPORT_EXCEPTIONS); $reportSupportsEvolution = !in_array($reportUniqueId, self::$REPORTS_DISABLED_EVOLUTION_GRAPH); if ($reportSupportsEvolution && $reportWithDimensionsSupportsEvolution) { $parameters['period'] = $periodForMultiplePeriodGraph; $parameters['date'] = $dateForMultiplePeriodGraph; $report['imageGraphEvolutionUrl'] = $urlPrefix . Url::getQueryStringFromParameters($parameters); } } }
public function get($idSite, $period, $date, $apiModule, $apiAction, $graphType = false, $outputType = API::GRAPH_OUTPUT_INLINE, $columns = false, $labels = false, $showLegend = true, $width = false, $height = false, $fontSize = API::DEFAULT_FONT_SIZE, $legendFontSize = false, $aliasedGraph = true, $idGoal = false, $colors = false, $textColor = API::DEFAULT_TEXT_COLOR, $backgroundColor = API::DEFAULT_BACKGROUND_COLOR, $gridColor = API::DEFAULT_GRID_COLOR, $idSubtable = false, $legendAppendMetric = true, $segment = false) { Piwik::checkUserHasViewAccess($idSite); // Health check - should we also test for GD2 only? if (!SettingsServer::isGdExtensionEnabled()) { throw new Exception('Error: To create graphs in Piwik, please enable GD php extension (with Freetype support) in php.ini, and restart your web server.'); } $useUnicodeFont = array('am', 'ar', 'el', 'fa', 'fi', 'he', 'ja', 'ka', 'ko', 'te', 'th', 'zh-cn', 'zh-tw'); $languageLoaded = Translate::getLanguageLoaded(); $font = self::getFontPath(self::DEFAULT_FONT); if (in_array($languageLoaded, $useUnicodeFont)) { $unicodeFontPath = self::getFontPath(self::UNICODE_FONT); $font = file_exists($unicodeFontPath) ? $unicodeFontPath : $font; } // save original GET to reset after processing. Important for API-in-API-call $savedGET = $_GET; try { $apiParameters = array(); if (!empty($idGoal)) { $apiParameters = array('idGoal' => $idGoal); } // Fetch the metadata for given api-action $metadata = APIMetadata::getInstance()->getMetadata($idSite, $apiModule, $apiAction, $apiParameters, $languageLoaded, $period, $date, $hideMetricsDoc = false, $showSubtableReports = true); if (!$metadata) { throw new Exception('Invalid API Module and/or API Action'); } $metadata = $metadata[0]; $reportHasDimension = !empty($metadata['dimension']); $constantRowsCount = !empty($metadata['constantRowsCount']); $isMultiplePeriod = Period::isMultiplePeriod($date, $period); if (!$reportHasDimension && !$isMultiplePeriod) { throw new Exception('The graph cannot be drawn for this combination of \'date\' and \'period\' parameters.'); } if (empty($legendFontSize)) { $legendFontSize = (int) $fontSize + self::DEFAULT_LEGEND_FONT_SIZE_OFFSET; } if (empty($graphType)) { if ($isMultiplePeriod) { $graphType = StaticGraph::GRAPH_TYPE_BASIC_LINE; } else { if ($constantRowsCount) { $graphType = StaticGraph::GRAPH_TYPE_VERTICAL_BAR; } else { $graphType = StaticGraph::GRAPH_TYPE_HORIZONTAL_BAR; } } $reportUniqueId = $metadata['uniqueId']; if (isset(self::$DEFAULT_GRAPH_TYPE_OVERRIDE[$reportUniqueId][$isMultiplePeriod])) { $graphType = self::$DEFAULT_GRAPH_TYPE_OVERRIDE[$reportUniqueId][$isMultiplePeriod]; } } else { $availableGraphTypes = StaticGraph::getAvailableStaticGraphTypes(); if (!in_array($graphType, $availableGraphTypes)) { throw new Exception(Piwik::translate('General_ExceptionInvalidStaticGraphType', array($graphType, implode(', ', $availableGraphTypes)))); } } $width = (int) $width; $height = (int) $height; if (empty($width)) { $width = self::$DEFAULT_PARAMETERS[$graphType][self::WIDTH_KEY]; } if (empty($height)) { $height = self::$DEFAULT_PARAMETERS[$graphType][self::HEIGHT_KEY]; } // Cap width and height to a safe amount $width = min($width, self::MAX_WIDTH); $height = min($height, self::MAX_HEIGHT); $reportColumns = array_merge(!empty($metadata['metrics']) ? $metadata['metrics'] : array(), !empty($metadata['processedMetrics']) ? $metadata['processedMetrics'] : array(), !empty($metadata['metricsGoal']) ? $metadata['metricsGoal'] : array(), !empty($metadata['processedMetricsGoal']) ? $metadata['processedMetricsGoal'] : array()); $ordinateColumns = array(); if (empty($columns)) { $ordinateColumns[] = empty($reportColumns[self::DEFAULT_ORDINATE_METRIC]) ? key($metadata['metrics']) : self::DEFAULT_ORDINATE_METRIC; } else { $ordinateColumns = explode(',', $columns); foreach ($ordinateColumns as $column) { if (empty($reportColumns[$column])) { throw new Exception(Piwik::translate('ImageGraph_ColumnOrdinateMissing', array($column, implode(',', array_keys($reportColumns))))); } } } $ordinateLabels = array(); foreach ($ordinateColumns as $column) { $ordinateLabels[$column] = $reportColumns[$column]; } // sort and truncate filters $defaultFilterTruncate = self::$DEFAULT_PARAMETERS[$graphType][self::TRUNCATE_KEY]; switch ($graphType) { case StaticGraph::GRAPH_TYPE_3D_PIE: case StaticGraph::GRAPH_TYPE_BASIC_PIE: if (count($ordinateColumns) > 1) { // pChart doesn't support multiple series on pie charts throw new Exception("Pie charts do not currently support multiple series"); } $_GET['filter_sort_column'] = reset($ordinateColumns); $this->setFilterTruncate($defaultFilterTruncate); break; case StaticGraph::GRAPH_TYPE_VERTICAL_BAR: case StaticGraph::GRAPH_TYPE_BASIC_LINE: if (!$isMultiplePeriod && !$constantRowsCount) { $this->setFilterTruncate($defaultFilterTruncate); } break; } $ordinateLogos = array(); // row evolutions if ($isMultiplePeriod && $reportHasDimension) { $plottedMetric = reset($ordinateColumns); // when no labels are specified, getRowEvolution returns the top N=filter_limit row evolutions // rows are sorted using filter_sort_column (see DataTableGenericFilter for more info) if (!$labels) { $savedFilterSortColumnValue = Common::getRequestVar('filter_sort_column', ''); $_GET['filter_sort_column'] = $plottedMetric; $savedFilterLimitValue = Common::getRequestVar('filter_limit', -1, 'int'); if ($savedFilterLimitValue == -1 || $savedFilterLimitValue > self::MAX_NB_ROW_LABELS) { $_GET['filter_limit'] = self::DEFAULT_NB_ROW_EVOLUTIONS; } } $processedReport = APIMetadata::getInstance()->getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $plottedMetric, $languageLoaded, $idGoal, $legendAppendMetric, $labelUseAbsoluteUrl = false); //@review this test will need to be updated after evaluating the @review comment in API/API.php if (!$processedReport) { throw new Exception(Piwik::translate('General_NoDataForGraph')); } // restoring generic filter parameters if (!$labels) { $_GET['filter_sort_column'] = $savedFilterSortColumnValue; if ($savedFilterLimitValue != -1) { $_GET['filter_limit'] = $savedFilterLimitValue; } } // retrieve metric names & labels $metrics = $processedReport['metadata']['metrics']; $ordinateLabels = array(); // getRowEvolution returned more than one label if (!array_key_exists($plottedMetric, $metrics)) { $ordinateColumns = array(); $i = 0; foreach ($metrics as $metric => $info) { $ordinateColumn = $plottedMetric . '_' . $i++; $ordinateColumns[] = $metric; $ordinateLabels[$ordinateColumn] = $info['name']; if (isset($info['logo'])) { $ordinateLogo = $info['logo']; // @review pChart does not support gifs in graph legends, would it be possible to convert all plugin pictures (cookie.gif, flash.gif, ..) to png files? if (!strstr($ordinateLogo, '.gif')) { $absoluteLogoPath = self::getAbsoluteLogoPath($ordinateLogo); if (file_exists($absoluteLogoPath)) { $ordinateLogos[$ordinateColumn] = $absoluteLogoPath; } } } } } else { $ordinateLabels[$plottedMetric] = $processedReport['label'] . ' (' . $metrics[$plottedMetric]['name'] . ')'; } } else { $processedReport = APIMetadata::getInstance()->getProcessedReport($idSite, $period, $date, $apiModule, $apiAction, $segment, $apiParameters = false, $idGoal, $languageLoaded, $showTimer = true, $hideMetricsDoc = false, $idSubtable, $showRawMetrics = false); } // prepare abscissa and ordinate series $abscissaSeries = array(); $abscissaLogos = array(); $ordinateSeries = array(); /** @var \Piwik\DataTable\Simple|\Piwik\DataTable\Map $reportData */ $reportData = $processedReport['reportData']; $hasData = false; $hasNonZeroValue = false; if (!$isMultiplePeriod) { $reportMetadata = $processedReport['reportMetadata']->getRows(); $i = 0; // $reportData instanceof DataTable foreach ($reportData->getRows() as $row) { // $row instanceof Row $rowData = $row->getColumns(); // Associative Array $abscissaSeries[] = Common::unsanitizeInputValue($rowData['label']); foreach ($ordinateColumns as $column) { $parsedOrdinateValue = $this->parseOrdinateValue($rowData[$column]); $hasData = true; if ($parsedOrdinateValue != 0) { $hasNonZeroValue = true; } $ordinateSeries[$column][] = $parsedOrdinateValue; } if (isset($reportMetadata[$i])) { $rowMetadata = $reportMetadata[$i]->getColumns(); if (isset($rowMetadata['logo'])) { $absoluteLogoPath = self::getAbsoluteLogoPath($rowMetadata['logo']); if (file_exists($absoluteLogoPath)) { $abscissaLogos[$i] = $absoluteLogoPath; } } } $i++; } } else { // $periodsData instanceof Simple[] $periodsData = array_values($reportData->getDataTables()); $periodsCount = count($periodsData); for ($i = 0; $i < $periodsCount; $i++) { // $periodsData[$i] instanceof Simple // $rows instanceof Row[] if (empty($periodsData[$i])) { continue; } $rows = $periodsData[$i]->getRows(); if (array_key_exists(0, $rows)) { $rowData = $rows[0]->getColumns(); // associative Array foreach ($ordinateColumns as $column) { $ordinateValue = $rowData[$column]; $parsedOrdinateValue = $this->parseOrdinateValue($ordinateValue); $hasData = true; if (!empty($parsedOrdinateValue)) { $hasNonZeroValue = true; } $ordinateSeries[$column][] = $parsedOrdinateValue; } } else { foreach ($ordinateColumns as $column) { $ordinateSeries[$column][] = 0; } } $rowId = $periodsData[$i]->getMetadata(DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getLocalizedShortString(); $abscissaSeries[] = Common::unsanitizeInputValue($rowId); } } if (!$hasData || !$hasNonZeroValue) { throw new Exception(Piwik::translate('General_NoDataForGraph')); } //Setup the graph $graph = StaticGraph::factory($graphType); $graph->setWidth($width); $graph->setHeight($height); $graph->setFont($font); $graph->setFontSize($fontSize); $graph->setLegendFontSize($legendFontSize); $graph->setOrdinateLabels($ordinateLabels); $graph->setShowLegend($showLegend); $graph->setAliasedGraph($aliasedGraph); $graph->setAbscissaSeries($abscissaSeries); $graph->setAbscissaLogos($abscissaLogos); $graph->setOrdinateSeries($ordinateSeries); $graph->setOrdinateLogos($ordinateLogos); $graph->setColors(!empty($colors) ? explode(',', $colors) : array()); $graph->setTextColor($textColor); $graph->setBackgroundColor($backgroundColor); $graph->setGridColor($gridColor); // when requested period is day, x-axis unit is time and all date labels can not be displayed // within requested width, force labels to be skipped every 6 days to delimit weeks if ($period == 'day' && $isMultiplePeriod) { $graph->setForceSkippedLabels(6); } // render graph $graph->renderGraph(); } catch (\Exception $e) { $graph = new \Piwik\Plugins\ImageGraph\StaticGraph\Exception(); $graph->setWidth($width); $graph->setHeight($height); $graph->setFont($font); $graph->setFontSize($fontSize); $graph->setBackgroundColor($backgroundColor); $graph->setTextColor($textColor); $graph->setException($e); $graph->renderGraph(); } // restoring get parameters $_GET = $savedGET; switch ($outputType) { case self::GRAPH_OUTPUT_FILE: if ($idGoal != '') { $idGoal = '_' . $idGoal; } $fileName = self::$DEFAULT_PARAMETERS[$graphType][self::FILENAME_KEY] . '_' . $apiModule . '_' . $apiAction . $idGoal . ' ' . str_replace(',', '-', $date) . ' ' . $idSite . '.png'; $fileName = str_replace(array(' ', '/'), '_', $fileName); if (!Filesystem::isValidFilename($fileName)) { throw new Exception('Error: Image graph filename ' . $fileName . ' is not valid.'); } return $graph->sendToDisk($fileName); case self::GRAPH_OUTPUT_PHP: return $graph->getRenderedImage(); case self::GRAPH_OUTPUT_INLINE: default: $graph->sendToBrowser(); exit; } }