lensGalleyBits plugin is not compatible with OJS 3.3

Hi
lensGalleyBits plugin is not compatible with OJS 3.3. When is it available? Or how to fix it?
Thanks
jan

Hi @trace

My understanding is that the project is mostly abandoned now, but you can try grabbing the commit in this pull request (which fixes the plugin for OJS 3.2) to see if it works for 3.3:

Best,
Jason

Thanks Jason
Unfortunately it doesn’t run on 3-3_0_6.
Best

Hi @trace

Did you have an error message when you try it? It might be very simple to fix.

Cheers,
Jason

Hi Jason
The error I get as follows. It seems to be some SMARTY thing:

[Wed Jun 23 13:00:34.636361 2021] [php7:error] [pid 7960:tid 1880] [client ::1:62311] PHP Fatal error: Uncaught Error: Call to a member function getId() on null in C:\\xampp\\htdocs\\ojs-3_3\\cache\\t_compile\\461a4acc08e77ad8ac40d868fce45fa05a8aa2b5^8396db423f80d06ea344891d9dea39aae85b3b44_0.plugins-1-plugins-generic-lensGalleyBits-generic-lensGalleyBits.articleGalley.tpl.php:34\nStack trace:\n#0 C:\\xampp\\htdocs\\ojs-3_3\\lib\\pkp\\lib\\vendor\\smarty\\smarty\\libs\\sysplugins\\smarty_template_resource_base.php(123): content_60d1d10b9d8097_96697361(Object(Smarty_Internal_Template))\n#1 C:\\xampp\\htdocs\\ojs-3_3\\lib\\pkp\\lib\\vendor\\smarty\\smarty\\libs\\sysplugins\\smarty_template_compiled.php(114): Smarty_Template_Resource_Base->getRenderedTemplateCode(Object(Smarty_Internal_Template))\n#2 C:\\xampp\\htdocs\\ojs-3_3\\lib\\pkp\\lib\\vendor\\smarty\\smarty\\libs\\sysplugins\\smarty_internal_template.php(216): Smarty_Template_Compiled->render(Object(Smarty_Internal_Template))\n#3 C:\\xampp\\htdocs\\ojs-3_3\\lib\\pkp\\lib\\vendor\\smarty\\smarty\\libs\\sysplugins\\smarty_internal_templatebase.php(232): Smarty_Internal_Template->render(false, 1)\n#4 C:\\xampp\\htdocs\\ in C:\\xampp\\htdocs\\ojs-3_3\\cache\\t_compile\\461a4acc08e77ad8ac40d868fce45fa05a8aa2b5^8396db423f80d06ea344891d9dea39aae85b3b44_0.plugins-1-plugins-generic-lensGalleyBits-generic-lensGalleyBits.articleGalley.tpl.php on line 34, referer: http://localhost/ojs-3_3/index.php/Test

Thanks
jan

Hi @jnugent
The error above was from my local installation on windows. The probably more helpful error on our Linux Server looks like this:

[Thu Jun 24 12:22:22.339075 2021] [php7:error] [pid 426086] [client 130.92.26.236:52016] PHP Fatal error: Uncaught Error: Call to undefined method SubmissionFile::getFilePath() in /var/www/ojs/plugins/generic/lensGalleyBits/LensGalleyBitsPlugin.inc.php:197\nStack trace:\n#0 /var/www/ojs/plugins/generic/lensGalleyBits/LensGalleyBitsPlugin.inc.php(171): LensGalleyBitsPlugin->_getXMLContents(Object(Request), Object(ArticleGalley))\n#1 /var/www/ojs/lib/pkp/classes/plugins/HookRegistry.inc.php(107): LensGalleyBitsPlugin->articleDownloadCallback('ArticleHandler:...', Array)\n#2 /var/www/ojs/pages/article/ArticleHandler.inc.php(421): HookRegistry::call('ArticleHandler:...', Array)\n#3 /var/www/ojs/lib/pkp/classes/core/PKPRouter.inc.php(395): ArticleHandler->download(Array, Object(Request))\n#4 /var/www/ojs/lib/pkp/classes/core/PKPPageRouter.inc.php(246): PKPRouter->_authorizeInitializeAndCallRequest(Array, Object(Request), Array, false)\n#5 /var/www/ojs/lib/pkp/classes/core/Dispatcher.inc.php(144): PKPPageRouter->route(Object(Request))\n#6 /var/www/ojs/lib/pkp/classes/core/PKPApplication.inc.php(362): Dispatcher->dispatch(Objec in /var/www/ojs/plugins/generic/lensGalleyBits/LensGalleyBitsPlugin.inc.php on line 197, referer: https://bop-test.unibe.ch/ciss/article/view/7647/10754

Thanks
Jan

Hi @trace

Ah, yes. I believe all of that has been refactored now, and what I suggest you do is look at the original lensGalley plugin (which was for JATS XML) and start here:

Which is the entry point for the _getXmlContents method and look at how the file is retrieved there. You can probably copy and paste most of that code into the same method for the LensGalleyBits plugin.

Cheers,
Jason

Hi @jnugent

@mfelczak fixed that for us. Maybe the code can be committed to the specific github repo to make it available to others.

Best
Jan

<?php

/**
 * @file plugins/generic/lensGalleyBits/LensGalleyBitsPlugin.inc.php
 *
 * Copyright (c) 2014-2020 Simon Fraser University
 * Copyright (c) 2003-2020 John Willinsky
 * Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
 *
 * @class LensGalleyBitsPlugin
 * @ingroup plugins_generic_lensGalley
 *
 * @brief Class for lensGalleyBits plugin
 */

import('lib.pkp.classes.plugins.GenericPlugin');

class LensGalleyBitsPlugin extends GenericPlugin {
        /**
         * @copydoc LazyLoadPlugin::register()
         */
        function register($category, $path, $mainContextId = null) {
                if (parent::register($category, $path, $mainContextId)) {
                        if ($this->getEnabled()) {
                                HookRegistry::register('ArticleHandler::view::galley', array($this, 'articleCallback'));
                                HookRegistry::register('IssueHandler::view::galley', array($this, 'issueCallback'));
                                HookRegistry::register('ArticleHandler::download', array($this, 'articleDownloadCallback'), HOOK_SEQUENCE_LATE);
                        }
                        return true;
                }
                return false;
        }

        /**
         * Install default settings on journal creation.
         * @return string
         */
        function getContextSpecificPluginSettingsFile() {
                return $this->getPluginPath() . '/settings.xml';
        }

        /**
         * Get the display name of this plugin.
         * @return String
         */
        function getDisplayName() {
                return __('plugins.generic.lensGalleyBits.displayName');
        }

        /**
         * Get a description of the plugin.
         */
        function getDescription() {
                return __('plugins.generic.lensGalleyBits.description');
        }

        /**
         * Callback that renders the article galley.
         * @param $hookName string
         * @param $args array
         * @return boolean
         */
        function articleCallback($hookName, $args) {
                $request =& $args[0];
                $issue =& $args[1];
                $galley =& $args[2];
                $submission =& $args[3];

                $templateMgr = TemplateManager::getManager($request);
                if ($galley && in_array($galley->getFileType(), array('application/xml', 'text/xml'))) {
                        $galleyPublication = null;
                        foreach ($submission->getData('publications') as $publication) {
                                if ($publication->getId() === $galley->getData('publicationId')) {
                                        $galleyPublication = $publication;
                                        break;
                                }
                        }
                        $templateMgr->assign(array(
                                'pluginLensPath' => $this->getLensPath($request),
                                'displayTemplatePath' => $this->getTemplateResource('display.tpl'),
                                'pluginUrl' => $request->getBaseUrl() . '/' . $this->getPluginPath(),
                                'galleyFile' => $galley->getFile(),
                                'issue' => $issue,
                                'article' => $submission,
                                'bestId' => $submission->getBestId(),
                                'isLatestPublication' => $submission->getData('currentPublicationId') === $galley->getData('publicationId'),
                                'galleyPublication' => $galleyPublication,
                                'galley' => $galley,
                                'jQueryUrl' => $this->_getJQueryUrl($request),
                        ));
                        $templateMgr->display($this->getTemplateResource('articleGalley.tpl'));
                        return true;
                }

                return false;
        }

        /**
         * Callback that renders the issue galley.
         * @param $hookName string
         * @param $args array
         * @return boolean
         */
        function issueCallback($hookName, $args) {
                $request =& $args[0];
                $issue =& $args[1];
                $galley =& $args[2];

                $templateMgr = TemplateManager::getManager($request);
                if ($galley && in_array($galley->getFileType(), array('application/xml', 'text/xml'))) {
                        $templateMgr->assign(array(
                                'pluginLensPath' => $this->getLensPath($request),
                                'displayTemplatePath' => $this->getTemplateResource('display.tpl'),
                                'pluginUrl' => $request->getBaseUrl() . '/' . $this->getPluginPath(),
                                'galleyFile' => $galley->getFile(),
                                'issue' => $issue,
                                'galley' => $galley,
                                'jQueryUrl' => $this->_getJQueryUrl($request),
                        ));
                        $templateMgr->addJavaScript(
                                'jquery',
                                $jquery,
                                array(
                                        'priority' => STYLE_SEQUENCE_CORE,
                                        'contexts' => 'frontend',
                                )
                        );
                        $templateMgr->display($this->getTemplateResource('issueGalley.tpl'));
                        return true;
                }

                return false;
        }

        /**
         * Get the URL for JQuery JS.
         * @param $request PKPRequest
         * @return string
         */
        private function _getJQueryUrl($request) {
                $min = Config::getVar('general', 'enable_minified') ? '.min' : '';
                if (Config::getVar('general', 'enable_cdn')) {
                        return '//ajax.googleapis.com/ajax/libs/jquery/' . CDN_JQUERY_VERSION . '/jquery' . $min . '.js';
                } else {
                        return $request->getBaseUrl() . '/lib/pkp/lib/vendor/components/jquery/jquery' . $min . '.js';
                }
        }

        /**
         * returns the base path for Lens JS included in this plugin.
         * @param $request PKPRequest
         * @return string
         */
        function getLensPath($request) {
                return $request->getBaseUrl() . '/' . $this->getPluginPath() . '/libs/lens';
        }

        /**
         * Present rewritten XML.
         * @param string $hookName
         * @param array $args
         */
        function articleDownloadCallback($hookName, $args) {
                $article =& $args[0];
                $galley =& $args[1];
                $fileId =& $args[2];
                $request = Application::get()->getRequest();

                if ($galley && in_array($galley->getFileType(), array('application/xml', 'text/xml')) && $galley->getFileId() == $fileId) {
                        if (!HookRegistry::call('LensGalleyBitsPlugin::articleDownload', array($article,  &$galley, &$fileId))) {
                                $xmlContents = $this->_getXMLContents($request, $galley);
                                header('Content-Type: application/xml');
                                header('Content-Length: ' . strlen($xmlContents));
                                header('Content-Disposition: inline');
                                header('Cache-Control: private');
                                header('Pragma: public');
                                echo $xmlContents;
                                $returner = true;
                                HookRegistry::call('LensGalleyBitsPlugin::articleDownloadFinished', array(&$returner));
                        }
                        return true;
                }

                return false;
        }

        /**
         * Return string containing the contents of the XML file.
         * This function performs any necessary filtering, like image URL replacement.
         * @param $request PKPRequest
         * @param $galley ArticleGalley
         * @return string
         */
        function _getXMLContents($request, $galley) {
                $journal = $request->getJournal();
                $submissionFile = $galley->getFile();
                $fileService = Services::get('file');
                $file = $fileService->get($submissionFile->getData('fileId'));
                $contents = $fileService->fs->read($file->path);

                // Replace media file references
                import('lib.pkp.classes.submission.SubmissionFile'); // Constants
                $embeddableFilesIterator = Services::get('submissionFile')->getMany([
                        'assocTypes' => [ASSOC_TYPE_SUBMISSION_FILE],
                        'assocIds' => [$submissionFile->getId()],
                        'fileStages' => [SUBMISSION_FILE_DEPENDENT],
                        'includeDependentFiles' => true,
                ]);
                $embeddableFiles = iterator_to_array($embeddableFilesIterator);
                $referredArticle = $referredPublication = null;
                $submissionDao = DAORegistry::getDAO('SubmissionDAO');
                $publicationService = Services::get('publication');
                foreach ($embeddableFiles as $embeddableFile) {
                        // Ensure that the $referredArticle object refers to the article we want
                        if (!$referredArticle || !$referredPublication || $referredPublication->getData('submissionId') != $referredArticle->getId() || $referredPublication->getId() != $galley->getData('publicationId')) {
                                $referredPublication = $publicationService->get($galley->getData('publicationId'));
                                $referredArticle = $submissionDao->getById($referredPublication->getData('submissionId'));
                        }
                        $fileUrl = $request->url(null, 'article', 'download', [$referredArticle->getBestArticleId(), $galley->getBestGalleyId(), $embeddableFile->getId()]);
                        $pattern = preg_quote(rawurlencode($embeddableFile->getLocalizedData('name')));

                        $contents = preg_replace(
                                $pattern='/([Ss][Rr][Cc]|[Hh][Rr][Ee][Ff]|[Dd][Aa][Tt][Aa])\s*=\s*"([^"]*' . $pattern . ')"/',
                                '\1="' . $fileUrl . '"',
                                $contents
                        );
                        if ($contents === null) error_log('PREG error in ' . __FILE__ . ' line ' . __LINE__ . ': ' . preg_last_error());
                }

                // Perform replacement for ojs://... URLs
                $contents = preg_replace_callback(
                        '/(<[^<>]*")[Oo][Jj][Ss]:\/\/([^"]+)("[^<>]*>)/',
                        array($this, '_handleOjsUrl'),
                        $contents
                );
                if ($contents === null) error_log('PREG error in ' . __FILE__ . ' line ' . __LINE__ . ': ' . preg_last_error());

                // Perform variable replacement for journal, issue, site info
                $issueDao = DAORegistry::getDAO('IssueDAO');
                $issue = $issueDao->getBySubmissionId($galley->getData('submissionId'));

                $journal = $request->getJournal();
                $site = $request->getSite();

                $paramArray = array(
                        'issueTitle' => $issue?$issue->getIssueIdentification():__('editor.article.scheduleForPublication.toBeAssigned'),
                        'journalTitle' => $journal->getLocalizedName(),
                        'siteTitle' => $site->getLocalizedTitle(),
                        'currentUrl' => $request->getRequestUrl(),
                );

                foreach ($paramArray as $key => $value) {
                        $contents = str_replace('{$' . $key . '}', $value, $contents);
                }

                return $contents;
        }

        function _handleOjsUrl($matchArray) {
                $request = Application::get()->getRequest();
                $url = $matchArray[2];
                $anchor = null;
                if (($i = strpos($url, '#')) !== false) {
                        $anchor = substr($url, $i+1);
                        $url = substr($url, 0, $i);
                }
                $urlParts = explode('/', $url);
                if (isset($urlParts[0])) switch(strtolower_codesafe($urlParts[0])) {
                        case 'journal':
                                $url = $request->url(isset($urlParts[1]) ? $urlParts[1] : $request->getRequestedJournalPath(), null, null, null, null, $anchor);
                                break;
                        case 'article':
                                if (isset($urlParts[1])) {$url = $request->url(null, 'article', 'view', $urlParts[1], null, $anchor);}
                                break;
                        case 'issue':
                                if (isset($urlParts[1])) {$url = $request->url(null, 'issue', 'view', $urlParts[1], null, $anchor);} else {
                                        $url = $request->url(null, 'issue', 'current', null, null, $anchor);}
                                break;
                        case 'sitepublic':
                                array_shift($urlParts);
                                import ('classes.file.PublicFileManager');
                                $publicFileManager = new PublicFileManager();
                                $url = $request->getBaseUrl() . '/' . $publicFileManager->getSiteFilesPath() . '/' . implode('/', $urlParts) . ($anchor?'#' . $anchor:'');
                                break;
                        case 'public':
                                array_shift($urlParts);
                                $journal = $request->getJournal();
                                import ('classes.file.PublicFileManager');
                                $publicFileManager = new PublicFileManager();
                                $url = $request->getBaseUrl() . '/' . $publicFileManager->getContextFilesPath($journal->getId()) . '/' . implode('/', $urlParts) . ($anchor?'#' . $anchor:'');
                                break;
                }
                return $matchArray[1] . $url . $matchArray[3];
        }
}

?>

Excuse me, I tried to use this code and replace it with LensGalleyBitsPlugin.inc.php of the master repo https://github.com/paflov/lensGalleyBits, but it crashes. I didn’t found any other repository more updated so I thought you have a new one.

I have OJS 3.3.8.

Could you upload the zip file with the fixed plugin? It would be a great contribution.

Hi
I cannot upload any .zip file here. Please provide me an email adress.
Best

1 Like