diff --git a/module/VuFind/src/VuFind/Controller/AbstractSearch.php b/module/VuFind/src/VuFind/Controller/AbstractSearch.php index c258e9b1428c838f15c654d563512b42c8093720..805d0f44c33cab4f4f477217deb755dd480ded70 100644 --- a/module/VuFind/src/VuFind/Controller/AbstractSearch.php +++ b/module/VuFind/src/VuFind/Controller/AbstractSearch.php @@ -224,15 +224,15 @@ class AbstractSearch extends AbstractBase } */ - /* TODO // Special case: If we're in RSS view, we need to render differently: - if ($this->view->results->getView() == 'rss') { - $this->_helper->viewRenderer->setNoRender(); - $this->_helper->layout->disableLayout(); - header('Content-type: text/xml', true); - echo $this->view->ResultFeed($this->view->results)->export('rss'); + if ($view->results->getView() == 'rss') { + $response = $this->getResponse(); + $response->getHeaders()->addHeaderLine('Content-type', 'text/xml'); + $feed = $this->getViewRenderer()->plugin('resultfeed'); + $response->setContent($feed($view->results)->export('rss')); + return $response; } - */ + return $view; } diff --git a/module/VuFind/src/VuFind/Feed/Writer/Extension/DublinCore/Entry.php b/module/VuFind/src/VuFind/Feed/Writer/Extension/DublinCore/Entry.php new file mode 100644 index 0000000000000000000000000000000000000000..a92eb588862dd370190aa08f257dd4b5cf216bd8 --- /dev/null +++ b/module/VuFind/src/VuFind/Feed/Writer/Extension/DublinCore/Entry.php @@ -0,0 +1,94 @@ +<?php +/** + * Zend\Feed\Entry extension for Dublin Core + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package Feed_Plugins + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/building_a_recommendations_module Wiki + */ +namespace VuFind\Feed\Writer\Extension\DublinCore; +use Zend\Feed\Writer\Extension\ITunes\Entry as ParentEntry; + +/** + * Zend\Feed\Entry extension for Dublin Core + * + * Note: There doesn't seem to be a generic base class for this functionality, + * and creating a class with no parent blows up due to unexpected calls to + * Itunes-related functionality. To work around this, we are extending the + * equivalent Itunes plugin. This works fine, but perhaps in future there will + * be a more elegant way to achieve the same effect. + * + * @category VuFind2 + * @package Feed_Plugins + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/building_a_recommendations_module Wiki + */ +class Entry extends ParentEntry +{ + protected $dcFormats = array(); + protected $dcDate = null; + + /** + * Add a Dublin Core format. + * + * @param string $format Format to add. + * + * @return void + */ + public function addDCFormat($format) + { + $this->dcFormats[] = $format; + } + + /** + * Set the Dublin Core date. + * + * @param string $date Date to set. + * + * @return void + */ + public function setDCDate($date) + { + $this->dcDate = $date; + } + + /** + * Get the Dublin Core date. + * + * @return string + */ + public function getDCDate() + { + return $this->dcDate; + } + + /** + * Get the Dublin Core formats. + * + * @return array + */ + public function getDCFormats() + { + return $this->dcFormats; + } +} diff --git a/module/VuFind/src/VuFind/Feed/Writer/Extension/DublinCore/Renderer/Entry.php b/module/VuFind/src/VuFind/Feed/Writer/Extension/DublinCore/Renderer/Entry.php new file mode 100644 index 0000000000000000000000000000000000000000..704eec3a5fc41b126bb1b5f3183f1e7f5bc31949 --- /dev/null +++ b/module/VuFind/src/VuFind/Feed/Writer/Extension/DublinCore/Renderer/Entry.php @@ -0,0 +1,101 @@ +<?php +/** + * Zend\Feed\Renderer\Entry extension for Dublin Core + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package Feed_Plugins + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/building_a_recommendations_module Wiki + */ +namespace VuFind\Feed\Writer\Extension\DublinCore\Renderer; +use DOMDocument, DOMElement, + Zend\Feed\Writer\Extension\DublinCore\Renderer\Entry as ParentEntry; + +/** + * Zend\Feed\Renderer\Entry extension for Dublin Core + * + * @category VuFind2 + * @package Feed_Plugins + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/building_a_recommendations_module Wiki + */ +class Entry extends ParentEntry +{ + /** + * Render entry + * + * @return void + */ + public function render() + { + if (strtolower($this->getType()) == 'atom') { + return; + } + $this->setDCFormats($this->_dom, $this->_base); + $this->setDCDate($this->_dom, $this->_base); + parent::render(); + } + + /** + * Set entry format elements + * + * @param DOMDocument $dom DOM document to update + * @param DOMElement $root Root of DOM document + * + * @return void + */ + protected function setDCFormats(DOMDocument $dom, DOMElement $root) + { + $dcFormats = $this->getDataContainer()->getDCFormats(); + if (empty($dcFormats)) { + return; + } + foreach ($dcFormats as $data) { + $format = $this->_dom->createElement('dc:format'); + $text = $dom->createTextNode($data); + $format->appendChild($text); + $root->appendChild($format); + } + $this->_called = true; + } + + /** + * Set entry date elements + * + * @param DOMDocument $dom DOM document to update + * @param DOMElement $root Root of DOM document + * + * @return void + */ + protected function setDCDate(DOMDocument $dom, DOMElement $root) + { + $dcDate = $this->getDataContainer()->getDCDate(); + if (empty($dcDate)) { + return; + } + $date = $this->_dom->createElement('dc:date'); + $text = $dom->createTextNode($dcDate); + $date->appendChild($text); + $root->appendChild($date); + $this->_called = true; + } +} diff --git a/module/VuFind/src/VuFind/Tests/ViewHelperTestCase.php b/module/VuFind/src/VuFind/Tests/ViewHelperTestCase.php index 118ff03499c2e387137336c9fa9fa4c2461143c7..d040a097d09883fb4e3c25a5070c86ff0ca29325 100644 --- a/module/VuFind/src/VuFind/Tests/ViewHelperTestCase.php +++ b/module/VuFind/src/VuFind/Tests/ViewHelperTestCase.php @@ -22,7 +22,7 @@ * * @category VuFind2 * @package Tests - * @author David Maus <maus@hab.de> + * @author Demian Katz <demian.katz@villanova.edu> * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link http://vufind.org/wiki/unit_tests Wiki */ @@ -33,7 +33,7 @@ namespace VuFind\Tests; * * @category VuFind2 * @package Tests - * @author David Maus <maus@hab.de> + * @author Demian Katz <demian.katz@villanova.edu> * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link http://vufind.org/wiki/unit_tests Wiki */ @@ -43,11 +43,12 @@ abstract class ViewHelperTestCase extends TestCase /** * Get a working renderer. * - * @param string $theme Theme directory to load from + * @param array $plugins Custom VuFind plug-ins to register + * @param string $theme Theme directory to load from * * @return \Zend\View\Renderer\PhpRenderer */ - protected function getPhpRenderer($theme = 'blueprint') + protected function getPhpRenderer($plugins = array(), $theme = 'blueprint') { $resolver = new \Zend\View\Resolver\TemplatePathStack(); @@ -62,6 +63,12 @@ abstract class ViewHelperTestCase extends TestCase ); $renderer = new \Zend\View\Renderer\PhpRenderer(); $renderer->setResolver($resolver); + if (!empty($plugins)) { + $pluginManager = $renderer->getHelperPluginManager(); + foreach ($plugins as $key => $value) { + $pluginManager->setService($key, $value); + } + } return $renderer; } diff --git a/module/VuFind/src/VuFind/Theme/Root/Helper/ResultFeed.php b/module/VuFind/src/VuFind/Theme/Root/Helper/ResultFeed.php index 011febb9ba2b58ff47491e27b4cc94042eef8658..69a5220ab535e1bed7845799dec13d6807d3a5f3 100644 --- a/module/VuFind/src/VuFind/Theme/Root/Helper/ResultFeed.php +++ b/module/VuFind/src/VuFind/Theme/Root/Helper/ResultFeed.php @@ -26,7 +26,8 @@ * @link http://vufind.org/wiki/building_a_recommendations_module Wiki */ namespace VuFind\Theme\Root\Helper; -use Zend\View\Helper\AbstractHelper; +use DateTime, Zend\Feed\Writer\Writer as FeedWriter, Zend\Feed\Writer\Feed, + Zend\View\Helper\AbstractHelper; /** * "Results as feed" view helper @@ -39,43 +40,87 @@ use Zend\View\Helper\AbstractHelper; */ class ResultFeed extends AbstractHelper { + protected $translator = false; + + /** + * Get access to the translator helper. + * + * @return object + */ + public function getTranslator() + { + if (!$this->translator) { + $this->translator = $this->getView()->plugin('translate'); + } + return $this->translator; + } + + /** + * Override the translator helper (useful for testing purposes). + * + * @param object $translator New translator object. + * + * @return void + */ + public function setTranslator($translator) + { + $this->translator = $translator; + } + + /** + * Set up Dublin Core extension. + * + * @return void + */ + protected function registerExtension() + { + $manager = FeedWriter::getExtensionManager(); + $manager->setService( + 'dublincorerendererentry', + new \VuFind\Feed\Writer\Extension\DublinCore\Renderer\Entry() + ); + $manager->setService( + 'dublincoreentry', new \VuFind\Feed\Writer\Extension\DublinCore\Entry() + ); + } + /** * Represent the current search results as a feed. * - * @param VF_Search_Base_Results $results Search results to convert to feed. + * @param \VuFind\Search\Base\Results $results Search results to convert to + * feed + * @param string $currentPath Base path to display in feed + * (leave null to load dynamically using currentpath view helper) * * @return Zend_Feed_Writer_Feed */ - public function __invoke($results) + public function __invoke($results, $currentPath = null) { - /* TODO - // Set up plugin loader so we can use custom feed extensions: - $loader = Zend_Feed_Writer::getPluginLoader(); - $loader->addPrefixPath( - 'VF_Feed_Writer_Extension_', 'VF/Feed/Writer/Extension/' - ); + $this->registerExtension(); + + // Determine base URL if not already provided: + if (is_null($currentPath)) { + $currentPath = $this->getView()->plugin('currentpath')->__invoke(); + } + $serverUrl = $this->getView()->plugin('serverurl'); + $baseUrl = $serverUrl($currentPath); // Create the parent feed - $feed = new Zend_Feed_Writer_Feed(); + $feed = new Feed(); + $translator = $this->getTranslator(); $feed->setTitle( - $this->view->translate('Results for') . ' ' - . $results->getDisplayQuery() - ); - $feed->setLink( - $this->view->serverUrl($this->view->currentPath()) - . $results->getUrl()->setViewParam(null, false) + $translator('Results for') . ' ' . $results->getDisplayQuery() ); + $feed->setLink($baseUrl . $results->getUrl()->setViewParam(null, false)); $feed->setFeedLink( - $this->view->serverUrl($this->view->currentPath()) - . $results->getUrl()->getParams(false), - $results->getView() + $baseUrl . $results->getUrl()->getParams(false), $results->getView() ); $records = $results->getResults(); $feed->setDescription( - $this->view->translate('Displaying the top') . ' ' . count($records) - . ' ' . $this->view->translate('search results of') . ' ' - . $results->getResultTotal() . ' ' . $this->view->translate('found') + $translator('Displaying the top') . ' ' . count($records) + . ' ' . $translator('search results of') . ' ' + . $results->getResultTotal() . ' ' . $translator('found') ); foreach ($records as $current) { @@ -83,7 +128,6 @@ class ResultFeed extends AbstractHelper } return $feed; - */ } /** @@ -129,7 +173,7 @@ class ResultFeed extends AbstractHelper * * @param VF_RecordDriver_Base $record Record to pull date from. * - * @return int|Zend_Date|null + * @return int|DateTime|null */ protected function getDateModified($record) { @@ -144,9 +188,9 @@ class ResultFeed extends AbstractHelper if (isset($date[0])) { // Extract first string of numbers -- this should be a year: preg_match('/[^0-9]*([0-9]+).*/', $date[0], $matches); - return new Zend_Date( - array('year' => $matches[1], 'month' => 1, 'day' => 1) - ); + $date = new DateTime(); + $date->setDate($matches[1], 1, 1); + return $date; } // If we got this far, no date is available: diff --git a/module/VuFind/tests/Theme/Root/Helper/ResultFeedTest.php b/module/VuFind/tests/Theme/Root/Helper/ResultFeedTest.php new file mode 100644 index 0000000000000000000000000000000000000000..32c23958de864fb421605b93538c09cd2c0c0abb --- /dev/null +++ b/module/VuFind/tests/Theme/Root/Helper/ResultFeedTest.php @@ -0,0 +1,109 @@ +<?php +/** + * ResultFeed Test Class + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/unit_tests Wiki + */ +namespace VuFind\Test\Theme\Root\Helper; +use VuFind\Theme\Root\Helper\ResultFeed; + +/** + * ResultFeed Test Class + * + * @category VuFind2 + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/unit_tests Wiki + */ +class ResultFeedTest extends \VuFind\Tests\ViewHelperTestCase +{ + /** + * Get plugins to register to support view helper being tested + * + * @return array + */ + protected function getPlugins() + { + $recordLink = $this->getMock('VuFind\Theme\Root\Helper\RecordLink'); + $recordLink->expects($this->any())->method('getUrl') + ->will($this->returnValue('test/url')); + return array( + 'recordlink' => $recordLink + ); + } + + /** + * Test feed generation + * + * @return void + */ + public function testRSS() + { + // Set up a request -- we'll sort by title to ensure a predictable order + // for the result list (relevance or last_indexed may lead to unstable test + // cases). + $request = new \Zend\Stdlib\Parameters(); + $request->set('lookfor', 'id:testbug2 OR id:testsample1'); + $request->set('skip_rss_sort', 1); + $request->set('sort', 'title'); + $request->set('view', 'rss'); + + $params = new \VuFind\Search\Solr\Params(); + $params->initFromRequest($request); + + $results = new \VuFind\Search\Solr\Results($params); + $helper = new ResultFeed(); + $helper->setView($this->getPhpRenderer($this->getPlugins())); + $mockTranslator = function ($str) { + return $str; + }; + $helper->setTranslator($mockTranslator); + $feed = $helper->__invoke($results, '/test/path'); + $this->assertTrue(is_object($feed)); + $rss = $feed->export('rss'); + + // Make sure it's really an RSS feed: + $this->assertTrue(strstr($rss, '<rss') !== false); + + // Make sure custom Dublin Core elements are present: + $this->assertTrue(strstr($rss, 'dc:format') !== false); + + // Now re-parse it and check for some expected values: + $parsedFeed = \Zend\Feed\Reader\Reader::importString($rss); + $this->assertEquals( + $parsedFeed->getDescription(), + 'Displaying the top 2 search results of 2 found' + ); + $items = array(); + $i = 0; + foreach ($parsedFeed as $item) { + $items[$i++] = $item; + } + $this->assertEquals( + $items[1]->getTitle(), 'Journal of rational emotive therapy : ' + . 'the journal of the Institute for Rational-Emotive Therapy.' + ); + } +} \ No newline at end of file