public function generateReport($idReport, $date, $language = false, $outputType = false, $period = false, $reportFormat = false, $parameters = false)
{
Piwik::checkUserIsNotAnonymous();
// load specified language
if (empty($language)) {
$language = Translate::getLanguageDefault();
}
/** @var Translator $translator */
$translator = StaticContainer::get('Piwik\\Translation\\Translator');
$translator->setCurrentLanguage($language);
$reports = $this->getReports($idSite = false, $_period = false, $idReport);
$report = reset($reports);
$idSite = $report['idsite'];
$login = $report['login'];
$reportType = $report['type'];
$this->checkUserHasViewPermission($login, $idSite);
// override report period
if (empty($period)) {
$period = $report['period'];
}
// override report format
if (!empty($reportFormat)) {
self::validateReportFormat($reportType, $reportFormat);
$report['format'] = $reportFormat;
} else {
$reportFormat = $report['format'];
}
// override and/or validate report parameters
$report['parameters'] = json_decode(self::validateReportParameters($reportType, empty($parameters) ? $report['parameters'] : $parameters), true);
// available reports
$availableReportMetadata = \Piwik\Plugins\API\API::getInstance()->getReportMetadata($idSite);
// we need to lookup which reports metadata are registered in this report
$reportMetadata = array();
foreach ($availableReportMetadata as $metadata) {
if (in_array($metadata['uniqueId'], $report['reports'])) {
$reportMetadata[] = $metadata;
}
}
// the report will be rendered with the first 23 rows and will aggregate other rows in a summary row
// 23 rows table fits in one portrait page
$initialFilterTruncate = Common::getRequestVar('filter_truncate', false);
$_GET['filter_truncate'] = Config::getInstance()->General['scheduled_reports_truncate'];
$prettyDate = null;
$processedReports = array();
$segment = self::getSegment($report['idsegment']);
foreach ($reportMetadata as $action) {
$apiModule = $action['module'];
$apiAction = $action['action'];
$apiParameters = array();
if (isset($action['parameters'])) {
$apiParameters = $action['parameters'];
}
$mustRestoreGET = false;
// all Websites dashboard should not be truncated in the report
if ($apiModule == 'MultiSites') {
$mustRestoreGET = $_GET;
$_GET['enhanced'] = true;
if ($apiAction == 'getAll') {
$_GET['filter_truncate'] = false;
$_GET['filter_limit'] = -1;
// show all websites in all websites report
// when a view/admin user created a report, workaround the fact that "Super User"
// is enforced in Scheduled tasks, and ensure Multisites.getAll only return the websites that this user can access
$userLogin = $report['login'];
if (!empty($userLogin) && !Piwik::hasTheUserSuperUserAccess($userLogin)) {
$_GET['_restrictSitesToLogin'] = $userLogin;
}
}
}
$params = array('idSite' => $idSite, 'period' => $period, 'date' => $date, 'apiModule' => $apiModule, 'apiAction' => $apiAction, 'apiParameters' => $apiParameters, 'flat' => 1, 'idGoal' => false, 'language' => $language, 'serialize' => 0, 'format' => 'original');
if ($segment != null) {
$params['segment'] = urlencode($segment['definition']);
} else {
$params['segment'] = false;
}
try {
$processedReport = Request::processRequest('API.getProcessedReport', $params);
} catch (\Exception $ex) {
// NOTE: can't use warning or error because the log message will appear in the UI as a notification
$this->logger->info("Error getting '?{report}' when generating scheduled report: {exception}", array('report' => http_build_query($params), 'exception' => $ex->getMessage()));
$this->logger->debug($ex);
continue;
}
$processedReport['segment'] = $segment;
// TODO add static method getPrettyDate($period, $date) in Period
$prettyDate = $processedReport['prettyDate'];
if ($mustRestoreGET) {
$_GET = $mustRestoreGET;
}
$processedReports[] = $processedReport;
}
// restore filter truncate parameter value
if ($initialFilterTruncate !== false) {
$_GET['filter_truncate'] = $initialFilterTruncate;
}
/**
* Triggered when generating the content of scheduled reports.
*
* This event can be used to modify the report data or report metadata of one or more reports
* in a scheduled report, before the scheduled report is rendered and delivered.
*
* TODO: list data available in $report or make it a new class that can be documented (same for
* all other events that use a $report)
*
* @param array &$processedReports The list of processed reports in the scheduled
* report. Entries includes report data and metadata for each report.
* @param string $reportType A string ID describing how the scheduled report will be sent, eg,
* `'sms'` or `'email'`.
* @param string $outputType The output format of the report, eg, `'html'`, `'pdf'`, etc.
* @param array $report An array describing the scheduled report that is being
* generated.
*/
Piwik::postEvent(self::PROCESS_REPORTS_EVENT, array(&$processedReports, $reportType, $outputType, $report));
$reportRenderer = null;
/**
* Triggered when obtaining a renderer instance based on the scheduled report output format.
*
* Plugins that provide new scheduled report output formats should use this event to
* handle their new report formats.
*
* @param ReportRenderer &$reportRenderer This variable should be set to an instance that
* extends {@link Piwik\ReportRenderer} by one of the event
* subscribers.
* @param string $reportType A string ID describing how the report is sent, eg,
* `'sms'` or `'email'`.
* @param string $outputType The output format of the report, eg, `'html'`, `'pdf'`, etc.
* @param array $report An array describing the scheduled report that is being
* generated.
*/
Piwik::postEvent(self::GET_RENDERER_INSTANCE_EVENT, array(&$reportRenderer, $reportType, $outputType, $report));
if (is_null($reportRenderer)) {
throw new Exception("A report renderer was not supplied in the event " . self::GET_RENDERER_INSTANCE_EVENT);
}
// init report renderer
$reportRenderer->setIdSite($idSite);
$reportRenderer->setLocale($language);
// render report
$description = str_replace(array("\r", "\n"), ' ', $report['description']);
list($reportSubject, $reportTitle) = self::getReportSubjectAndReportTitle(Common::unsanitizeInputValue(Site::getNameFor($idSite)), $report['reports']);
// if reporting for a segment, use the segment's name in the title
if (is_array($segment) && strlen($segment['name'])) {
$reportTitle .= " - " . $segment['name'];
}
$filename = "{$reportTitle} - {$prettyDate} - {$description}";
$reportRenderer->renderFrontPage($reportTitle, $prettyDate, $description, $reportMetadata, $segment);
array_walk($processedReports, array($reportRenderer, 'renderReport'));
switch ($outputType) {
case self::OUTPUT_SAVE_ON_DISK:
$outputFilename = strtoupper($reportFormat) . ' ' . ucfirst($reportType) . ' Report - ' . $idReport . '.' . $date . '.' . $idSite . '.' . $language;
$outputFilename = $reportRenderer->sendToDisk($outputFilename);
$additionalFiles = $this->getAttachments($reportRenderer, $report, $processedReports, $prettyDate);
return array($outputFilename, $prettyDate, $reportSubject, $reportTitle, $additionalFiles);
break;
case self::OUTPUT_INLINE:
$reportRenderer->sendToBrowserInline($filename);
break;
case self::OUTPUT_RETURN:
return $reportRenderer->getRenderedReport();
break;
default:
case self::OUTPUT_DOWNLOAD:
$reportRenderer->sendToBrowserDownload($filename);
break;
}
}