first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-06-08 17:09:23 -04:00
commit df3a033196
17887 changed files with 8637778 additions and 0 deletions
+231
View File
@@ -0,0 +1,231 @@
<?php
/**
* @file classes/services/ContextService.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ContextService
*
* @ingroup services
*
* @brief Extends the base context service class with app-specific
* requirements.
*/
namespace APP\services;
use APP\article\ArticleTombstoneManager;
use APP\core\Application;
use APP\facades\Repo;
use APP\file\PublicFileManager;
use APP\subscription\IndividualSubscriptionDAO;
use APP\subscription\InstitutionalSubscriptionDAO;
use APP\subscription\SubscriptionTypeDAO;
use PKP\config\Config;
use PKP\db\DAORegistry;
use PKP\file\TemporaryFileManager;
use PKP\plugins\Hook;
use PKP\submission\GenreDAO;
class ContextService extends \PKP\services\PKPContextService
{
/** @copydoc \PKP\services\PKPContextService::$contextsFileDirName */
public $contextsFileDirName = 'journals';
/**
* Initialize hooks for extending PKPContextService
*/
public function __construct()
{
$this->installFileDirs = [
Config::getVar('files', 'files_dir') . '/%s/%d',
Config::getVar('files', 'files_dir') . '/%s/%d/articles',
Config::getVar('files', 'files_dir') . '/%s/%d/issues',
Config::getVar('files', 'public_files_dir') . '/%s/%d',
];
Hook::add('Context::add', [$this, 'afterAddContext']);
Hook::add('Context::edit', [$this, 'afterEditContext']);
Hook::add('Context::delete::before', [$this, 'beforeDeleteContext']);
Hook::add('Context::delete', [$this, 'afterDeleteContext']);
Hook::add('Context::validate', [$this, 'validateContext']);
}
/**
* Take additional actions after a new context has been added
*
* @param string $hookName
* @param array $args [
*
* @option Journal The new context
* @option Request
* ]
*/
public function afterAddContext($hookName, $args)
{
$context = $args[0];
// Create a default section
$section = Repo::section()->newDataObject();
$section->setTitle(__('section.default.title'), $context->getPrimaryLocale());
$section->setAbbrev(__('section.default.abbrev'), $context->getPrimaryLocale());
$section->setMetaIndexed(true);
$section->setMetaReviewed(true);
$section->setPolicy(__('section.default.policy'), $context->getPrimaryLocale());
$section->setEditorRestricted(false);
$section->setHideTitle(false);
$section->setContextId($context->getId());
Repo::section()->add($section);
}
/**
* Update journal-specific settings when a context is edited
*
* @param string $hookName
* @param array $args [
*
* @option Journal The new context
* @option Journal The current context
* @option array The params to edit
* @option Request
* ]
*/
public function afterEditContext($hookName, $args)
{
$newContext = $args[0];
$currentContext = $args[1];
$params = $args[2];
$request = $args[3];
// Move an uploaded journal thumbnail and set the updated data
if (!empty($params['journalThumbnail'])) {
$supportedLocales = $newContext->getSupportedFormLocales();
foreach ($supportedLocales as $localeKey) {
if (!array_key_exists($localeKey, $params['journalThumbnail'])) {
continue;
}
$localeValue = $this->_saveFileParam(
$newContext,
$params['journalThumbnail'][$localeKey],
'journalThumbnail',
$request->getUser()->getId(),
$localeKey,
true
);
$newContext->setData('journalThumbnail', $localeValue, $localeKey);
}
}
// If the context is enabled or disabled, create or delete
// tombstones for all published submissions
if ($newContext->getData('enabled') !== $currentContext->getData('enabled')) {
$articleTombstoneManager = new ArticleTombstoneManager();
if ($newContext->getData('enabled')) {
$articleTombstoneManager->deleteTombstonesByContextId($newContext->getId());
} else {
$articleTombstoneManager->insertTombstonesByContext($newContext);
}
}
}
/**
* Perform actions before a context has been deleted
*
* This should only be used in cases where you need the context to still exist
* in the database to complete the actions. Otherwise, use
* ContextService::afterDeleteContext().
*
* @param string $hookName
* @param array $args [
*
* @option Context The new context
* @option Request
* ]
*/
public function beforeDeleteContext($hookName, $args)
{
$context = $args[0];
// Create tombstones for all published submissions
$articleTombstoneManager = new ArticleTombstoneManager();
$articleTombstoneManager->insertTombstonesByContext($context);
/** @var GenreDAO */
$genreDao = DAORegistry::getDAO('GenreDAO');
$genreDao->deleteByContextId($context->getId());
}
/**
* Take additional actions after a context has been deleted
*
* @param string $hookName
* @param array $args [
*
* @option Journal The new context
* @option Request
* ]
*/
public function afterDeleteContext($hookName, $args)
{
$context = $args[0];
Repo::section()->deleteByContextId($context->getId());
Repo::issue()->deleteByContextId($context->getId());
/** @var IndividualSubscriptionDAO */
$subscriptionDao = DAORegistry::getDAO('IndividualSubscriptionDAO');
$subscriptionDao->deleteByJournalId($context->getId());
/** @var InstitutionalSubscriptionDAO */
$subscriptionDao = DAORegistry::getDAO('InstitutionalSubscriptionDAO');
$subscriptionDao->deleteByJournalId($context->getId());
/** @var SubscriptionTypeDAO */
$subscriptionTypeDao = DAORegistry::getDAO('SubscriptionTypeDAO');
$subscriptionTypeDao->deleteByJournal($context->getId());
Repo::submission()->deleteByContextId($context->getId());
$publicFileManager = new PublicFileManager();
$publicFileManager->rmtree($publicFileManager->getContextFilesPath($context->getId()));
}
/**
* Make additional validation checks
*
* @param string $hookName
* @param array $args [
*
* @option Journal The new context
* @option Request
* ]
*/
public function validateContext($hookName, $args)
{
$errors = & $args[0];
$props = $args[2];
$allowedLocales = $args[3];
if (!isset($props['journalThumbnail'])) {
return;
}
// If a journal thumbnail is passed, check that the temporary file exists
// and the current user owns it
$user = Application::get()->getRequest()->getUser();
$userId = $user ? $user->getId() : null;
$temporaryFileManager = new TemporaryFileManager();
if (isset($props['journalThumbnail']) && empty($errors['journalThumbnail'])) {
foreach ($allowedLocales as $localeKey) {
if (empty($props['journalThumbnail'][$localeKey]) || empty($props['journalThumbnail'][$localeKey]['temporaryFileId'])) {
continue;
}
if (!$temporaryFileManager->getFile($props['journalThumbnail'][$localeKey]['temporaryFileId'], $userId)) {
if (!is_array($errors['journalThumbnail'])) {
$errors['journalThumbnail'] = [];
}
$errors['journalThumbnail'][$localeKey] = [__('common.noTemporaryFile')];
}
}
}
}
}
+174
View File
@@ -0,0 +1,174 @@
<?php
/**
* @file classes/services/NavigationMenuService.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class NavigationMenuService
*
* @ingroup services
*
* @brief Helper class that encapsulates NavigationMenu business logic
*/
namespace APP\services;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\plugins\Hook;
use PKP\security\Validation;
class NavigationMenuService extends \PKP\services\PKPNavigationMenuService
{
// Types for all ojs default navigationMenuItems
public const NMI_TYPE_SUBSCRIPTIONS = 'NMI_TYPE_SUBSCRIPTIONS';
public const NMI_TYPE_MY_SUBSCRIPTIONS = 'NMI_TYPE_MY_SUBSCRIPTIONS';
public const NMI_TYPE_CURRENT = 'NMI_TYPE_CURRENT';
public const NMI_TYPE_ARCHIVES = 'NMI_TYPE_ARCHIVES';
/**
* Initialize hooks for extending PKPNavigationMenuService
*/
public function __construct()
{
Hook::add('NavigationMenus::itemTypes', [$this, 'getMenuItemTypesCallback']);
Hook::add('NavigationMenus::displaySettings', [$this, 'getDisplayStatusCallback']);
}
/**
* Return all default navigationMenuItemTypes.
*
* @param string $hookName
* @param array $args of arguments passed
*/
public function getMenuItemTypesCallback($hookName, $args)
{
$types = & $args[0];
$ojsTypes = [
self::NMI_TYPE_CURRENT => [
'title' => __('editor.issues.currentIssue'),
'description' => __('manager.navigationMenus.current.description'),
],
self::NMI_TYPE_ARCHIVES => [
'title' => __('navigation.archives'),
'description' => __('manager.navigationMenus.archives.description'),
],
self::NMI_TYPE_SUBSCRIPTIONS => [
'title' => __('navigation.subscriptions'),
'description' => __('manager.navigationMenus.subscriptions.description'),
'conditionalWarning' => __('manager.navigationMenus.subscriptions.conditionalWarning'),
],
self::NMI_TYPE_MY_SUBSCRIPTIONS => [
'title' => __('user.subscriptions.mySubscriptions'),
'description' => __('manager.navigationMenus.mySubscriptions.description'),
'conditionalWarning' => __('manager.navigationMenus.mySubscriptions.conditionalWarning'),
],
];
$types = array_merge($types, $ojsTypes);
}
/**
* Callback for display menu item functionality
*
* @param string $hookName
* @param array $args of arguments passed
*/
public function getDisplayStatusCallback($hookName, $args)
{
$navigationMenuItem = & $args[0];
$request = Application::get()->getRequest();
$dispatcher = $request->getDispatcher();
$templateMgr = TemplateManager::getManager(Application::get()->getRequest());
$isUserLoggedIn = Validation::isLoggedIn();
$isUserLoggedInAs = Validation::loggedInAs();
$context = $request->getContext();
$this->transformNavMenuItemTitle($templateMgr, $navigationMenuItem);
$menuItemType = $navigationMenuItem->getType();
// Conditionally hide some items
switch ($menuItemType) {
case self::NMI_TYPE_CURRENT:
case self::NMI_TYPE_ARCHIVES:
$navigationMenuItem->setIsDisplayed($context && $context->getData('publishingMode') != \APP\journal\Journal::PUBLISHING_MODE_NONE);
break;
case self::NMI_TYPE_SUBSCRIPTIONS:
if ($context) {
$paymentManager = Application::getPaymentManager($context);
$navigationMenuItem->setIsDisplayed($context->getData('paymentsEnabled') && $paymentManager->isConfigured());
}
break;
case self::NMI_TYPE_MY_SUBSCRIPTIONS:
if ($context) {
$paymentManager = Application::getPaymentManager($context);
$navigationMenuItem->setIsDisplayed(Validation::isLoggedIn() && $context->getData('paymentsEnabled') && $paymentManager->isConfigured() && $context->getData('publishingMode') == \APP\journal\Journal::PUBLISHING_MODE_SUBSCRIPTION);
}
break;
}
if ($navigationMenuItem->getIsDisplayed()) {
// Set the URL
switch ($menuItemType) {
case self::NMI_TYPE_CURRENT:
$navigationMenuItem->setUrl($dispatcher->url(
$request,
Application::ROUTE_PAGE,
null,
'issue',
'current',
null
));
break;
case self::NMI_TYPE_ARCHIVES:
$navigationMenuItem->setUrl($dispatcher->url(
$request,
Application::ROUTE_PAGE,
null,
'issue',
'archive',
null
));
break;
case self::NMI_TYPE_SUBSCRIPTIONS:
$navigationMenuItem->setUrl($dispatcher->url(
$request,
Application::ROUTE_PAGE,
null,
'about',
'subscriptions',
null
));
break;
case self::NMI_TYPE_MY_SUBSCRIPTIONS:
$navigationMenuItem->setUrl($dispatcher->url(
$request,
Application::ROUTE_PAGE,
null,
'user',
'subscriptions',
null
));
break;
}
}
}
}
if (!PKP_STRICT_MODE) {
foreach ([
'NMI_TYPE_SUBSCRIPTIONS',
'NMI_TYPE_MY_SUBSCRIPTIONS',
'NMI_TYPE_CURRENT',
'NMI_TYPE_ARCHIVES',
] as $constantName) {
define($constantName, constant('\APP\services\NavigationMenuService::' . $constantName));
}
}
+89
View File
@@ -0,0 +1,89 @@
<?php
/**
* @file classes/services/OJSServiceProvider.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class OJSServiceProvider
*
* @ingroup services
*
* @brief Utility class to package all OJS services
*/
namespace APP\services;
use Pimple\Container;
use PKP\services\PKPFileService;
use PKP\services\PKPSchemaService;
use PKP\services\PKPSiteService;
use PKP\services\PKPStatsContextService;
use PKP\services\PKPStatsGeoService;
use PKP\services\PKPStatsSushiService;
class OJSServiceProvider implements \Pimple\ServiceProviderInterface
{
/**
* Registers services
*
*/
public function register(Container $pimple)
{
// File service
$pimple['file'] = function () {
return new PKPFileService();
};
// NavigationMenus service
$pimple['navigationMenu'] = function () {
return new NavigationMenuService();
};
// Context service
$pimple['context'] = function () {
return new ContextService();
};
// Site service
$pimple['site'] = function () {
return new PKPSiteService();
};
// Schema service
$pimple['schema'] = function () {
return new PKPSchemaService();
};
// Context statistics service
$pimple['contextStats'] = function () {
return new PKPStatsContextService();
};
// Publication statistics service
$pimple['publicationStats'] = function () {
return new StatsPublicationService();
};
// Issue statistics service
$pimple['issueStats'] = function () {
return new StatsIssueService();
};
// Geo statistics service
$pimple['geoStats'] = function () {
return new PKPStatsGeoService();
};
// SUSHI statistics service
$pimple['sushiStats'] = function () {
return new PKPStatsSushiService();
};
// Editorial statistics service
$pimple['editorialStats'] = function () {
return new StatsEditorialService();
};
}
}
@@ -0,0 +1,34 @@
<?php
/**
* @file classes/services/StatsEditorialService.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class StatsEditorialService
*
* @ingroup services
*
* @brief Helper class that encapsulates business logic for getting
* editorial stats
*/
namespace APP\services;
class StatsEditorialService extends \PKP\services\PKPStatsEditorialService
{
/**
* Process the sectionIds param when getting the query builder
*
* @param array $args
*/
protected function getQueryBuilder($args = [])
{
$statsQB = parent::getQueryBuilder($args);
if (!empty(($args['sectionIds']))) {
$statsQB->filterBySections($args['sectionIds']);
}
return $statsQB;
}
}
+169
View File
@@ -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;
}
}
@@ -0,0 +1,29 @@
<?php
/**
* @file classes/services/StatsPublicationService.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 StatsPublicationService
*
* @ingroup services
*
* @brief Helper class that encapsulates publication statistics business logic
*/
namespace APP\services;
use APP\services\queryBuilders\StatsPublicationQueryBuilder;
class StatsPublicationService extends \PKP\services\PKPStatsPublicationService
{
protected function getAppSpecificFilters(StatsPublicationQueryBuilder &$statsQB, array $args = []): void
{
if (!empty(($args['issueIds']))) {
$statsQB->filterByIssues($args['issueIds']);
}
}
}
@@ -0,0 +1,28 @@
<?php
/**
* @file classes/services/QueryBuilders/ContextQueryBuilder.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ContextQueryBuilder
*
* @ingroup query_builders
*
* @brief Journal list query builder
*/
namespace APP\services\queryBuilders;
class ContextQueryBuilder extends \PKP\services\queryBuilders\PKPContextQueryBuilder
{
/** @copydoc \PKP\services\queryBuilders\PKPContextQueryBuilder::$db */
protected $db = 'journals';
/** @copydoc \PKP\services\queryBuilders\PKPContextQueryBuilder::$dbSettings */
protected $dbSettings = 'journal_settings';
/** @copydoc \PKP\services\queryBuilders\PKPContextQueryBuilder::$dbIdColumn */
protected $dbIdColumn = 'journal_id';
}
@@ -0,0 +1,108 @@
<?php
/**
* @file classes/services/QueryBuilders/GalleyQueryBuilder.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class GalleyQueryBuilder
*
* @ingroup query_builders
*
* @brief Class for building database queries for galleys
*/
namespace APP\services\queryBuilders;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use PKP\plugins\Hook;
use PKP\services\queryBuilders\interfaces\EntityQueryBuilderInterface;
class GalleyQueryBuilder implements EntityQueryBuilderInterface
{
/** @var array List of columns (see getQuery) */
public $columns;
/** @var array get authors for one or more publications */
protected $publicationIds = [];
public ?array $contextIds = null;
/**
* Set publicationIds filter
*
* @param array|int $publicationIds
*
* @return \APP\services\queryBuilders\GalleyQueryBuilder
*/
public function filterByPublicationIds($publicationIds)
{
$this->publicationIds = is_array($publicationIds) ? $publicationIds : [$publicationIds];
return $this;
}
public function filterByContexts(array $contextIds): self
{
$this->contextIds = $contextIds;
return $this;
}
/**
* @copydoc PKP\services\queryBuilders\interfaces\EntityQueryBuilderInterface::getCount()
*/
public function getCount()
{
return $this
->getQuery()
->select('g.galley_id')
->get()
->count();
}
/**
* @copydoc PKP\services\queryBuilders\interfaces\EntityQueryBuilderInterface::getCount()
*/
public function getIds()
{
return $this
->getQuery()
->select('g.galley_id')
->pluck('g.galley_id')
->toArray();
}
/**
* @copydoc PKP\services\queryBuilders\interfaces\EntityQueryBuilderInterface::getCount()
*/
public function getQuery()
{
$this->columns = ['*'];
$q = DB::table('publication_galleys as g');
if (!empty($this->publicationIds)) {
$q->whereIn('g.publication_id', $this->publicationIds);
}
// Contexts
$q->when($this->contextIds !== null, function (Builder $q) {
$q->whereIn('g.galley_id', function (Builder $q) {
$q->select('g.galley_id')
->from('publication_galleys as g')
->leftJoin('publications as p', 'p.publication_id', '=', 'g.publication_id')
->leftJoin('submissions as s', 's.submission_id', '=', 'p.submission_id')
->whereIn('s.context_id', $this->contextIds);
});
});
$q->orderBy('g.seq', 'asc');
// Add app-specific query statements
Hook::call('Galley::getMany::queryObject', [&$q, $this]);
$q->select($this->columns);
return $q;
}
}
@@ -0,0 +1,25 @@
<?php
/**
* @file classes/services/QueryBuilders/StatsEditorialQueryBuilder.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class StatsEditorialQueryBuilder
*
* @ingroup query_builders
*
* @brief Editorial statistics list query builder
*/
namespace APP\services\queryBuilders;
use PKP\services\queryBuilders\PKPStatsEditorialQueryBuilder;
class StatsEditorialQueryBuilder extends PKPStatsEditorialQueryBuilder
{
/** @var string The table column name for section IDs */
public $sectionIdsColumn = 'section_id';
}
@@ -0,0 +1,58 @@
<?php
/**
* @file classes/services/queryBuilders/StatsGeoQueryBuilder.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 StatsGeoQueryBuilder
*
* @ingroup query_builders
*
* @brief Helper class to construct a query to fetch geographic stats records from the
* metrics_submission_geo_monthly table.
*/
namespace APP\services\queryBuilders;
use APP\submission\Submission;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use PKP\services\queryBuilders\PKPStatsGeoQueryBuilder;
use PKP\statistics\PKPStatisticsHelper;
class StatsGeoQueryBuilder extends PKPStatsGeoQueryBuilder
{
/** Include records for these issues */
protected array $issueIds = [];
public function getSectionColumn(): string
{
return 'section_id';
}
/**
* Set the issues to get records for
*/
public function filterByIssues(array $issueIds): self
{
$this->issueIds = $issueIds;
return $this;
}
protected function _getAppSpecificQuery(Builder &$q): void
{
if (!empty($this->issueIds)) {
$issueSubmissionIds = DB::table('publications as p')->select('p.submission_id')->distinct()
->from('publications as p')
->leftJoin('publication_settings as ps', 'ps.setting_name', '=', DB::raw('\'issueId\''))
->where('p.status', Submission::STATUS_PUBLISHED)
->whereIn('ps.setting_value', $this->issueIds);
$q->joinSub($issueSubmissionIds, 'is', function ($join) {
$join->on('metrics_submission_geo_monthly.' . PKPStatisticsHelper::STATISTICS_DIMENSION_SUBMISSION_ID, '=', 'is.submission_id');
});
}
}
}
@@ -0,0 +1,137 @@
<?php
/**
* @file classes/services/queryBuilders/StatsIssueQueryBuilder.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 StatsIssueQueryBuilder
*
* @ingroup query_builders
*
* @brief Helper class to construct a query to fetch issue stats records from the
* metrics_issue table.
*/
namespace APP\services\queryBuilders;
use APP\core\Application;
use APP\statistics\StatisticsHelper;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use PKP\plugins\Hook;
use PKP\services\queryBuilders\PKPStatsQueryBuilder;
class StatsIssueQueryBuilder extends PKPStatsQueryBuilder
{
/** Include records for one of these object types: Application::ASSOC_TYPE_ISSUE, Application::ASSOC_TYPE_ISSUE_GALLEY */
protected array $assocTypes = [];
/** Include records for these issues */
protected array $issueIds = [];
/** Include records for these issues galleys */
protected array $issueGalleyIds = [];
/**
* Set the issues to get records for
*/
public function filterByIssues(array $issueIds): self
{
$this->issueIds = $issueIds;
return $this;
}
/**
* Set the issues to get records for
*/
public function filterByIssueGalleys(array $issueGalleyIds): self
{
$this->issueGalleyIds = $issueGalleyIds;
return $this;
}
/**
* Set the assocTypes to get records for
*/
public function filterByAssocTypes(array $assocTypes): self
{
$this->assocTypes = $assocTypes;
return $this;
}
/**
* Get issue IDs
*/
public function getIssueIds(): Builder
{
return $this->_getObject()
->select([StatisticsHelper::STATISTICS_DIMENSION_ISSUE_ID])
->distinct();
}
/**
* @copydoc PKPStatsQueryBuilder::getSelectColumns()
*/
protected function getSelectColumns(array $selectColumns): array
{
$selectColumns = parent::getSelectColumns($selectColumns);
// consider PKPStatisticsHelper::STATISTICS_DIMENSION_ASSOC_TYPE because it can be used in reports
if (in_array(StatisticsHelper::STATISTICS_DIMENSION_ASSOC_TYPE, $selectColumns)) {
foreach ($selectColumns as $i => $selectColumn) {
if ($selectColumn == StatisticsHelper::STATISTICS_DIMENSION_ASSOC_TYPE) {
$assocTypeIssue = Application::ASSOC_TYPE_ISSUE;
$assocTypeIssueGalley = Application::ASSOC_TYPE_ISSUE_GALLEY;
$selectColumns[$i] = DB::raw("CASE WHEN issue_galley_id IS NULL THEN '{$assocTypeIssue}' ELSE '{$assocTypeIssueGalley}' END AS assoc_type");
break;
}
}
}
return $selectColumns;
}
/**
* @copydoc PKPStatsQueryBuilder::_getObject()
*/
protected function _getObject(): Builder
{
$q = DB::table('metrics_issue');
if (!empty($this->contextIds)) {
$q->whereIn(StatisticsHelper::STATISTICS_DIMENSION_CONTEXT_ID, $this->contextIds);
}
if (!empty($this->issueIds)) {
$q->whereIn(StatisticsHelper::STATISTICS_DIMENSION_ISSUE_ID, $this->issueIds);
}
if (!empty($this->issueGalleyIds)) {
$q->whereIn(StatisticsHelper::STATISTICS_DIMENSION_ISSUE_GALLEY_ID, $this->issueGalleyIds);
}
if (!empty($this->assocTypes)) {
if (in_array(Application::ASSOC_TYPE_ISSUE, $this->assocTypes)) {
$q->whereNull(StatisticsHelper::STATISTICS_DIMENSION_ISSUE_GALLEY_ID);
} elseif (in_array(Application::ASSOC_TYPE_ISSUE_GALLEY, $this->assocTypes)) {
$q->whereNotNull(StatisticsHelper::STATISTICS_DIMENSION_ISSUE_GALLEY_ID);
}
}
$q->whereBetween(StatisticsHelper::STATISTICS_DIMENSION_DATE, [$this->dateStart, $this->dateEnd]);
if ($this->limit > 0) {
$q->limit($this->limit);
if ($this->offset > 0) {
$q->offset($this->offset);
}
}
Hook::call('StatsIssue::queryObject', [&$q, $this]);
return $q;
}
}
@@ -0,0 +1,58 @@
<?php
/**
* @file classes/services/queryBuilders/StatsPublicationQueryBuilder.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 StatsPublicationQueryBuilder
*
* @ingroup query_builders
*
* @brief Helper class to construct a query to fetch stats records from the
* metrics_submission table.
*/
namespace APP\services\queryBuilders;
use APP\submission\Submission;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use PKP\services\queryBuilders\PKPStatsPublicationQueryBuilder;
use PKP\statistics\PKPStatisticsHelper;
class StatsPublicationQueryBuilder extends PKPStatsPublicationQueryBuilder
{
/** Include records for these issues */
protected array $issueIds = [];
public function getSectionColumn(): string
{
return 'section_id';
}
/**
* Set the issues to get records for
*/
public function filterByIssues(array $issueIds): self
{
$this->issueIds = $issueIds;
return $this;
}
protected function _getAppSpecificQuery(Builder &$q): void
{
if (!empty($this->issueIds)) {
$issueSubmissionIds = DB::table('publications as p')->select('p.submission_id')->distinct()
->from('publications as p')
->leftJoin('publication_settings as ps', 'ps.setting_name', '=', DB::raw('\'issueId\''))
->where('p.status', Submission::STATUS_PUBLISHED)
->whereIn('ps.setting_value', $this->issueIds);
$q->joinSub($issueSubmissionIds, 'is', function ($join) {
$join->on('metrics_submission.' . PKPStatisticsHelper::STATISTICS_DIMENSION_SUBMISSION_ID, '=', 'is.submission_id');
});
}
}
}