first commit
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/services/StatsIssueService.php
|
||||
*
|
||||
* Copyright (c) 2022 Simon Fraser University
|
||||
* Copyright (c) 2022 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class StatsIssueService
|
||||
*
|
||||
* @ingroup services
|
||||
*
|
||||
* @brief Helper class that encapsulates issue statistics business logic
|
||||
*/
|
||||
|
||||
namespace APP\services;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\services\queryBuilders\StatsIssueQueryBuilder;
|
||||
use APP\statistics\StatisticsHelper;
|
||||
use PKP\plugins\Hook;
|
||||
use PKP\services\PKPStatsServiceTrait;
|
||||
|
||||
class StatsIssueService
|
||||
{
|
||||
use PKPStatsServiceTrait;
|
||||
|
||||
/**
|
||||
* A callback to be used with array_filter() to return records for
|
||||
* the TOC views.
|
||||
*/
|
||||
public function filterRecordTOC(object $record): bool
|
||||
{
|
||||
return $record->assoc_type == Application::ASSOC_TYPE_ISSUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback to be used with array_filter() to return records for
|
||||
* the issue galley views.
|
||||
*/
|
||||
public function filterRecordIssueGalley(object $record): bool
|
||||
{
|
||||
return $record->assoc_type == Application::ASSOC_TYPE_ISSUE_GALLEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of all issues with stats that match the request arguments
|
||||
*/
|
||||
public function getCount(array $args): int
|
||||
{
|
||||
$defaultArgs = $this->getDefaultArgs();
|
||||
$args = array_merge($defaultArgs, $args);
|
||||
unset($args['count']);
|
||||
unset($args['offset']);
|
||||
$metricsQB = $this->getQueryBuilder($args);
|
||||
|
||||
Hook::call('StatsIssue::getCount::queryBuilder', [&$metricsQB, $args]);
|
||||
|
||||
return $metricsQB->getIssueIds()->get()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the issues with total stats that match the request arguments
|
||||
*/
|
||||
public function getTotals(array $args): array
|
||||
{
|
||||
$defaultArgs = $this->getDefaultArgs();
|
||||
$args = array_merge($defaultArgs, $args);
|
||||
$metricsQB = $this->getQueryBuilder($args);
|
||||
|
||||
Hook::call('StatsIssue::getTotals::queryBuilder', [&$metricsQB, $args]);
|
||||
|
||||
$groupBy = [StatisticsHelper::STATISTICS_DIMENSION_ISSUE_ID];
|
||||
$metricsQB = $metricsQB->getSum($groupBy);
|
||||
|
||||
$orderDirection = $args['orderDirection'] === StatisticsHelper::STATISTICS_ORDER_ASC ? 'asc' : 'desc';
|
||||
$metricsQB->orderBy(StatisticsHelper::STATISTICS_METRIC, $orderDirection);
|
||||
return $metricsQB->get()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metrics by type (toc, issue galley) for an issue
|
||||
* Assumes that the issue ID is provided in parameters
|
||||
*/
|
||||
public function getTotalsByType(int $issueId, int $contextId, ?string $dateStart, ?string $dateEnd): array
|
||||
{
|
||||
$defaultArgs = $this->getDefaultArgs();
|
||||
$args = [
|
||||
'issueIds' => [$issueId],
|
||||
'contextIds' => [$contextId],
|
||||
'dateStart' => $dateStart ?? $defaultArgs['dateStart'],
|
||||
'dateEnd' => $dateEnd ?? $defaultArgs['dateEnd'],
|
||||
];
|
||||
$metricsQB = $this->getQueryBuilder($args);
|
||||
|
||||
Hook::call('StatsIssue::getTotalsByType::queryBuilder', [&$metricsQB, $args]);
|
||||
|
||||
// get toc and galley views for the issue
|
||||
$groupBy = [StatisticsHelper::STATISTICS_DIMENSION_ASSOC_TYPE];
|
||||
$metricsQB = $metricsQB->getSum($groupBy);
|
||||
$metricsByType = $metricsQB->get()->toArray();
|
||||
|
||||
$tocViews = $issueGalleyViews = 0;
|
||||
$tocRecord = array_filter($metricsByType, [$this, 'filterRecordTOC']);
|
||||
if (!empty($tocRecord)) {
|
||||
$tocViews = (int) current($tocRecord)->metric;
|
||||
}
|
||||
$issueGalleyRecord = array_filter($metricsByType, [$this, 'filterRecordIssueGalley']);
|
||||
if (!empty($issueGalleyRecord)) {
|
||||
$issueGalleyViews = current($issueGalleyRecord)->metric;
|
||||
}
|
||||
|
||||
return [
|
||||
'toc' => $tocViews,
|
||||
'galley' => $issueGalleyViews,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default parameters
|
||||
*/
|
||||
public function getDefaultArgs(): array
|
||||
{
|
||||
return [
|
||||
'dateStart' => StatisticsHelper::STATISTICS_EARLIEST_DATE,
|
||||
'dateEnd' => date('Y-m-d', strtotime('yesterday')),
|
||||
|
||||
// Require a context to be specified to prevent unwanted data leakage
|
||||
// if someone forgets to specify the context.
|
||||
'contextIds' => [\PKP\core\PKPApplication::CONTEXT_ID_NONE],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a QueryBuilder object with the passed args
|
||||
*/
|
||||
public function getQueryBuilder(array $args = []): StatsIssueQueryBuilder
|
||||
{
|
||||
$statsQB = new StatsIssueQueryBuilder();
|
||||
$statsQB
|
||||
->filterByContexts($args['contextIds'])
|
||||
->before($args['dateEnd'])
|
||||
->after($args['dateStart']);
|
||||
|
||||
if (!empty(($args['issueIds']))) {
|
||||
$statsQB->filterByIssues($args['issueIds']);
|
||||
}
|
||||
|
||||
if (!empty(($args['issueGalleyIds']))) {
|
||||
$statsQB->filterByIssueGalleys($args['issueGalleyIds']);
|
||||
}
|
||||
|
||||
if (!empty($args['assocTypes'])) {
|
||||
$statsQB->filterByAssocTypes($args['assocTypes']);
|
||||
}
|
||||
|
||||
if (isset($args['count'])) {
|
||||
$statsQB->limit($args['count']);
|
||||
if (isset($args['offset'])) {
|
||||
$statsQB->offset($args['offset']);
|
||||
}
|
||||
}
|
||||
|
||||
Hook::call('StatsIssue::queryBuilder', [&$statsQB, $args]);
|
||||
|
||||
return $statsQB;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user