694 lines
26 KiB
PHP
694 lines
26 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file classes/sushi/CounterR5Report.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 CounterR5Report
|
|
*
|
|
* @ingroup sushi
|
|
*
|
|
* @brief Base class for COUNTER R5 reports
|
|
*
|
|
*/
|
|
|
|
namespace PKP\sushi;
|
|
|
|
use APP\core\Application;
|
|
use APP\core\Services;
|
|
use APP\facades\Repo;
|
|
use DateInterval;
|
|
use DatePeriod;
|
|
use DateTime;
|
|
use Exception;
|
|
use PKP\components\forms\FieldSelect;
|
|
use PKP\components\forms\FieldText;
|
|
use PKP\context\Context;
|
|
|
|
abstract class CounterR5Report
|
|
{
|
|
/** The access method */
|
|
public const ACCESS_METHOD = 'Regular';
|
|
|
|
/** Access type */
|
|
public const ACCESS_TYPE = 'OA_Gold';
|
|
|
|
/** ID of the context the report is for. */
|
|
public Context $context;
|
|
|
|
/** Platform name, either context or site name (if configured so in the site settings). */
|
|
public string $platformName;
|
|
|
|
/** The platform ID is configured in the site settings. Uses the context path if no platform ID is configured. */
|
|
public string $platformId;
|
|
|
|
/** The customer ID is the ID of the institutional record in this context. */
|
|
public int $customerId;
|
|
|
|
/** Name of the institutional record in this context. */
|
|
public string $institutionName;
|
|
|
|
/** Available institution IDs (the ID of the institutional record and ROR). */
|
|
public ?array $institutionIds;
|
|
|
|
/** The requested begin date */
|
|
public string $beginDate;
|
|
|
|
/** The requested end date */
|
|
public string $endDate;
|
|
|
|
/** Requested metric types */
|
|
public array $metricTypes = [
|
|
'Total_Item_Investigations',
|
|
'Unique_Item_Investigations',
|
|
'Total_Item_Requests',
|
|
'Unique_Item_Requests'
|
|
];
|
|
|
|
/** Requested Year of Publication (YOP) */
|
|
public array $yearsOfPublication = [];
|
|
|
|
/** Warnings displayed in the report header. */
|
|
public array $warnings = [];
|
|
|
|
/** List of all filters requested and applied that will be displayed in the report header. */
|
|
protected array $filters = [];
|
|
|
|
/** List of all attributes requested and applied that will be displayed in the report header. */
|
|
protected array $attributes = [];
|
|
|
|
/** Additional columns/elements to include in the report. */
|
|
protected array $attributesToShow = [];
|
|
|
|
/** The granularity of the usage data to include in the report. */
|
|
protected string $granularity = 'Month';
|
|
|
|
/**
|
|
* Get report name defined by COUNTER.
|
|
*/
|
|
abstract public function getName(): string;
|
|
|
|
/**
|
|
* Get report ID defined by COUNTER.
|
|
*/
|
|
abstract public function getID(): string;
|
|
|
|
/**
|
|
* Get report release.
|
|
*/
|
|
public function getRelease(): string
|
|
{
|
|
return '5';
|
|
}
|
|
|
|
/**
|
|
* Get report description.
|
|
*/
|
|
abstract public function getDescription(): string;
|
|
|
|
/**
|
|
* Get API path defined by COUNTER for this report.
|
|
*/
|
|
abstract public function getAPIPath(): string;
|
|
|
|
/**
|
|
* Get request parameters supported by this report.
|
|
*/
|
|
abstract public function getSupportedParams(): array;
|
|
|
|
/**
|
|
* Get filters supported by this report.
|
|
*/
|
|
abstract public function getSupportedFilters(): array;
|
|
|
|
/**
|
|
* Get attributes supported by this report.
|
|
*/
|
|
abstract public function getSupportedAttributes(): array;
|
|
|
|
/**
|
|
* Get used filters that will be displayed in the report header.
|
|
*/
|
|
public function getFilters(): array
|
|
{
|
|
return $this->filters;
|
|
}
|
|
|
|
/**
|
|
* Get used attributes that will be displayed in the report header.
|
|
*/
|
|
public function getAttributes(): array
|
|
{
|
|
return $this->attributes;
|
|
}
|
|
|
|
/**
|
|
* Set filters based on the requested parameters.
|
|
*/
|
|
public function setFilters(array $filters): void
|
|
{
|
|
$this->filters = $filters;
|
|
foreach ($filters as $filter) {
|
|
switch ($filter['Name']) {
|
|
case 'Metric_Type':
|
|
$this->metricTypes = explode('|', $filter['Value']);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set attributes based on the requested parameters.
|
|
*/
|
|
public function setAttributes(array $attributes): void
|
|
{
|
|
$this->attributes = $attributes;
|
|
foreach ($attributes as $attribute) {
|
|
switch ($attribute['Name']) {
|
|
case 'Attributes_To_Show':
|
|
$this->attributesToShow = explode('|', $attribute['Value']);
|
|
break;
|
|
case 'granularity':
|
|
$this->granularity = $attribute['Value'];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Get report items */
|
|
abstract public function getReportItems(): array;
|
|
|
|
/** Get report items prepared for TSV report */
|
|
abstract public function getTSVReportItems(): array;
|
|
|
|
/** Get TSV report column names */
|
|
abstract public function getTSVColumnNames(): array;
|
|
|
|
/** Add a warning */
|
|
protected function addWarning(array $exception): void
|
|
{
|
|
$this->warnings[] = $exception;
|
|
}
|
|
|
|
/**
|
|
* Process report parameters
|
|
*
|
|
* @throws SushiException
|
|
*/
|
|
public function processReportParams($request, $params): void
|
|
{
|
|
$this->context = $request->getContext();
|
|
$this->setPlatform($request->getSite());
|
|
|
|
$this->checkRequiredParams($params);
|
|
|
|
$this->checkCustomerId($params);
|
|
|
|
$this->checkDate($params);
|
|
|
|
$this->checkSupportedParams($params);
|
|
|
|
$this->checkFilters($params);
|
|
|
|
$this->checkAttributes($params);
|
|
}
|
|
|
|
/**
|
|
* Set the platform name and ID
|
|
*/
|
|
protected function setPlatform($site): void
|
|
{
|
|
$platformName = $this->context->getName($this->context->getPrimaryLocale());
|
|
$platformId = $this->context->getPath();
|
|
if ($site->getData('isSiteSushiPlatform')) {
|
|
if ($site->getData('title')) {
|
|
$platformName = $site->getTitle($site->getPrimaryLocale());
|
|
}
|
|
$platformId = $site->getData('sushiPlatformID');
|
|
}
|
|
$this->platformName = $platformName;
|
|
$this->platformId = $platformId;
|
|
}
|
|
|
|
/**
|
|
* Check if the required parameter are provided
|
|
*
|
|
* @throws SushiException
|
|
*/
|
|
protected function checkRequiredParams($params): void
|
|
{
|
|
$missingRequiredParams = [];
|
|
if (!isset($params['customer_id'])) {
|
|
$missingRequiredParams[] = 'customer_id';
|
|
}
|
|
if (!isset($params['begin_date'])) {
|
|
$missingRequiredParams[] = 'begin_date';
|
|
}
|
|
if (!isset($params['end_date'])) {
|
|
$missingRequiredParams[] = 'end_date';
|
|
}
|
|
if (!empty($missingRequiredParams)) {
|
|
throw new SushiException(
|
|
'Insufficient Information to Process Request',
|
|
1030,
|
|
'Fatal',
|
|
__('sushi.exception.1030.missing', ['params' => implode(__('common.commaListSeparator'), $missingRequiredParams)]),
|
|
400
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the customer ID is valid
|
|
*
|
|
* @throws SushiException
|
|
*/
|
|
protected function checkCustomerId($params): void
|
|
{
|
|
$institutionName = $institutionId = null;
|
|
$customerId = $params['customer_id'];
|
|
if (is_numeric($customerId)) {
|
|
if ($customerId == 0) {
|
|
$institutionName = 'The World';
|
|
} else {
|
|
$institution = Repo::institution()->get($customerId);
|
|
if (isset($institution) && $institution->getContextId() == $this->context->getId()) {
|
|
$institutionId = [];
|
|
$institutionName = $institution->getLocalizedName();
|
|
$ror = $institution->getROR();
|
|
if (isset($ror)) {
|
|
$institutionId[] = ['Type' => 'ROR', 'Value' => $ror];
|
|
}
|
|
$institutionId[] = ['Type' => 'Proprietary', 'Value' => $this->platformId . ':' . $customerId];
|
|
}
|
|
}
|
|
}
|
|
if (!isset($institutionName)) {
|
|
throw new SushiException(
|
|
'Insufficient Information to Process Request',
|
|
1030,
|
|
'Fatal',
|
|
__('sushi.exception.1030.invalid', ['params' => 'customer_id']),
|
|
400
|
|
);
|
|
}
|
|
|
|
$this->customerId = $customerId;
|
|
$this->institutionName = $institutionName;
|
|
if (isset($institutionId)) {
|
|
$this->institutionIds = $institutionId;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the first month the usage data is available for COUNTER R5 reports.
|
|
* It is either:
|
|
* the next month of the COUNTER R5 start, or
|
|
* this journal's first publication date.
|
|
*/
|
|
public static function getEarliestDate(): string
|
|
{
|
|
$context = Application::get()->getRequest()->getContext();
|
|
$statsService = Services::get('sushiStats');
|
|
$counterR5StartDate = $statsService->getEarliestDate();
|
|
$firstDatePublished = Repo::publication()->getDateBoundaries(
|
|
Repo::publication()
|
|
->getCollector()
|
|
->filterByContextIds([$context->getId()])
|
|
)->min_date_published;
|
|
$earliestDate = strtotime($firstDatePublished) > strtotime($counterR5StartDate) ? $firstDatePublished : $counterR5StartDate;
|
|
$earliestDate = date('Y-m-01', strtotime($earliestDate . ' + 1 months'));
|
|
return $earliestDate;
|
|
}
|
|
|
|
/**
|
|
* Get the last possible date COUNTER R5 reports could exist for.
|
|
* This is the last day of the previous month,
|
|
* because the all stats for the previous month should be already compiled.
|
|
*/
|
|
public static function getLastDate(): string
|
|
{
|
|
return date('Y-m-d', strtotime('last day of previous month'));
|
|
}
|
|
|
|
/**
|
|
* Validate the date parameters (begin_date, end_date)
|
|
*
|
|
* @throws SushiException
|
|
*/
|
|
protected function checkDate($params): void
|
|
{
|
|
$earliestDate = self::getEarliestDate();
|
|
$lastDate = self::getLastDate();
|
|
$beginDate = $params['begin_date'];
|
|
$endDate = $params['end_date'];
|
|
|
|
$invalidDateErrorMessages = [];
|
|
// validate if begin_date and end_date in the format Y-m-d or Y-m
|
|
if ((!$this->validateDate($beginDate) && !$this->validateDate($beginDate, 'Y-m')) ||
|
|
(!$this->validateDate($endDate) && !$this->validateDate($endDate, 'Y-m'))) {
|
|
$invalidDateErrorMessages[] = __('sushi.exception.3020.dateFormat');
|
|
}
|
|
// validate if begin_date is after the end_date, or
|
|
// if it is the current of future month i.e. later than the lastDate
|
|
if (strtotime($beginDate) >= strtotime($endDate) ||
|
|
strtotime($beginDate) > strtotime($lastDate)) {
|
|
$invalidDateErrorMessages[] = __('sushi.exception.3020.dateRange');
|
|
}
|
|
if (!empty($invalidDateErrorMessages)) {
|
|
throw new SushiException(
|
|
'Invalid Date Arguments',
|
|
3020,
|
|
'Error',
|
|
implode('. ', $invalidDateErrorMessages),
|
|
400
|
|
);
|
|
}
|
|
|
|
// check for warnings
|
|
if (strtotime($endDate) > strtotime($lastDate)) {
|
|
$this->addWarning([
|
|
'Code' => 3031,
|
|
'Severity' => 'Warning',
|
|
'Message' => 'Usage Not Ready for Requested Dates',
|
|
'Data' => __('sushi.exception.3031', ['beginDate' => $beginDate, 'endDate' => $endDate, 'lastDate' => $lastDate])
|
|
]);
|
|
$endDate = $lastDate;
|
|
}
|
|
if (strtotime($beginDate) < strtotime($earliestDate)) {
|
|
$this->addWarning([
|
|
'Code' => 3032,
|
|
'Severity' => 'Warning',
|
|
'Message' => 'Usage No Longer Available for Requested Dates',
|
|
'Data' => __('sushi.exception.3032', ['beginDate' => $beginDate, 'endDate' => $endDate, 'earliestDate' => $earliestDate])
|
|
]);
|
|
$beginDate = $earliestDate;
|
|
}
|
|
// check if requested dates are in the middle of a month, if their format is YYYY-MM-DD
|
|
if ($this->validateDate($beginDate) || $this->validateDate($endDate)) {
|
|
$beginDay = date('d', strtotime($beginDate));
|
|
$endDay = date('d', strtotime($endDate));
|
|
$lastDayOfEndMonth = date('t', strtotime($endDate));
|
|
if ($beginDay != '01' || $endDay != $lastDayOfEndMonth) {
|
|
$this->addWarning([
|
|
'Code' => 1,
|
|
'Severity' => 'Warning',
|
|
'Message' => 'Wrong Requested Dates',
|
|
'Data' => __('sushi.exception.1', ['beginDate' => $beginDate, 'endDate' => $endDate])
|
|
]);
|
|
}
|
|
}
|
|
|
|
$this->beginDate = date_format(date_create($beginDate), 'Y-m-01');
|
|
$this->endDate = date_format(date_create($endDate), 'Y-m-t');
|
|
}
|
|
|
|
/**
|
|
* Check if there are other, not recognized parameters in this context/for this report
|
|
*/
|
|
protected function checkSupportedParams($params): void
|
|
{
|
|
$supportedParameters = $this->getSupportedParams();
|
|
$unsupportedParameters = array_diff(array_keys($params), $supportedParameters);
|
|
if (!empty($unsupportedParameters)) {
|
|
$this->addWarning([
|
|
'Code' => 3050,
|
|
'Severity' => 'Warning',
|
|
'Message' => 'Parameter Not Recognized in this Context',
|
|
'Data' => __('sushi.exception.3050', ['params' => implode(__('common.commaListSeparator'), $unsupportedParameters)])
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check required filters
|
|
*/
|
|
protected function checkFilters($params): void
|
|
{
|
|
$filters = [
|
|
['Name' => 'Begin_Date', 'Value' => $this->beginDate],
|
|
['Name' => 'End_Date', 'Value' => $this->endDate],
|
|
];
|
|
$unsupportedFilterParams = [];
|
|
$supportedFilters = $this->getSupportedFilters();
|
|
foreach ($supportedFilters as $supportedFilter) {
|
|
if (isset($params[$supportedFilter['param']])) {
|
|
$requestedFilterValues = explode('|', $params[$supportedFilter['param']]);
|
|
$validFilters = array_intersect($requestedFilterValues, $supportedFilter['supportedValues']);
|
|
if (!empty($validFilters)) {
|
|
$filters[] = ['Name' => $supportedFilter['name'], 'Value' => implode('|', $validFilters)];
|
|
}
|
|
if ($supportedFilter['name'] == 'YOP') {
|
|
$unsupportedYOP = $validYOP = [];
|
|
foreach ($requestedFilterValues as $yopValue) {
|
|
if (!preg_match('/\d{4}|\d{4}-\d{4}/', $yopValue)) {
|
|
$unsupportedYOP[] = $yopValue;
|
|
} else {
|
|
$validYOP[] = $yopValue;
|
|
}
|
|
}
|
|
if (!empty($unsupportedYOP)) {
|
|
$unsupportedFilterParams[] = $supportedFilter['param'] . '=' . implode('|', $unsupportedYOP);
|
|
}
|
|
if (!empty($validYOP)) {
|
|
$filters[] = ['Name' => $supportedFilter['name'], 'Value' => implode('|', $validYOP)];
|
|
}
|
|
} elseif ($supportedFilter['name'] == 'Item_Id') {
|
|
$itemId = array_shift($requestedFilterValues);
|
|
if (!is_numeric($itemId)) {
|
|
$this->addWarning([
|
|
'Code' => 2,
|
|
'Severity' => 'Warning',
|
|
'Message' => 'Invalid Item_Id',
|
|
'Data' => __('sushi.exception.2', ['itemId' => $itemId])
|
|
]);
|
|
} else {
|
|
$filters[] = ['Name' => $supportedFilter['name'], 'Value' => $itemId];
|
|
if (!empty($requestedFilterValues)) {
|
|
$this->addWarning([
|
|
'Code' => 3,
|
|
'Severity' => 'Warning',
|
|
'Message' => 'Wrong Item_Id Value',
|
|
'Data' => __('sushi.exception.3', ['itemIdValues' => implode('|', $requestedFilterValues)])
|
|
]);
|
|
}
|
|
}
|
|
} else {
|
|
$unsupportedFilterValues = array_diff($requestedFilterValues, $supportedFilter['supportedValues']);
|
|
if (!empty($unsupportedFilterValues)) {
|
|
$unsupportedFilterParams[] = $supportedFilter['param'] . '=' . implode('|', $unsupportedFilterValues);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$this->setFilters($filters);
|
|
|
|
// The Platform filter is only intended in cases where there is a single endpoint for multiple platforms.
|
|
// This can be omitted if the service provides report data for only one platform.
|
|
// Thus we will not consider it in the filter list we provide in the response, but will use an exception
|
|
// if it is provided in the request and different that this platform name.
|
|
if (isset($params['platform']) && $params['platform'] != $this->platformName) {
|
|
$unsupportedFilterParams[] = 'platform=' . $params['platform'];
|
|
}
|
|
if (!empty($unsupportedFilterParams)) {
|
|
$this->addWarning([
|
|
'Code' => 3060,
|
|
'Severity' => 'Warning',
|
|
'Message' => 'Invalid ReportFilter Value',
|
|
'Data' => __('sushi.exception.3060', ['filterValues' => implode(__('common.commaListSeparator'), $unsupportedFilterParams)])
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check required attributes
|
|
*/
|
|
protected function checkAttributes($params): void
|
|
{
|
|
$attributes = $unsupportedAttributeParams = [];
|
|
$supportedAttributes = $this->getSupportedAttributes();
|
|
foreach ($supportedAttributes as $supportedAttribute) {
|
|
if (isset($params[$supportedAttribute['param']])) {
|
|
$requestedAttributeValues = explode('|', $params[$supportedAttribute['param']]);
|
|
$unsupportedAttributeValues = array_diff($requestedAttributeValues, $supportedAttribute['supportedValues']);
|
|
if (!empty($unsupportedAttributeValues)) {
|
|
$unsupportedAttributeParams[] = $supportedAttribute['param'] . '=' . implode('|', $unsupportedAttributeValues);
|
|
}
|
|
$validAttributes = array_intersect($requestedAttributeValues, $supportedAttribute['supportedValues']);
|
|
if (!empty($validAttributes)) {
|
|
$attributes[] = ['Name' => $supportedAttribute['name'], 'Value' => implode('|', $validAttributes)];
|
|
}
|
|
}
|
|
}
|
|
if (!empty($unsupportedAttributeParams)) {
|
|
$this->addWarning([
|
|
'Code' => 3062,
|
|
'Severity' => 'Warning',
|
|
'Message' => 'Invalid ReportAttribute Value',
|
|
'Data' => __('sushi.exception.3062', ['attributeValues' => implode(__('common.commaListSeparator'), $unsupportedAttributeParams)])
|
|
]);
|
|
}
|
|
// even if attributes are empty (e.g. for standard views), call setAttribute so that the predefined attributes can be set
|
|
$this->setAttributes($attributes);
|
|
}
|
|
|
|
/**
|
|
* Get report header
|
|
*/
|
|
public function getReportHeader(): array
|
|
{
|
|
$reportHeader = [
|
|
'Created' => date('Y-m-d\TH:i:s\Z', time()),
|
|
'Created_By' => $this->platformName,
|
|
'Customer_ID' => (string) $this->customerId,
|
|
'Report_ID' => $this->getID(),
|
|
'Release' => $this->getRelease(),
|
|
'Report_Name' => $this->getName(),
|
|
'Institution_Name' => $this->institutionName,
|
|
];
|
|
if (!empty($this->institutionIds)) {
|
|
$reportHeader['Institution_ID'] = $this->institutionIds;
|
|
}
|
|
$reportHeader['Report_Filters'] = $this->getFilters();
|
|
if (!empty($this->getAttributes())) {
|
|
$reportHeader['Report_Attributes'] = $this->getAttributes();
|
|
}
|
|
if (!empty($this->warnings)) {
|
|
$reportHeader['Exceptions'] = $this->warnings;
|
|
}
|
|
|
|
return $reportHeader;
|
|
}
|
|
|
|
/** Get report header for TSV reports */
|
|
public function getTSVReportHeader(): array
|
|
{
|
|
$institutionIds = [];
|
|
if (isset($this->institutionIds)) {
|
|
foreach ($this->institutionIds as $institutionId) {
|
|
if ($institutionId['Type'] == 'Proprietary') {
|
|
$institutionIds[] = $institutionId['Value'];
|
|
} else {
|
|
$institutionIds[] = $institutionId['Type'] . ':' . $institutionId['Value'];
|
|
}
|
|
}
|
|
}
|
|
$reportHeaderInstitutionId = !empty($institutionIds) ? implode(';', $institutionIds) : '';
|
|
$reportHeaderMetricTypes = $beginDate = $endDate = '';
|
|
$reportHeaderFilters = $reportHeaderAttributes = [];
|
|
foreach ($this->filters as $filter) {
|
|
switch ($filter['Name']) {
|
|
case ('Metric_Type'):
|
|
$reportHeaderMetricTypes = implode(';', explode('|', $filter['Value']));
|
|
break;
|
|
case ('Begin_Date'):
|
|
$beginDate = $filter['Name'] . '=' . $filter['Value'];
|
|
break;
|
|
case ('End_Date'):
|
|
$endDate = $filter['Name'] . '=' . $filter['Value'];
|
|
break;
|
|
default:
|
|
$reportHeaderFilters[] = $filter['Name'] . '=' . $filter['Value'];
|
|
}
|
|
}
|
|
foreach ($this->attributes as $attribute) {
|
|
if ($attribute['Name'] == 'granularity') {
|
|
$excludeMonthlyDetails = $attribute['Value'] == 'Month' ? 'False' : 'True';
|
|
$reportHeaderAttributes[] = 'Exclude_Monthly_Details' . '=' . $excludeMonthlyDetails;
|
|
} else {
|
|
$reportHeaderAttributes[] = $attribute['Name'] . '=' . $attribute['Value'];
|
|
}
|
|
}
|
|
|
|
$exceptions = [];
|
|
foreach ($this->warnings as $warning) {
|
|
$exceptions[] = $warning['Code'] . ':' . $warning['Message'] . '(' . $warning['Data'] . ')';
|
|
}
|
|
|
|
$reportHeader = [
|
|
['Report_Name', $this->getName()],
|
|
['Report_ID', $this->getID()],
|
|
['Release', $this->getRelease()],
|
|
['Institution_Name', $this->institutionName],
|
|
['Institution_ID', $reportHeaderInstitutionId],
|
|
['Metric_Types', $reportHeaderMetricTypes],
|
|
['Report_Filters', implode(';', $reportHeaderFilters)],
|
|
['Report_Attributes', implode(';', $reportHeaderAttributes)],
|
|
['Exceptions', implode(';', $exceptions)],
|
|
['Reporting_Period', $beginDate . ';' . $endDate],
|
|
['Created', date('Y-m-d\TH:i:s\Z', time())],
|
|
['Created_By', $this->platformName],
|
|
];
|
|
return $reportHeader;
|
|
}
|
|
|
|
/** Get monthly period */
|
|
protected function getMonthlyDatePeriod(): DatePeriod
|
|
{
|
|
// every month for the given period needs to be considered
|
|
$start = new DateTime($this->beginDate);
|
|
$end = new DateTime($this->endDate);
|
|
$interval = DateInterval::createFromDateString('1 month');
|
|
return new DatePeriod($start, $interval, $end);
|
|
}
|
|
|
|
/**
|
|
* Validate date, check if the date is a valid date and in requested format
|
|
*/
|
|
protected function validateDate(string $date, string $format = 'Y-m-d'): bool
|
|
{
|
|
$d = DateTime::createFromFormat($format, $date);
|
|
return $d && $d->format($format) === $date;
|
|
}
|
|
|
|
/**
|
|
* Get report form fields common to all reports
|
|
*/
|
|
public static function getCommonReportSettingsFormFields(): array
|
|
{
|
|
$context = Application::get()->getRequest()->getContext();
|
|
$institutions = Repo::institution()->getCollector()
|
|
->filterByContextIds([$context->getId()])
|
|
->getMany();
|
|
|
|
$institutionOptions = [['value' => '0', 'label' => 'The World']];
|
|
foreach ($institutions as $institution) {
|
|
$institutionOptions[] = ['value' => $institution->getId(), 'label' => $institution->getLocalizedName()];
|
|
}
|
|
|
|
$earliestDate = self::getEarliestDate();
|
|
$lastDate = self::getLastDate();
|
|
|
|
return [
|
|
new FieldText('begin_date', [
|
|
'label' => __('manager.statistics.counterR5Report.settings.startDate'),
|
|
'description' => __('manager.statistics.counterR5Report.settings.date.startDate.description', ['earliestDate' => $earliestDate]),
|
|
'size' => 'small',
|
|
'isMultilingual' => false,
|
|
'isRequired' => true,
|
|
'value' => $earliestDate,
|
|
'groupId' => 'default',
|
|
]),
|
|
new FieldText('end_date', [
|
|
'label' => __('manager.statistics.counterR5Report.settings.endDate'),
|
|
'description' => __('manager.statistics.counterR5Report.settings.date.endDate.description', ['lastDate' => $lastDate]),
|
|
'size' => 'small',
|
|
'isMultilingual' => false,
|
|
'isRequired' => true,
|
|
'value' => $lastDate,
|
|
'groupId' => 'default',
|
|
]),
|
|
new FieldSelect('customer_id', [
|
|
'label' => __('manager.statistics.counterR5Report.settings.customerId'),
|
|
'options' => $institutionOptions,
|
|
'value' => '0',
|
|
'isRequired' => true,
|
|
'groupId' => 'default',
|
|
]),
|
|
];
|
|
}
|
|
}
|