setDisplayName('DataCite XML export'); parent::__construct($filterGroup); } // // Implement template methods from PersistableFilter // /** * @copydoc PersistableFilter::getClassName() */ function getClassName() { return 'plugins.importexport.datacite.filter.DataciteXmlFilter'; } // // Implement template methods from Filter // /** * @see Filter::process() * @param $pubObject Issue|PublishedArticle|ArticleGalley * @return DOMDocument */ function &process(&$pubObject) { // Create the XML document $doc = new DOMDocument('1.0', 'utf-8'); $doc->preserveWhiteSpace = false; $doc->formatOutput = true; $deployment = $this->getDeployment(); $context = $deployment->getContext(); $plugin = $deployment->getPlugin(); $cache = $plugin->getCache(); // Get all objects $issue = $article = $galley = $galleyFile = null; if (is_a($pubObject, 'Issue')) { $issue = $pubObject; if (!$cache->isCached('issues', $issue->getId())) { $cache->add($issue, null); } } elseif (is_a($pubObject, 'PublishedArticle')) { $article = $pubObject; if (!$cache->isCached('articles', $article->getId())) { $cache->add($article, null); } } elseif (is_a($pubObject, 'ArticleGalley')) { $galley = $pubObject; $galleyFile = $galley->getFile(); $articleId = $galley->getSubmissionId(); if ($cache->isCached('articles', $articleId)) { $article = $cache->get('articles', $articleId); } else { $articleDao = DAORegistry::getDAO('PublishedArticleDAO'); /* @var $articleDao PublishedArticleDAO */ $article = $articleDao->getByArticleId($pubObject->getSubmissionId(), $context->getId()); if ($article) $cache->add($article, null); } } if (!$issue) { $issueId = $article->getIssueId(); if ($cache->isCached('issues', $issueId)) { $issue = $cache->get('issues', $issueId); } else { $issueDao = DAORegistry::getDAO('IssueDAO'); /* @var $issueDao IssueDAO */ $issue = $issueDao->getById($issueId, $context->getId()); if ($issue) $cache->add($issue, null); } } // Identify the object locale. $objectLocalePrecedence = $this->getObjectLocalePrecedence($context, $article, $galley); // The publisher is required. // Use the journal title as DataCite recommends for now. $publisher = $this->getPrimaryTranslation($context->getName(null), $objectLocalePrecedence); assert(!empty($publisher)); // The publication date is required. $publicationDate = (isset($article) ? $article->getDatePublished() : null); if (empty($publicationDate)) { $publicationDate = $issue->getDatePublished(); } assert(!empty($publicationDate)); // Create the root node $rootNode = $this->createRootNode($doc); $doc->appendChild($rootNode); // DOI (mandatory) $doi = $pubObject->getStoredPubId('doi'); if ($plugin->isTestMode($context)) { $doi = PKPString::regexp_replace('#^[^/]+/#', DATACITE_API_TESTPREFIX . '/', $doi); } $rootNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'identifier', htmlspecialchars($doi, ENT_COMPAT, 'UTF-8'))); $node->setAttribute('identifierType', DATACITE_IDTYPE_DOI); // Creators (mandatory) $rootNode->appendChild($this->createCreatorsNode($doc, $issue, $article, $galley, $galleyFile, $publisher, $objectLocalePrecedence)); // Title (mandatory) $rootNode->appendChild($this->createTitlesNode($doc, $issue, $article, $galley, $galleyFile, $objectLocalePrecedence)); // Publisher (mandatory) $rootNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'publisher', htmlspecialchars($publisher, ENT_COMPAT, 'UTF-8'))); // Publication Year (mandatory) $rootNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'publicationYear', date('Y', strtotime($publicationDate)))); // Subjects $subject = null; if (!empty($galleyFile) && is_a($galleyFile, 'SupplementaryFile')) { $subject = $this->getPrimaryTranslation($galleyFile->getSubject(null), $objectLocalePrecedence); } elseif (!empty($article)) { $subject = $this->getPrimaryTranslation($article->getSubject(null), $objectLocalePrecedence); } if (!empty($subject)) { $subjectsNode = $doc->createElementNS($deployment->getNamespace(), 'subjects'); $subjectsNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'subject', htmlspecialchars($subject, ENT_COMPAT, 'UTF-8'))); $rootNode->appendChild($subjectsNode); } // Dates $rootNode->appendChild($this->createDatesNode($doc, $issue, $article, $galley, $galleyFile, $publicationDate)); // Language $rootNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'language', AppLocale::getIso1FromLocale($objectLocalePrecedence[0]))); // Resource Type $resourceTypeNode = $this->createResourceTypeNode($doc, $issue, $article, $galley, $galleyFile); if ($resourceTypeNode) $rootNode->appendChild($resourceTypeNode); // Alternate Identifiers $rootNode->appendChild($this->createAlternateIdentifiersNode($doc, $issue, $article, $galley)); // Related Identifiers $relatedIdentifiersNode = $this->createRelatedIdentifiersNode($doc, $issue, $article, $galley); if ($relatedIdentifiersNode) $rootNode->appendChild($relatedIdentifiersNode); // Sizes $sizesNode = $this->createSizesNode($doc, $issue, $article, $galley, $galleyFile); if ($sizesNode) $rootNode->appendChild($sizesNode); // Formats if (!empty($galleyFile)) { $format = $galleyFile->getFileType(); if (!empty($format)) { $formatsNode = $doc->createElementNS($deployment->getNamespace(), 'formats'); $formatsNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'format', htmlspecialchars($format, ENT_COMPAT, 'UTF-8'))); $rootNode->appendChild($formatsNode); } } // Rights $rightsURL = $article ? $article->getLicenseURL() : $context->getSetting('licenseURL'); if(!empty($rightsURL)) { $rightsNode = $doc->createElementNS($deployment->getNamespace(), 'rightsList'); $rightsNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'rights', htmlspecialchars(strip_tags(Application::getCCLicenseBadge($rightsURL)), ENT_COMPAT, 'UTF-8'))); $node->setAttribute('rightsURI', $rightsURL); $rootNode->appendChild($rightsNode); } // Descriptions $descriptionsNode = $this->createDescriptionsNode($doc, $issue, $article, $galley, $galleyFile, $objectLocalePrecedence); if ($descriptionsNode) $rootNode->appendChild($descriptionsNode); return $doc; } // // Conversion functions // /** * Create and return the root node. * @param $doc DOMDocument * @return DOMElement */ function createRootNode($doc) { $deployment = $this->getDeployment(); $rootNode = $doc->createElementNS($deployment->getNamespace(), $deployment->getRootElementName()); $rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', $deployment->getXmlSchemaInstance()); $rootNode->setAttribute('xsi:schemaLocation', $deployment->getNamespace() . ' ' . $deployment->getSchemaFilename()); return $rootNode; } /** * Create creators node. * @param $doc DOMDocument * @param $issue Issue * @param $article PublishedArticle * @param $galley ArticleGalley * @param $galleyFile SubmissionFile * @param $publisher string * @param $objectLocalePrecedence array * @return DOMElement */ function createCreatorsNode($doc, $issue, $article, $galley, $galleyFile, $publisher, $objectLocalePrecedence) { $deployment = $this->getDeployment(); $creators = array(); switch (true) { case (isset($galleyFile) && is_a($galleyFile, 'SupplementaryFile')): // Check whether we have a supp file creator set... $creator = $this->getPrimaryTranslation($galleyFile->getCreator(null), $objectLocalePrecedence); if (!empty($creator)) { $creators[] = $creator; break; } // ...if not then go on by retrieving the article // authors. case isset($article): // Retrieve the article authors. $authors = $article->getAuthors(); assert(!empty($authors)); foreach ($authors as $author) { /* @var $author Author */ $creators[] = $author->getFullName(true); } break; case isset($issue): $creators[] = $publisher; break; } assert(count($creators) >= 1); $creatorsNode = $doc->createElementNS($deployment->getNamespace(), 'creators'); foreach ($creators as $creator) { $creatorNode = $doc->createElementNS($deployment->getNamespace(), 'creator'); $creatorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'creatorName', htmlspecialchars($creator, ENT_COMPAT, 'UTF-8'))); $creatorsNode->appendChild($creatorNode); } return $creatorsNode; } /** * Create titles node. * @param $doc DOMDocument * @param $issue Issue * @param $article PublishedArticle * @param $galley ArticleGalley * @param $galleyFile SubmissionFile * @param $objectLocalePrecedence array * @return DOMElement */ function createTitlesNode($doc, $issue, $article, $galley, $galleyFile, $objectLocalePrecedence) { $deployment = $this->getDeployment(); // Get an array of localized titles. $alternativeTitle = null; switch (true) { case (isset($galleyFile) && is_a($galleyFile, 'SupplementaryFile')): $titles = $galleyFile->getName(null); break; case isset($article): $titles = $article->getTitle(null); break; case isset($issue): $titles = $this->getIssueInformation($issue); $alternativeTitle = $this->getPrimaryTranslation($issue->getTitle(null), $objectLocalePrecedence); break; } // Order titles by locale precedence. $titles = $this->getTranslationsByPrecedence($titles, $objectLocalePrecedence); // We expect at least one title. assert(count($titles)>=1); $titlesNode = $doc->createElementNS($deployment->getNamespace(), 'titles'); // Start with the primary object locale. $primaryTitle = array_shift($titles); $titlesNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'title', htmlspecialchars(PKPString::html2text($primaryTitle), ENT_COMPAT, 'UTF-8'))); // Then let the translated titles follow. foreach($titles as $locale => $title) { $titlesNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'title', htmlspecialchars(PKPString::html2text($title), ENT_COMPAT, 'UTF-8'))); $node->setAttribute('titleType', DATACITE_TITLETYPE_TRANSLATED); } // And finally the alternative title. if (!empty($alternativeTitle)) { $titlesNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'title', htmlspecialchars(PKPString::html2text($alternativeTitle), ENT_COMPAT, 'UTF-8'))); $node->setAttribute('titleType', DATACITE_TITLETYPE_ALTERNATIVE); } return $titlesNode; } /** * Create a date node list. * @param $doc DOMDocument * @param $issue Issue * @param $article PublishedArticle * @param $galley ArticleGalley * @param $galleyFile SubmissionFile * @param $publicationDate string * @return DOMElement */ function createDatesNode($doc, $issue, $article, $galley, $galleyFile, $publicationDate) { $deployment = $this->getDeployment(); $dates = array(); switch (true) { case isset($galleyFile): if (is_a($galleyFile, 'SupplementaryFile')) { // Created date (for supp files only): supp file date created. $createdDate = $galleyFile->getDateCreated(); if (!empty($createdDate)) { $dates[DATACITE_DATE_CREATED] = $createdDate; } } // Accepted date (for galleys files): file uploaded. $acceptedDate = $galleyFile->getDateUploaded(); if (!empty($acceptedDate)) { $dates[DATACITE_DATE_ACCEPTED] = $acceptedDate; } // Last modified date (for galley files): file modified date. $lastModified = $galleyFile->getDateModified(); if (!empty($lastModified)) { $dates[DATACITE_DATE_UPDATED] = $lastModified; } break; case isset($article): // Submitted date (for articles): article date submitted. $submittedDate = $article->getDateSubmitted(); if (!empty($submittedDate)) { $dates[DATACITE_DATE_SUBMITTED] = $submittedDate; } // Accepted date: the last editor accept decision date $editDecisionDao = DAORegistry::getDAO('EditDecisionDAO'); $editDecisions = $editDecisionDao->getEditorDecisions($article->getId()); foreach (array_reverse($editDecisions) as $editDecision) { if ($editDecision['decision'] == SUBMISSION_EDITOR_DECISION_ACCEPT) { $dates[DATACITE_DATE_ACCEPTED] = $editDecision['dateDecided']; } } // Last modified date (for articles): last$lastModifiede. $lastModified = $article->getLastModified(); if (!empty($lastModified)) { $dates[DATACITE_DATE_UPDATED] = $lastModified; } break; case isset($issue): // Last modified date (for issues): last modified date. $lastModified = $issue->getLastModified(); if (!empty($lastModified)) { $dates[DATACITE_DATE_UPDATED] = $issue->getLastModified(); } break; } $datesNode = $doc->createElementNS($deployment->getNamespace(), 'dates'); // Issued date: publication date. $dates[DATACITE_DATE_ISSUED] = $publicationDate; // Available date: issue open access date. $availableDate = $issue->getOpenAccessDate(); if (!empty($availableDate)) { $dates[DATACITE_DATE_AVAILABLE] = $availableDate; } // Create the date elements for all dates. foreach($dates as $dateType => $date) { // Format the date. $date = date('Y-m-d', strtotime($date)); $datesNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'date', $date)); $node->setAttribute('dateType', $dateType); } return $datesNode; } /** * Create a resource type node. * @param $doc DOMDocument * @param $issue Issue * @param $article PublishedArticle * @param $galley ArticleGalley * @param $galleyFile SubmissionFile * @return DOMElement. */ function createResourceTypeNode($doc, $issue, $article, $galley, $galleyFile) { $deployment = $this->getDeployment(); $resourceTypeNode = null; switch (true) { case isset($galley): if (!$galley->getRemoteURL()) { $genreDao = DAORegistry::getDAO('GenreDAO'); /* @var $genreDao GenreDAO */ $genre = $genreDao->getById($galleyFile->getGenreId()); if ($genre->getCategory() == GENRE_CATEGORY_DOCUMENT && !$genre->getSupplementary() && !$genre->getDependent()) { $resourceType = 'Article'; } } else { $resourceType = 'Article'; } break; case isset($article): $resourceType = 'Article'; break; case isset($issue): $resourceType = 'Journal Issue'; break; default: assert(false); } if (!empty($resourceType)) { // Create the resourceType element. $resourceTypeNode = $doc->createElementNS($deployment->getNamespace(), 'resourceType', $resourceType); $resourceTypeNode->setAttribute('resourceTypeGeneral', 'Text'); } else { // It is a supplementary file $resourceTypeNode = $doc->createElementNS($deployment->getNamespace(), 'resourceType'); $resourceTypeNode->setAttribute('resourceTypeGeneral', 'Dataset'); } return $resourceTypeNode; } /** * Generate alternate identifiers node list. * @param $doc DOMDocument * @param $issue Issue * @param $article PublishedArticle * @param $galley ArticleGalley * @return DOMElement */ function createAlternateIdentifiersNode($doc, $issue, $article, $galley) { $deployment = $this->getDeployment(); $context = $deployment->getContext(); $alternateIdentifiersNode = $doc->createElementNS($deployment->getNamespace(), 'alternateIdentifiers'); // Proprietary ID $proprietaryId = $context->getId(); if ($issue) $proprietaryId .= '-' . $issue->getId(); if ($article) $proprietaryId .= '-' . $article->getId(); if ($galley) $proprietaryId .= '-g' . $galley->getId(); $alternateIdentifiersNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'alternateIdentifier', $proprietaryId)); $node->setAttribute('alternateIdentifierType', DATACITE_IDTYPE_PROPRIETARY); // ISSN - for issues only. if (!isset($article) && !isset($galley)) { $onlineIssn = $context->getSetting('onlineIssn'); if (!empty($onlineIssn)) { $alternateIdentifiersNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'alternateIdentifier', $onlineIssn)); $node->setAttribute('alternateIdentifierType', DATACITE_IDTYPE_EISSN); } $printIssn = $context->getSetting('printIssn'); if (!empty($printIssn)) { $alternateIdentifiersNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'alternateIdentifier', $printIssn)); $node->setAttribute('alternateIdentifierType', DATACITE_IDTYPE_ISSN); } } return $alternateIdentifiersNode; } /** * Generate related identifiers node list. * @param $doc DOMDocument * @param $issue Issue * @param $article PublishedArticle * @param $galley ArticleGalley * @return DOMElement|null */ function createRelatedIdentifiersNode($doc, $issue, $article, $galley) { $deployment = $this->getDeployment(); $relatedIdentifiersNode = $doc->createElementNS($deployment->getNamespace(), 'relatedIdentifiers'); switch (true) { case isset($galley): // Part of: article. assert(isset($article)); $doi = $article->getStoredPubId('doi'); if (!empty($doi)) { $relatedIdentifiersNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'relatedIdentifier', htmlspecialchars($doi, ENT_COMPAT, 'UTF-8'))); $node->setAttribute('relatedIdentifierType', DATACITE_IDTYPE_DOI); $node->setAttribute('relationType', DATACITE_RELTYPE_ISPARTOF); } break; case isset($article): // Part of: issue. assert(isset($issue)); $doi = $issue->getStoredPubId('doi'); if (!empty($doi)) { $relatedIdentifiersNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'relatedIdentifier', htmlspecialchars($doi, ENT_COMPAT, 'UTF-8'))); $node->setAttribute('relatedIdentifierType', DATACITE_IDTYPE_DOI); $node->setAttribute('relationType', DATACITE_RELTYPE_ISPARTOF); } unset($doi); // Parts: galleys. $galleyDao = DAORegistry::getDAO('ArticleGalleyDAO'); /* @var $galleyDao ArticleGalleyDAO */ $galleysByArticle = $galleyDao->getBySubmissionId($article->getId())->toArray(); foreach ($galleysByArticle as $relatedGalley) { $doi = $relatedGalley->getStoredPubId('doi'); if (!empty($doi)) { $relatedIdentifiersNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'relatedIdentifier', htmlspecialchars($doi, ENT_COMPAT, 'UTF-8'))); $node->setAttribute('relatedIdentifierType', DATACITE_IDTYPE_DOI); $node->setAttribute('relationType', DATACITE_RELTYPE_HASPART); } unset($relatedGalley, $doi); } break; case isset($issue): // Parts: articles in this issue. $articleDao = DAORegistry::getDAO('PublishedArticleDAO'); /* @var $articleDao PublishedArticleDAO */ $articlesByIssue = $articleDao->getPublishedArticles($issue->getId()); foreach ($articlesByIssue as $relatedArticle) { $doi = $relatedArticle->getStoredPubId('doi'); if (!empty($doi)) { $relatedIdentifiersNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'relatedIdentifier', htmlspecialchars($doi, ENT_COMPAT, 'UTF-8'))); $node->setAttribute('relatedIdentifierType', DATACITE_IDTYPE_DOI); $node->setAttribute('relationType', DATACITE_RELTYPE_HASPART); } unset($relatedArticle, $doi); } break; } if ($relatedIdentifiersNode->hasChildNodes()) return $relatedIdentifiersNode; else return null; } /** * Create a sizes node list. * @param $doc DOMDocument * @param $issue Issue * @param $article PublishedArticle * @param $galley ArticleGalley * @param $galleyFile SubmissionFile * @return DOMElement|null Can be null if a size * cannot be identified for the given object. */ function createSizesNode($doc, $issue, $article, $galley, $galleyFile) { $deployment = $this->getDeployment(); switch (true) { case isset($galley): // The galley represents the article. $pages = $article->getPages(); $files = array($galleyFile); break; case isset($article): $pages = $article->getPages(); $files = array(); break; case isset($issue): $issueGalleyDao = DAORegistry::getDAO('IssueGalleyDAO'); /* @var $issueGalleyDao IssueGalleyDAO */ $files = $issueGalleyDao->getByIssueId($issue->getId()); break; default: assert(false); } $sizes = array(); if (!empty($pages)) { AppLocale::requireComponents(array(LOCALE_COMPONENT_APP_EDITOR)); $sizes[] = $pages . ' ' . __('editor.issues.pages'); } foreach($files as $file) { /* @var $file PKPFile */ if ($file) { $sizes[] = $file->getNiceFileSize(); } unset($file); } $sizesNode = null; if (!empty($sizes)) { $sizesNode = $doc->createElementNS($deployment->getNamespace(), 'sizes'); foreach($sizes as $size) { $sizesNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'size', htmlspecialchars($size, ENT_COMPAT, 'UTF-8'))); } } return $sizesNode; } /** * Create descriptions node list. * @param $doc DOMDocument * @param $issue Issue * @param $article PublishedArticle * @param $galley Alley * @param $galleyFile SubmissionFile * @param $objectLocalePrecedence array * @return DOMElement|null Can be null if a size * cannot be identified for the given object. */ function createDescriptionsNode($doc, $issue, $article, $galley, $galleyFile, $objectLocalePrecedence) { $deployment = $this->getDeployment(); $descriptions = array(); switch (true) { case isset($galley): if (is_a($galleyFile, 'SupplementaryFile')) { $suppFileDesc = $this->getPrimaryTranslation($galleyFile->getDescription(null), $objectLocalePrecedence); if (!empty($suppFileDesc)) $descriptions[DATACITE_DESCTYPE_OTHER] = $suppFileDesc; } break; case isset($article): $articleAbstract = $this->getPrimaryTranslation($article->getAbstract(null), $objectLocalePrecedence); if (!empty($articleAbstract)) $descriptions[DATACITE_DESCTYPE_ABSTRACT] = $articleAbstract; break; case isset($issue): $issueDesc = $this->getPrimaryTranslation($issue->getDescription(null), $objectLocalePrecedence); if (!empty($issueDesc)) $descriptions[DATACITE_DESCTYPE_OTHER] = $issueDesc; $descriptions[DATACITE_DESCTYPE_TOC] = $this->getIssueToc($issue, $objectLocalePrecedence); break; default: assert(false); } if (isset($article)) { // Articles and galleys. $descriptions[DATACITE_DESCTYPE_SERIESINFO] = $this->getIssueInformation($issue, $objectLocalePrecedence); } $descriptionsNode = null; if (!empty($descriptions)) { $descriptionsNode = $doc->createElementNS($deployment->getNamespace(), 'descriptions'); foreach($descriptions as $descType => $description) { $descriptionsNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'description', htmlspecialchars(PKPString::html2text($description), ENT_COMPAT, 'UTF-8'))); $node->setAttribute('descriptionType', $descType); } } return $descriptionsNode; } // // Helper functions // /** * Identify the locale precedence for this export. * @param $context Context * @param $article PublishedArticle * @param $galley ArticleGalley * @return array A list of valid PKP locales in descending * order of priority. */ function getObjectLocalePrecedence($context, $article, $galley) { $locales = array(); if (is_a($galley, 'ArticleGalley') && AppLocale::isLocaleValid($galley->getLocale())) { $locales[] = $galley->getLocale(); } if (is_a($article, 'Submission')) { // First try to translate the article language into a locale. $articleLocale = $this->translateLanguageToLocale($article->getLanguage()); if (!is_null($articleLocale)) { $locales[] = $articleLocale; } // Use the article locale as fallback only // as this is the primary locale of article meta-data, not // necessarily of the article itself. if(AppLocale::isLocaleValid($article->getLocale())) { $locales[] = $article->getLocale(); } } // Use the journal locale as fallback. $locales[] = $context->getPrimaryLocale(); // Use form locales as fallback. $formLocales = array_keys($context->getSupportedFormLocaleNames()); // Sort form locales alphabetically so that // we get a well-defined order. sort($formLocales); foreach($formLocales as $formLocale) { if (!in_array($formLocale, $locales)) $locales[] = $formLocale; } assert(!empty($locales)); return $locales; } /** * Try to translate an ISO language code to an OJS locale. * @param $language string 2- or 3-letter ISO language code * @return string|null An OJS locale or null if no matching * locale could be found. */ function translateLanguageToLocale($language) { $locale = null; if (strlen($language) == 2) { $language = AppLocale::get3LetterFrom2LetterIsoLanguage($language); } if (strlen($language) == 3) { $language = AppLocale::getLocaleFrom3LetterIso($language); } if (AppLocale::isLocaleValid($language)) { $locale = $language; } return $locale; } /** * Identify the primary translation from an array of * localized data. * @param $localizedData array An array of localized * data (key: locale, value: localized data). * @param $localePrecedence array An array of locales * by descending priority. * @return mixed|null The value of the primary locale * or null if no primary translation could be found. */ function getPrimaryTranslation($localizedData, $localePrecedence) { // Check whether we have localized data at all. if (!is_array($localizedData) || empty($localizedData)) return null; // Try all locales from the precedence list first. foreach($localePrecedence as $locale) { if (isset($localizedData[$locale]) && !empty($localizedData[$locale])) { return $localizedData[$locale]; } } // As a fallback: use any translation by alphabetical // order of locales. ksort($localizedData); foreach($localizedData as $locale => $value) { if (!empty($value)) return $value; } // If we found nothing (how that?) return null. return null; } /** * Re-order localized data by locale precedence. * @param $localizedData array An array of localized * data (key: locale, value: localized data). * @param $localePrecedence array An array of locales * by descending priority. * @return array Re-ordered localized data. */ function getTranslationsByPrecedence($localizedData, $localePrecedence) { $reorderedLocalizedData = array(); // Check whether we have localized data at all. if (!is_array($localizedData) || empty($localizedData)) return $reorderedLocalizedData; // Order by explicit locale precedence first. foreach($localePrecedence as $locale) { if (isset($localizedData[$locale]) && !empty($localizedData[$locale])) { $reorderedLocalizedData[$locale] = $localizedData[$locale]; } unset($localizedData[$locale]); } // Order any remaining values alphabetically by locale // and amend the re-ordered array. ksort($localizedData); $reorderedLocalizedData = array_merge($reorderedLocalizedData, $localizedData); return $reorderedLocalizedData; } /** * Construct an issue title from the journal title * and the issue identification. * @param $issue Issue * @param $objectLocalePrecedence array * @return array|string An array of localized issue titles * or a string if a locale has been given. */ function getIssueInformation($issue, $objectLocalePrecedence = null) { $deployment = $this->getDeployment(); $context = $deployment->getContext(); $issueIdentification = $issue->getIssueIdentification(); assert(!empty($issueIdentification)); if (is_null($objectLocalePrecedence)) { $issueInfo = array(); foreach ($context->getName(null) as $locale => $contextName) { $issueInfo[$locale] = "$contextName, $issueIdentification"; } } else { $issueInfo = $this->getPrimaryTranslation($context->getName(null), $objectLocalePrecedence); if (!empty($issueInfo)) { $issueInfo .= ', '; } $issueInfo .= $issueIdentification; } return $issueInfo; } /** * Construct a table of content for an issue. * @param $issue Issue * @param $objectLocalePrecedence array * @return string */ function getIssueToc($issue, $objectLocalePrecedence) { $articleDao = DAORegistry::getDAO('PublishedArticleDAO'); /* @var $articleDao PublishedArticleDAO */ $articlesByIssue = $articleDao->getPublishedArticles($issue->getId()); assert(is_array($articlesByIssue)); $toc = ''; foreach ($articlesByIssue as $articleInIssue) { $currentEntry = $this->getPrimaryTranslation($articleInIssue->getTitle(null), $objectLocalePrecedence); assert(!empty($currentEntry)); $pages = $articleInIssue->getPages(); if (!empty($pages)) { $currentEntry .= '...' . $pages; } $toc .= $currentEntry . "
"; unset($articleInIssue); } return $toc; } } ?>