<?php
/**
* @file plugins/generic/recommendByAuthor/RecommendByAuthorPlugin.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class RecommendByAuthorPlugin
*
* @brief Plugin to recommend articles from the same author.
*/
namespace APP\plugins\generic\recommendByAuthor;
use APP\author\Author;
use APP\core\Application;
use APP\core\Services;
use APP\facades\Repo;
use APP\handler\Handler;
use APP\search\ArticleSearch;
use APP\statistics\StatisticsHelper;
use PKP\core\VirtualArrayIterator;
use PKP\plugins\GenericPlugin;
use PKP\plugins\Hook;
use PKP\submission\PKPSubmission;
class RecommendByAuthorPlugin extends GenericPlugin
{
public const RECOMMEND_BY_AUTHOR_PLUGIN_COUNT = 10;
//
// Implement template methods from Plugin.
//
/**
* @copydoc Plugin::register()
*
* @param null|mixed $mainContextId
*/
public function register($category, $path, $mainContextId = null)
{
$success = parent::register($category, $path, $mainContextId);
if (Application::isUnderMaintenance()) {
return $success;
}
if ($success && $this->getEnabled($mainContextId)) {
Hook::add('Templates::Article::Footer::PageFooter', [$this, 'callbackTemplateArticlePageFooter']);
}
return $success;
}
/**
* @copydoc Plugin::getDisplayName()
*/
public function getDisplayName()
{
return __('plugins.generic.recommendByAuthor.displayName');
}
/**
* @copydoc Plugin::getDescription()
*/
public function getDescription()
{
return __('plugins.generic.recommendByAuthor.description');
}
//
// View level hook implementations.
//
/**
* Add content to the article footer.
*/
public function callbackTemplateArticlePageFooter($hookName, $params)
{
$smarty = & $params[1];
$output = & $params[2];
// Find articles of the same author(s).
$displayedArticle = $smarty->getTemplateVars('article');
$displayedPublication = $smarty->getTemplateVars('publication');
$authors = $displayedPublication->getData('authors');
$foundArticles = [];
foreach ($authors as $author) { /** @var Author $author */
// The following article search is by name only as authors are
// not normalized in OJS. This is rather crude and may produce
// false positives or miss some entries. But there's no other way
// until OJS allows users to consistently normalize authors (via name,
// email, ORCID, whatever).
$authorsIterator = Repo::author()
->getCollector()
->filterByContextIds([$displayedArticle->getData('contextId')])
->filterByName($author->getLocalizedGivenName(), $author->getLocalizedFamilyName())
->getMany();
$publicationIds = [];
foreach ($authorsIterator as $thisAuthor) {
$publicationIds[] = $thisAuthor->getData('publicationId');
}
$submissionIds = array_map(function ($publicationId) {
$publication = Repo::publication()->get($publicationId);
return $publication->getData('status') == PKPSubmission::STATUS_PUBLISHED ? $publication->getData('submissionId') : null;
}, array_unique($publicationIds));
$foundArticles = array_unique(array_merge($foundArticles, $submissionIds));
}
$results = array_filter($foundArticles, function ($value) use ($displayedArticle) {
if ($value !== $displayedArticle->getId()) {
return $value;
}
return null;
});
// Order results by metric.
$filters = [
'contextIds' => [$displayedArticle->getData('contextId')],
'submissionIds' => $results,
'assocTypes' => [Application::ASSOC_TYPE_SUBMISSION, Application::ASSOC_TYPE_SUBMISSION_FILE]
];
$orderedResults = [];
if ($results) {
// pkp/pkp-lib#9512: Check $results above, as an empty list of submissionIds is treated as no filter at all.
$statsReport = Services::get('publicationStats')->getTotals($filters);
foreach ($statsReport as $reportRow) {
$orderedResults[] = $reportRow->{StatisticsHelper::STATISTICS_DIMENSION_SUBMISSION_ID};
}
}
// Make sure we even get results that have no statistics (yet) and that
// we get them in some consistent order for paging.
$remainingResults = array_diff($results, $orderedResults);
sort($remainingResults);
$orderedResults = array_merge($orderedResults, $remainingResults);
// Pagination.
$request = Application::get()->getRequest();
$rangeInfo = Handler::getRangeInfo($request, 'articlesBySameAuthor');
if ($rangeInfo && $rangeInfo->isValid()) {
$page = $rangeInfo->getPage();
} else {
$page = 1;
}
$totalResults = count($orderedResults);
$itemsPerPage = self::RECOMMEND_BY_AUTHOR_PLUGIN_COUNT;
$offset = $itemsPerPage * ($page - 1);
$length = max($totalResults - $offset, 0);
$length = min($itemsPerPage, $length);
if ($length == 0) {
$pagedResults = [];
} else {
$pagedResults = array_slice(
$orderedResults,
$offset,
$length
);
}
// Visualization.
$articleSearch = new ArticleSearch();
$pagedResults = $articleSearch->formatResults($pagedResults);
$returner = new VirtualArrayIterator($pagedResults, $totalResults, $page, $itemsPerPage);
$smarty->assign('articlesBySameAuthor', $returner);
$output .= $smarty->fetch($this->getTemplateResource('articleFooter.tpl'));
return false;
}
}
|