first commit
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup citation Citation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file classes/citation/Citation.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 Citation
|
||||
*
|
||||
* @ingroup citation
|
||||
*
|
||||
* @brief Class representing a citation (bibliographic reference)
|
||||
*/
|
||||
|
||||
namespace PKP\citation;
|
||||
|
||||
use PKP\core\PKPString;
|
||||
|
||||
class Citation extends \PKP\core\DataObject
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $rawCitation an unparsed citation string
|
||||
*/
|
||||
public function __construct($rawCitation = null)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setRawCitation($rawCitation);
|
||||
}
|
||||
|
||||
//
|
||||
// Getters and Setters
|
||||
//
|
||||
|
||||
/**
|
||||
* Replace URLs through HTML links, if the citation does not already contain HTML links
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCitationWithLinks()
|
||||
{
|
||||
$citation = $this->getRawCitation();
|
||||
if (stripos($citation, '<a href=') === false) {
|
||||
$citation = preg_replace_callback(
|
||||
'#(http|https|ftp)://[\d\w\.-]+\.[\w\.]{2,6}[^\s\]\[\<\>]*/?#',
|
||||
function ($matches) {
|
||||
$trailingDot = in_array($char = substr($matches[0], -1), ['.', ',']);
|
||||
$url = rtrim($matches[0], '.,');
|
||||
return "<a href=\"{$url}\">{$url}</a>" . ($trailingDot ? $char : '');
|
||||
},
|
||||
$citation
|
||||
);
|
||||
}
|
||||
return $citation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rawCitation
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawCitation()
|
||||
{
|
||||
return $this->getData('rawCitation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rawCitation
|
||||
*
|
||||
* @param string $rawCitation
|
||||
*/
|
||||
public function setRawCitation($rawCitation)
|
||||
{
|
||||
$rawCitation = $this->_cleanCitationString($rawCitation);
|
||||
$this->setData('rawCitation', $rawCitation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sequence number
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSequence()
|
||||
{
|
||||
return $this->getData('seq');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sequence number
|
||||
*
|
||||
* @param int $seq
|
||||
*/
|
||||
public function setSequence($seq)
|
||||
{
|
||||
$this->setData('seq', $seq);
|
||||
}
|
||||
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
/**
|
||||
* Take a citation string and clean/normalize it
|
||||
*
|
||||
* @param string $citationString
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function _cleanCitationString($citationString)
|
||||
{
|
||||
// 1) Strip slashes and whitespace
|
||||
$citationString = trim(stripslashes($citationString));
|
||||
|
||||
// 2) Normalize whitespace
|
||||
$citationString = PKPString::regexp_replace('/[\s]+/', ' ', $citationString);
|
||||
|
||||
return $citationString;
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\citation\Citation', '\Citation');
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/citation/CitationDAO.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 CitationDAO
|
||||
*
|
||||
* @ingroup citation
|
||||
*
|
||||
* @see Citation
|
||||
*
|
||||
* @brief Operations for retrieving and modifying Citation objects
|
||||
*/
|
||||
|
||||
namespace PKP\citation;
|
||||
|
||||
use PKP\db\DAOResultFactory;
|
||||
use PKP\plugins\Hook;
|
||||
|
||||
class CitationDAO extends \PKP\db\DAO
|
||||
{
|
||||
/**
|
||||
* Insert a new citation.
|
||||
*
|
||||
* @param Citation $citation
|
||||
*
|
||||
* @return int the new citation id
|
||||
*/
|
||||
public function insertObject($citation)
|
||||
{
|
||||
$seq = $citation->getSequence();
|
||||
if (!(is_numeric($seq) && $seq > 0)) {
|
||||
// Find the latest sequence number
|
||||
$result = $this->retrieve(
|
||||
'SELECT MAX(seq) AS lastseq FROM citations
|
||||
WHERE publication_id = ?',
|
||||
[(int)$citation->getData('publicationId')]
|
||||
);
|
||||
$row = $result->current();
|
||||
$citation->setSequence($row ? $row->lastseq + 1 : 1);
|
||||
}
|
||||
|
||||
$this->update(
|
||||
sprintf('INSERT INTO citations
|
||||
(publication_id, raw_citation, seq)
|
||||
VALUES
|
||||
(?, ?, ?)'),
|
||||
[
|
||||
(int) $citation->getData('publicationId'),
|
||||
$citation->getRawCitation(),
|
||||
(int) $seq
|
||||
]
|
||||
);
|
||||
$citation->setId($this->getInsertId());
|
||||
$this->_updateObjectMetadata($citation);
|
||||
return $citation->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a citation by id.
|
||||
*
|
||||
* @param int $citationId
|
||||
*
|
||||
* @return ?Citation
|
||||
*/
|
||||
public function getById($citationId)
|
||||
{
|
||||
$result = $this->retrieve(
|
||||
'SELECT * FROM citations WHERE citation_id = ?',
|
||||
[$citationId]
|
||||
);
|
||||
$row = $result->current();
|
||||
return $row ? $this->_fromRow((array) $row) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import citations from a raw citation list of the particular publication.
|
||||
*
|
||||
* @param int $publicationId
|
||||
* @param string $rawCitationList
|
||||
*/
|
||||
public function importCitations($publicationId, $rawCitationList)
|
||||
{
|
||||
assert(is_numeric($publicationId));
|
||||
$publicationId = (int) $publicationId;
|
||||
|
||||
$existingCitations = $this->getByPublicationId($publicationId)->toAssociativeArray();
|
||||
|
||||
// Remove existing citations.
|
||||
$this->deleteByPublicationId($publicationId);
|
||||
|
||||
// Tokenize raw citations
|
||||
$citationTokenizer = new CitationListTokenizerFilter();
|
||||
$citationStrings = $citationTokenizer->execute($rawCitationList);
|
||||
|
||||
// Instantiate and persist citations
|
||||
$importedCitations = [];
|
||||
if (is_array($citationStrings)) {
|
||||
foreach ($citationStrings as $seq => $citationString) {
|
||||
if (!empty(trim($citationString))) {
|
||||
$citation = new Citation($citationString);
|
||||
// Set the publication
|
||||
$citation->setData('publicationId', $publicationId);
|
||||
// Set the counter
|
||||
$citation->setSequence($seq + 1);
|
||||
|
||||
$this->insertObject($citation);
|
||||
|
||||
$importedCitations[] = $citation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Hook::call('CitationDAO::afterImportCitations', [$publicationId, $existingCitations, $importedCitations]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an array of citations matching a particular publication id.
|
||||
*
|
||||
* @param int $publicationId
|
||||
* @param ?\PKP\db\DBResultRange $rangeInfo
|
||||
*
|
||||
* @return DAOResultFactory<Citation> containing matching Citations
|
||||
*/
|
||||
public function getByPublicationId($publicationId, $rangeInfo = null)
|
||||
{
|
||||
$result = $this->retrieveRange(
|
||||
'SELECT *
|
||||
FROM citations
|
||||
WHERE publication_id = ?
|
||||
ORDER BY seq, citation_id',
|
||||
[(int)$publicationId],
|
||||
$rangeInfo
|
||||
);
|
||||
return new DAOResultFactory($result, $this, '_fromRow', ['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing citation.
|
||||
*
|
||||
* @param Citation $citation
|
||||
*/
|
||||
public function updateObject($citation)
|
||||
{
|
||||
$returner = $this->update(
|
||||
'UPDATE citations
|
||||
SET publication_id = ?,
|
||||
raw_citation = ?,
|
||||
seq = ?
|
||||
WHERE citation_id = ?',
|
||||
[
|
||||
(int) $citation->getData('publicationId'),
|
||||
$citation->getRawCitation(),
|
||||
(int) $citation->getSequence(),
|
||||
(int) $citation->getId()
|
||||
]
|
||||
);
|
||||
$this->_updateObjectMetadata($citation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a citation.
|
||||
*
|
||||
* @param Citation $citation
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteObject($citation)
|
||||
{
|
||||
return $this->deleteById($citation->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a citation by id.
|
||||
*
|
||||
* @param int $citationId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteById($citationId)
|
||||
{
|
||||
$this->update('DELETE FROM citation_settings WHERE citation_id = ?', [(int) $citationId]);
|
||||
return $this->update('DELETE FROM citations WHERE citation_id = ?', [(int) $citationId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all citations matching a particular publication id.
|
||||
*
|
||||
* @param int $publicationId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteByPublicationId($publicationId)
|
||||
{
|
||||
$citations = $this->getByPublicationId($publicationId);
|
||||
while ($citation = $citations->next()) {
|
||||
$this->deleteById($citation->getId());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Private helper methods
|
||||
//
|
||||
/**
|
||||
* Construct a new citation object.
|
||||
*
|
||||
* @return Citation
|
||||
*/
|
||||
public function _newDataObject()
|
||||
{
|
||||
return new Citation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to return a citation object from a
|
||||
* row.
|
||||
*
|
||||
* @param array $row
|
||||
*
|
||||
* @return Citation
|
||||
*/
|
||||
public function _fromRow($row)
|
||||
{
|
||||
$citation = $this->_newDataObject();
|
||||
$citation->setId((int)$row['citation_id']);
|
||||
$citation->setData('publicationId', (int)$row['publication_id']);
|
||||
$citation->setRawCitation($row['raw_citation']);
|
||||
$citation->setSequence((int)$row['seq']);
|
||||
|
||||
$this->getDataObjectSettings('citation_settings', 'citation_id', $row['citation_id'], $citation);
|
||||
|
||||
return $citation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the citation meta-data
|
||||
*
|
||||
* @param Citation $citation
|
||||
*/
|
||||
public function _updateObjectMetadata($citation)
|
||||
{
|
||||
$this->updateDataObjectSettings('citation_settings', $citation, ['citation_id' => $citation->getId()]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\citation\CitationDAO', '\CitationDAO');
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/citation/CitationListTokenizerFilter.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 CitationListTokenizerFilter
|
||||
*
|
||||
* @ingroup classes_citation
|
||||
*
|
||||
* @brief Class that takes an unformatted list of citations
|
||||
* and returns an array of raw citation strings.
|
||||
*/
|
||||
|
||||
namespace PKP\citation;
|
||||
|
||||
use PKP\core\PKPString;
|
||||
use PKP\filter\Filter;
|
||||
|
||||
class CitationListTokenizerFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setDisplayName('Split a reference list into separate citations');
|
||||
|
||||
parent::__construct('primitive::string', 'primitive::string[]');
|
||||
}
|
||||
|
||||
//
|
||||
// Implement template methods from Filter
|
||||
//
|
||||
/**
|
||||
* @see Filter::process()
|
||||
*
|
||||
* @param string $input
|
||||
*
|
||||
* @return mixed array
|
||||
*/
|
||||
public function &process(&$input)
|
||||
{
|
||||
// The default implementation assumes that raw citations are
|
||||
// separated with line endings.
|
||||
// 1) Remove empty lines and normalize line endings.
|
||||
$input = PKPString::regexp_replace('/[\r\n]+/s', "\n", $input);
|
||||
// 2) Remove trailing/leading line breaks.
|
||||
$input = trim($input, "\n");
|
||||
// 3) Break up at line endings.
|
||||
if (empty($input)) {
|
||||
$citations = [];
|
||||
} else {
|
||||
$citations = explode("\n", $input);
|
||||
}
|
||||
// 4) Remove numbers from the beginning of each citation.
|
||||
foreach ($citations as $index => $citation) {
|
||||
$citations[$index] = PKPString::regexp_replace('/^\s*[\[#]?[0-9]+[.)\]]?\s*/', '', $citation);
|
||||
}
|
||||
|
||||
return $citations;
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\citation\CitationListTokenizerFilter', '\CitationListTokenizerFilter');
|
||||
}
|
||||
Reference in New Issue
Block a user