getTemplatePath() . 'timedViewReportForm.tpl'); // Start date is provided and is valid $this->addCheck(new FormValidator($this, 'dateStartYear', 'required', 'plugins.reports.timedView.form.dateStartRequired')); $this->addCheck(new FormValidatorCustom($this, 'dateStartYear', 'required', 'plugins.reports.timedView.form.dateStartValid', create_function('$dateStartYear', '$minYear = date(\'Y\') + TIMED_VIEW_REPORT_YEAR_OFFSET_PAST; $maxYear = date(\'Y\') + TIMED_VIEW_REPORT_YEAR_OFFSET_FUTURE; return ($dateStartYear >= $minYear && $dateStartYear <= $maxYear) ? true : false;'))); $this->addCheck(new FormValidator($this, 'dateStartMonth', 'required', 'plugins.reports.timedView.form.dateStartRequired')); $this->addCheck(new FormValidatorCustom($this, 'dateStartMonth', 'required', 'plugins.reports.timedView.form.dateStartValid', create_function('$dateStartMonth', 'return ($dateStartMonth >= 1 && $dateStartMonth <= 12) ? true : false;'))); $this->addCheck(new FormValidator($this, 'dateStartDay', 'required', 'plugins.reports.timedView.form.dateStartRequired')); $this->addCheck(new FormValidatorCustom($this, 'dateStartDay', 'required', 'plugins.reports.timedView.form.dateStartValid', create_function('$dateStartDay', 'return ($dateStartDay >= 1 && $dateStartDay <= 31) ? true : false;'))); // End date is provided and is valid $this->addCheck(new FormValidator($this, 'dateEndYear', 'required', 'plugins.reports.timedView.form.dateEndRequired')); $this->addCheck(new FormValidatorCustom($this, 'dateEndYear', 'required', 'plugins.reports.timedView.form.dateEndValid', create_function('$dateEndYear', '$minYear = date(\'Y\') + TIMED_VIEW_REPORT_YEAR_OFFSET_PAST; $maxYear = date(\'Y\') + TIMED_VIEW_REPORT_YEAR_OFFSET_FUTURE; return ($dateEndYear >= $minYear && $dateEndYear <= $maxYear) ? true : false;'))); $this->addCheck(new FormValidator($this, 'dateEndMonth', 'required', 'plugins.reports.timedView.form.dateEndRequired')); $this->addCheck(new FormValidatorCustom($this, 'dateEndMonth', 'required', 'plugins.reports.timedView.form.dateEndValid', create_function('$dateEndMonth', 'return ($dateEndMonth >= 1 && $dateEndMonth <= 12) ? true : false;'))); $this->addCheck(new FormValidator($this, 'dateEndDay', 'required', 'plugins.reports.timedView.form.dateEndRequired')); $this->addCheck(new FormValidatorCustom($this, 'dateEndDay', 'required', 'plugins.reports.timedView.form.dateEndValid', create_function('$dateEndDay', 'return ($dateEndDay >= 1 && $dateEndDay <= 31) ? true : false;'))); $this->addCheck(new FormValidatorPost($this)); } /** * Display the form. */ function display() { $templateMgr = &TemplateManager::getManager(); $journal = &Request::getJournal(); $templateMgr->assign('yearOffsetPast', TIMED_VIEW_REPORT_YEAR_OFFSET_PAST); $templateMgr->assign('yearOffsetFuture', TIMED_VIEW_REPORT_YEAR_OFFSET_FUTURE); parent::display(); } /** * Assign form data to user-submitted data. */ function readInputData() { $this->readUserVars(array('dateStartYear', 'dateStartMonth', 'dateStartDay', 'dateEndYear', 'dateEndMonth', 'dateEndDay', 'useTimedViewRecords')); $this->_data['dateStart'] = date('Ymd', mktime(0, 0, 0, $this->_data['dateStartMonth'], $this->_data['dateStartDay'], $this->_data['dateStartYear'])); $this->_data['dateEnd'] = date('Ymd', mktime(0, 0, 0, $this->_data['dateEndMonth'], $this->_data['dateEndDay'], $this->_data['dateEndYear'])); } /** * Save subscription. * @param $request Request */ function execute(&$request) { $router =& $request->getRouter(); $journal =& $router->getContext($request); $journalId = $journal->getId(); $dateStart = $this->getData('dateStart'); $dateEnd = $this->getData('dateEnd'); if ($this->getData('useTimedViewRecords')) { $metricType = OJS_METRIC_TYPE_TIMED_VIEWS; } else { $metricType = OJS_METRIC_TYPE_COUNTER; } import('lib.pkp.classes.db.DBResultRange'); $dbResultRange = new DBResultRange(STATISTICS_MAX_ROWS); $metricsDao = DAORegistry::getDAO('MetricsDAO'); /* @var $metricsDao MetricsDAO */ $columns = array(STATISTICS_DIMENSION_ASSOC_ID, STATISTICS_DIMENSION_ASSOC_TYPE, STATISTICS_DIMENSION_SUBMISSION_ID); $filter = array(STATISTICS_DIMENSION_ASSOC_TYPE => array(ASSOC_TYPE_ARTICLE, ASSOC_TYPE_GALLEY), STATISTICS_DIMENSION_CONTEXT_ID => $journalId); if ($dateStart && $dateEnd) { $filter[STATISTICS_DIMENSION_DAY] = array('from' => $dateStart, 'to' => $dateEnd); } // Need to consider paging of stats records for databases with // large amount of statistics data. We store all the records we // need in those total variables. In a really really large metrics // table, and for a considerable large period of time, this process // might exceed the maximum amount of memory or take so long to // finish that the browser will time out. Since users can generate // the report by smaller periods of time, this is not a big issue. $allReportStats = array(); // While we still have stats records about article abstract views, // keep adding them to the total. while (true) { $reportStats = $metricsDao->getMetrics($metricType, $columns, $filter, array(STATISTICS_DIMENSION_SUBMISSION_ID => STATISTICS_ORDER_ASC, STATISTICS_DIMENSION_ASSOC_TYPE => STATISTICS_ORDER_ASC), $dbResultRange); $allReportStats = array_merge($allReportStats, $reportStats); $dbResultRange->setPage($dbResultRange->getPage() + 1); // It means we don't have more pages to fetch. if (count($reportStats) < $dbResultRange->getCount()) break; } // Format stats and retrieve submission and galleys info. list($articleData, $galleyLabels, $galleyViews) = $this->_formatStats($allReportStats); $this->_buildReport($articleData, $galleyLabels, $galleyViews); } /** * Return report statistics already formatted in columns * to generate the report. * @param $reportStats array All metric records retrieved * with MetricsDAO::getMetrics() * @return array */ function _formatStats($reportStats) { $articleData = $galleyLabels = $galleyViews = array(); $issueDao =& DAORegistry::getDAO('IssueDAO'); $publishedArticleDao =& DAORegistry::getDAO('PublishedArticleDAO'); $galleyDao =& DAORegistry::getDAO('ArticleGalleyDAO'); /* @var $galleyDao ArticleGalleyDAO */ $articleId = null; $objects = array(); foreach ($reportStats as $record) { $articleId = $record[STATISTICS_DIMENSION_SUBMISSION_ID]; // Retrieve article and galleys data related to the // working article id. $assocType = $record[STATISTICS_DIMENSION_ASSOC_TYPE]; // Retrieve article data, if it wasn't before. if (!isset($articleData[$articleId])) { $publishedArticle =& $publishedArticleDao->getPublishedArticleByArticleId($articleId, null, true); if (!$publishedArticle) continue; $issueId = $publishedArticle->getIssueId(); $issue =& $issueDao->getIssueById($issueId, null, true); if ($assocType == ASSOC_TYPE_ARTICLE) { $abstractViews = $record[STATISTICS_METRIC]; } else { $abstractViews = ''; } $articleData[$articleId] = array( 'id' => $articleId, 'title' => $publishedArticle->getLocalizedTitle(), 'issue' => $issue->getIssueIdentification(), 'datePublished' => $publishedArticle->getDatePublished(), 'totalAbstractViews' => $abstractViews ); } // Retrieve galley data. if ($assocType == ASSOC_TYPE_GALLEY) { if (!isset($galleyViews[$articleId])) { $galleyViews[$articleId] = array(); } $galleyId = $record[STATISTICS_DIMENSION_ASSOC_ID]; $galley =& $galleyDao->getGalley($galleyId, null, true); $label = $galley->getLabel(); $i = array_search($label, $galleyLabels); if ($i === false) { $i = count($galleyLabels); $galleyLabels[] = $label; } // Make sure the array is the same size as in previous iterations // so that we insert values into the right location $galleyViews[$articleId] = array_pad($galleyViews[$articleId], count($galleyLabels), ''); $views = $record[STATISTICS_METRIC]; $galleyViews[$articleId][$i] = $views; if (!isset($galleyViewTotal)) $galleyViewTotal = 0; $galleyViewTotal += $views; } // Check if we got all article galley stats, if yes, add // the total galley views info. $nextRecord = next($reportStats); if ($nextRecord) { $nextArticleId = $nextRecord[STATISTICS_DIMENSION_SUBMISSION_ID]; } else { $nextArticleId = null; } if ($nextArticleId != $articleId) { // Finished getting data for all objects related to the // working article id. // Add the galleys total downloads. if (isset($articleData[$articleId]) && isset($galleyViewTotal)) { $articleData[$articleId]['galleyViews'] = $galleyViewTotal; } // Clean up. unset($galleyViewTotal); } } return array($articleData, $galleyLabels, $galleyViews); } /** * Build the report using the passed data. * @param $articleData array Title, journal, data, abstract views, etc. * @param $galleyLabels array All galley labels to be used as columns. * @param $galleyViews array All galley views per label. */ function _buildReport($articleData, $galleyLabels, $galleyViews) { header('content-type: text/comma-separated-values'); header('content-disposition: attachment; filename=report.csv'); $fp = fopen('php://output', 'wt'); $reportColumns = array( __('plugins.reports.timedView.report.articleId'), __('plugins.reports.timedView.report.articleTitle'), __('issue.issue'), __('plugins.reports.timedView.report.datePublished'), __('plugins.reports.timedView.report.abstractViews'), __('plugins.reports.timedView.report.galleyViews'), ); fputcsv($fp, array_merge($reportColumns, $galleyLabels)); $dateFormatShort = Config::getVar('general', 'date_format_short'); foreach ($articleData as $articleId => $article) { if (isset($galleyViews[$articleId])) { fputcsv($fp, array_merge($articleData[$articleId], $galleyViews[$articleId])); } else { fputcsv($fp, $articleData[$articleId]); } } fclose($fp); } } ?>