From 33c696263dddc7b27d4e49edbf0633ede8eaffd5 Mon Sep 17 00:00:00 2001 From: Demian Katz <demian.katz@villanova.edu> Date: Thu, 19 Jul 2012 14:07:35 -0400 Subject: [PATCH] Added remaining missing controllers (not functional yet). --- module/VuFind/config/module.config.php | 2 + .../VuFind/Controller/UpgradeController.php | 476 ++++++++++++++++++ .../src/VuFind/Controller/VudlController.php | 274 ++++++++++ 3 files changed, 752 insertions(+) create mode 100644 module/VuFind/src/VuFind/Controller/UpgradeController.php create mode 100644 module/VuFind/src/VuFind/Controller/VudlController.php diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index 4c2696674de..05cb8bebac5 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -83,6 +83,8 @@ $config = array( 'summon' => 'VuFind\Controller\SummonController', 'summonrecord' => 'VuFind\Controller\SummonrecordController', 'tag' => 'VuFind\Controller\TagController', + 'upgrade' => 'VuFind\Controller\UpgradeController', + 'vudl' => 'VuFind\Controller\VudlController', 'worldcat' => 'VuFind\Controller\WorldcatController', 'worldcatrecord' => 'VuFind\Controller\WorldcatrecordController', ), diff --git a/module/VuFind/src/VuFind/Controller/UpgradeController.php b/module/VuFind/src/VuFind/Controller/UpgradeController.php new file mode 100644 index 00000000000..03c007644c8 --- /dev/null +++ b/module/VuFind/src/VuFind/Controller/UpgradeController.php @@ -0,0 +1,476 @@ +<?php +/** + * Upgrade Controller + * + * 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 Controller + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org Main Site + */ +namespace VuFind\Controller; + +/** + * Class controls VuFind upgrading. + * + * @category VuFind2 + * @package Controller + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org Main Site + */ +class UpgradeController extends AbstractBase +{ + protected $cookie; + protected $session; + + /** + * init + * + * @return void + */ + public function init() + { + /* TODO + $this->view->flashMessenger = $this->_helper->flashMessenger; + + // We want to use cookies for tracking the state of the upgrade, since the + // session is unreliable -- if the user upgrades a configuration that uses + // a different session handler than the default one, we'll lose track of our + // upgrade state in the middle of the process! + $this->cookie = new VF_Cookie_Namespace('vfup'); + + // ...however, once the configuration piece of the upgrade is done, we can + // safely use the session for storing some values. We'll use this for the + // temporary storage of root database credentials, since it is unwise to + // send such sensitive values around as cookies! + $this->session = new Zend_Session_Namespace('upgrade'); + + // We should also use the session for storing warnings once we know it will + // be stable; this will prevent the cookies from getting too big. + if (!isset($this->session->warnings)) { + $this->session->warnings = array(); + } + */ + } + + /** + * Support method -- given a directory, extract a version number from the + * build.xml file within that directory. + * + * @param string $dir Directory to search for build.xml + * + * @return string + */ + protected function getVersion($dir) + { + $xml = simplexml_load_file($dir . '/build.xml'); + if (!$xml) { + throw new \Exception('Cannot load ' . $dir . '/build.xml.'); + } + $parts = $xml->xpath('/project/property[@name="version"]/@value'); + return (string)$parts[0]; + } + + /** + * Display a fatal error message. + * + * @return void + */ + public function errorAction() + { + // Just display template + return $this->createViewModel(); + } + + /** + * Figure out which version(s) are being used. + * + * @return void + */ + public function establishversionsAction() + { + /* TODO + $this->cookie->oldVersion = $this->getVersion( + realpath(APPLICATION_PATH . '/..') + ); + $this->cookie->newVersion = $this->getVersion( + $this->cookie->sourceDir + ); + + // Block upgrade when encountering common errors: + if (empty($this->cookie->oldVersion)) { + $this->_helper->flashMessenger->setNamespace('error') + ->addMessage('Cannot determine source version.'); + unset($this->cookie->oldVersion); + return $this->_forward('Error'); + } + if (empty($this->cookie->newVersion)) { + $this->_helper->flashMessenger->setNamespace('error') + ->addMessage('Cannot determine destination version.'); + unset($this->cookie->newVersion); + return $this->_forward('Error'); + } + if ($this->cookie->newVersion == $this->cookie->oldVersion) { + $this->_helper->flashMessenger->setNamespace('error') + ->addMessage('Cannot upgrade version to itself.'); + unset($this->cookie->newVersion); + return $this->_forward('Error'); + } + + // If we got this far, everything is okay: + return $this->_forward('Home'); + */ + } + + /** + * Upgrade the configuration files. + * + * @return void + */ + public function fixconfigAction() + { + /* TODO + $upgrader = new VF_Config_Upgrade( + $this->cookie->oldVersion, $this->cookie->newVersion, + $this->cookie->sourceDir . '/web/conf', + APPLICATION_PATH . '/configs', + LOCAL_OVERRIDE_DIR . '/application/configs' + ); + try { + $upgrader->run(); + $this->cookie->warnings = $upgrader->getWarnings(); + $this->cookie->configOkay = true; + return $this->_forward('Home'); + } catch (Exception $e) { + $extra = is_a($e, 'VF_Exception_FileAccess') + ? ' Check file permissions.' : ''; + $this->_helper->flashMessenger->setNamespace('error') + ->addMessage('Config upgrade failed: ' . $e->getMessage() . $extra); + return $this->_forward('Error'); + } + */ + } + + /** + * Upgrade the database. + * + * @return void + */ + public function fixdatabaseAction() + { + /* TODO + try { + // Set up the helper with information from our SQL file: + $this->_helper->dbUpgrade->loadSql(APPLICATION_PATH . '/sql/mysql.sql'); + + // Check for missing tables. Note that we need to finish dealing with + // missing tables before we proceed to the missing columns check, or else + // the missing tables will cause fatal errors during the column test. + $missingTables = $this->_helper->dbUpgrade->getMissingTables(); + if (!empty($missingTables)) { + if (!isset($this->session->dbRootUser) + || !isset($this->session->dbRootPass) + ) { + return $this->_forward('GetDbCredentials'); + } + $db = VF_DB::connect( + $this->session->dbRootUser, $this->session->dbRootPass + ); + $this->_helper->dbUpgrade->createMissingTables($missingTables, $db); + $this->session->warnings[] = "Created missing table(s): " + . implode(', ', $missingTables); + } + + // Check for missing columns. + $missingCols = $this->_helper->dbUpgrade->getMissingColumns(); + if (!empty($missingCols)) { + if (!isset($this->session->dbRootUser) + || !isset($this->session->dbRootPass) + ) { + return $this->_forward('GetDbCredentials'); + } + if (!isset($db)) { // connect to DB if not already connected + $db = VF_DB::connect( + $this->session->dbRootUser, $this->session->dbRootPass + ); + } + $this->_helper->dbUpgrade->createMissingColumns($missingCols, $db); + $this->session->warnings[] = "Added column(s) to table(s): " + . implode(', ', array_keys($missingCols)); + } + + // Check for modified columns. + $modifiedCols = $this->_helper->dbUpgrade->getModifiedColumns(); + if (!empty($modifiedCols)) { + if (!isset($this->session->dbRootUser) + || !isset($this->session->dbRootPass) + ) { + return $this->_forward('GetDbCredentials'); + } + if (!isset($db)) { // connect to DB if not already connected + $db = VF_DB::connect( + $this->session->dbRootUser, $this->session->dbRootPass + ); + } + $this->_helper->dbUpgrade->updateModifiedColumns($modifiedCols, $db); + $this->session->warnings[] = "Modified column(s) in table(s): " + . implode(', ', array_keys($modifiedCols)); + } + + // Don't keep DB credentials in session longer than necessary: + unset($this->session->dbRootUser); + unset($this->session->dbRootPass); + + // Check for legacy "anonymous tag" bug: + $anonymousTags = VuFind_Model_Db_Tags::getAnonymousCount(); + if ($anonymousTags > 0 && !isset($this->cookie->skipAnonymousTags)) { + $this->view->anonymousCount = $anonymousTags; + return $this->_forward('FixAnonymousTags'); + } + } catch (Exception $e) { + $this->_helper->flashMessenger->setNamespace('error') + ->addMessage('Database upgrade failed: ' . $e->getMessage()); + return $this->_forward('Error'); + } + + $this->cookie->databaseOkay = true; + return $this->_forward('Home'); + */ + } + + /** + * Prompt the user for database credentials. + * + * @return void + */ + public function getdbcredentialsAction() + { + /* TODO + $this->view->dbrootuser = $this->_request->getParam('dbrootuser', 'root'); + + // Process form submission: + if (strlen($this->_request->getParam('submit', '')) > 0) { + $pass = $this->_request->getParam('dbrootpass'); + + // Test the connection: + try { + $db = VF_DB::connect($this->view->dbrootuser, $pass); + $db->query("SELECT * FROM user;"); // query a table known to exist + $this->session->dbRootUser = $this->view->dbrootuser; + $this->session->dbRootPass = $pass; + return $this->_forward('FixDatabase'); + } catch (Exception $e) { + $this->_helper->flashMessenger->setNamespace('error') + ->addMessage('Could not connect; please try again.'); + } + } + */ + } + + /** + * Prompt the user about fixing anonymous tags. + * + * @return void + */ + public function fixanonymoustagsAction() + { + /* TODO + // Handle skip action: + if (strlen($this->_request->getParam('skip', '')) > 0) { + $this->cookie->skipAnonymousTags = true; + return $this->_forward('FixDatabase'); + } + + // Handle submit action: + if (strlen($this->_request->getParam('submit', '')) > 0) { + $user = $this->_request->getParam('username'); + if (empty($user)) { + $this->_helper->flashMessenger->setNamespace('error') + ->addMessage('Username must not be empty.'); + } else { + $user = VuFind_Model_Db_User::getByUsername($user, false); + if (empty($user) || !is_object($user) || !isset($user->id)) { + $this->_helper->flashMessenger->setNamespace('error') + ->addMessage("User {$user} not found."); + } else { + $table = new VuFind_Model_Db_ResourceTags(); + $table->assignAnonymousTags($user->id); + $this->session->warnings[] + = "Assigned all anonymous tags to {$user->username}."; + return $this->_forward('FixDatabase'); + } + } + } + */ + } + + /** + * Fix missing metadata in the resource table. + * + * @return void + */ + public function fixmetadataAction() + { + /* TODO + // User requested skipping this step? No need to do further work: + if (strlen($this->_request->getParam('skip', '')) > 0) { + $this->cookie->metadataOkay = true; + return $this->_forward('Home'); + } + + // Check for problems: + $table = new VuFind_Model_Db_Resource(); + $problems = $table->findMissingMetadata(); + + // No problems? We're done here! + if (count($problems) == 0) { + $this->cookie->metadataOkay = true; + return $this->_forward('Home'); + } + + // Process submit button: + if (strlen($this->_request->getParam('submit', '')) > 0) { + foreach ($problems as $problem) { + try { + $driver = VF_Record::load($problem->record_id, $problem->source); + $problem->assignMetadata($driver)->save(); + } catch (VF_Exception_RecordMissing $e) { + $this->session->warnings[] + = "Unable to load metadata for record " + . "{$problem->source}:{$problem->record_id}"; + } + } + $this->cookie->metadataOkay = true; + return $this->_forward('Home'); + } + */ + } + + /** + * Prompt the user for a source directory. + * + * @return void + */ + public function getsourcedirAction() + { + /* TODO + // Process form submission: + $dir = $this->_request->getParam('sourcedir'); + if (!empty($dir)) { + $this->cookie->sourceDir = rtrim($dir, '\/'); + // Clear out request to avoid infinite loop: + $this->_request->setParam('sourcedir', ''); + return $this->_forward('Home'); + } + + // If a bad directory was provided, display an appropriate error: + if (isset($this->cookie->sourceDir)) { + if (!is_dir($this->cookie->sourceDir)) { + $this->_helper->flashMessenger->setNamespace('error') + ->addMessage($this->cookie->sourceDir . ' does not exist.'); + } else if (!file_exists($this->cookie->sourceDir . '/build.xml')) { + $this->_helper->flashMessenger->setNamespace('error')->addMessage( + 'Could not find build.xml in source directory;' + . ' upgrade does not support VuFind versions prior to 1.1.' + ); + } + } + */ + } + + /** + * Display summary of installation status + * + * @return void + */ + public function homeAction() + { + /* TODO + // If the cache is messed up, nothing is going to work right -- check that + // first: + $cache = new VF_Cache_Manager(); + if ($cache->hasDirectoryCreationError()) { + return $this->_redirect('/Install/fixcache'); + } + + // First find out which version we are upgrading: + if (!isset($this->cookie->sourceDir) + || !is_dir($this->cookie->sourceDir) + ) { + return $this->_forward('GetSourceDir'); + } + + // Next figure out which version(s) are involved: + if (!isset($this->cookie->oldVersion) + || !isset($this->cookie->newVersion) + ) { + return $this->_forward('EstablishVersions'); + } + + // Now make sure we have a configuration file ready: + if (!isset($this->cookie->configOkay)) { + return $this->_redirect('/Upgrade/FixConfig'); + } + + // Now make sure the database is up to date: + if (!isset($this->cookie->databaseOkay)) { + return $this->_redirect('/Upgrade/FixDatabase'); + } + + // Check for missing metadata in the resource table; note that we do a + // redirect rather than a forward here so that a submit button clicked + // in the database action doesn't cause the metadata action to also submit! + if (!isset($this->cookie->metadataOkay)) { + return $this->_redirect('/Upgrade/FixMetadata'); + } + + // We're finally done -- display any warnings that we collected during + // the process. + $allWarnings = array_merge( + isset($this->cookie->warnings) ? $this->cookie->warnings : array(), + $this->session->warnings + ); + foreach ($allWarnings as $warning) { + $this->_helper->flashMessenger->setNamespace('info') + ->addMessage($warning); + } + */ + } + + /** + * Start over with the upgrade process in case of an error. + * + * @return void + */ + public function resetAction() + { + /* TODO + foreach ($this->cookie->getAllValues() as $k => $v) { + unset($this->cookie->$k); + } + foreach ($this->session as $k => $v) { + unset($this->session->$k); + } + return $this->_forward('Home'); + */ + } +} + diff --git a/module/VuFind/src/VuFind/Controller/VudlController.php b/module/VuFind/src/VuFind/Controller/VudlController.php new file mode 100644 index 00000000000..596491eb47e --- /dev/null +++ b/module/VuFind/src/VuFind/Controller/VudlController.php @@ -0,0 +1,274 @@ +<?php +/** + * VuDLController Module Controller + * + * PHP Version 5 + * + * Copyright (C) Villanova University 2011. + * + * 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 Controller + * @author Chris Hallberg <challber@villanova.edu> + * @author David Lacy <david.lacy@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org Main Site + */ +namespace VuFind\Controller; +use VuFind\Search\Solr\Results as SolrResults; + +/** + * This controller is for the viewing of the digital library files. + * + * @category VuFind2 + * @package Controller + * @author Chris Hallberg <challber@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org Main Site + */ +class VudlController extends AbstractBase +{ + /** + * Get the information from the XML + * + * Image srcs, document groups + * + * Data is later loaded and rendered with JS + * + * @return void + */ + public function recordAction() + { + /* TODO + // TARGET ID + $id = $this->_request->getParam('id'); + $this->view->id = $id; + + // GET XML FILE NAME + $driver = SolrResults::getRecord($id); + if (!method_exists($driver, 'getFullRecord')) { + throw new Exception('Cannot obtain VuDL record'); + } + $result = $driver->getFullRecord(); + $url = isset($result->url) ? trim($result->url) : false; + if (empty($url)) { + throw new Exception('Not a VuDL Record: '.$id); + } + + // LOAD FILE (this is the only time we pull the whole XML file + $xml = simplexml_load_file($url); + if (!$xml) { + //echo 'catch','<br>'; + // DOUBLE ENCODING MADNESS - some of the records need to be encoded + $split = explode('/', $url); + // uri encode everything in url after 'VuDL' + for ($i=8;$i<count($split);$i++) { + //echo $split[$i],'<br>'; + $split[$i] = rawurlencode($split[$i]); + } + $url = implode($split, '/'); + $xml = simplexml_load_file($url); + } + + // FILE INFORMATION / DESCRIPTION + $fileDetails = $this->getDocSummary($xml); + $this->view->details = $fileDetails; + $this->view->file = urlencode($url); + + // GET IDS FOR ALL FILES + $files = $this->getAllFiles($xml); + + // GET PAGE AND DOCUMENT STRUCTURE + $pages = array(); + $docs = array(); + foreach ($xml->xpath('//METS:structMap/METS:div/METS:div') as $div) { + foreach ($div->xpath('METS:div') as $item) { + $index = intval($item['ORDER']) - 1; + // Only the first five pages, the rest are loaded thru AJAX + if ($div['TYPE'] == 'page_level') { + $pages[$index] = array( + 'label'=>(string) $item['LABEL'], + 'original' => '' + ); + // Store image srcs under their use + foreach ($item->xpath('METS:fptr') as $id) { + $file = $files[(string) $id['FILEID']]; + $pages[$index][$file['use']] = $file['src']; + } + } elseif ($div['TYPE'] == 'document_level') { + $id = $item->xpath('METS:fptr'); + $id = $id[0]; + // Assuming only one document per... document + $file = $files[(string) $id['FILEID']]; + $docs[$index] = array( + 'label' =>(string) $item['LABEL'], + 'src' => $file['src'] + ); + // Set the right thumbnail + if ($file['type'] == 'application/pdf') { + $docs[$index]['img'] = 'pdf'; + } elseif ($file['type'] == 'application/msword') { + $docs[$index]['img'] = 'doc'; + } + } + } + } + + // SEND THE DATA FOR THE FIRST PAGES + // (Original, Large, Medium, Thumbnail srcs) and THE DOCUMENTS + $this->view->pages = $pages; + $this->view->docs = $docs; + */ + } + + /** + * In order to reduce initial load time the majority + * of the data is called here after document.ready + * + * @return string JSON encoded data with the urls of all the images + * for each page associated with the document + */ + public function pageDataAction() + { + /* TODO + // We don't want to use views or layouts in this controller since + // it is responsible for generating AJAX responses rather than HTML. + $this->_helper->viewRenderer->setNoRender(); + $this->_helper->layout->disableLayout(); + + $url = $this->_request->getParam('file'); + $xml = simplexml_load_file($url); + + // GET IDS FOR ALL FILES + $files = $this->getAllFiles($xml); + + // RETURN IMAGES BY use AND labels + foreach ($xml->xpath('//METS:structMap/METS:div/METS:div') as $div) { + error_reporting(0); // No notices in my JSON please! + foreach ($div->xpath('METS:div') as $item) { + if ($div['TYPE'] == 'page_level') { + $index = intval($item['ORDER']) - 1; + $pages[$index] = array( + 'label'=>(string) $item['LABEL'], + 'original' => '' + ); + // Store image srcs under their use + foreach ($item->xpath('METS:fptr') as $id) { + $file = $files[(string) $id['FILEID']]; + $pages[$index][$file['use']] = $file['src']; + } + } + } + } + echo json_encode($pages); + error_reporting(-1); + */ + } + + /** + * Parses the xml file for the section detailing the files + * + * @param SimpleXMLElement $xml - to be parsed + * + * @return An array of file objects, string-indexed by ID + * Object contains 'src','type','use'(size) + */ + protected function getAllFiles($xml) + { + $files = array(); + // really only one: + foreach ($xml->xpath('//METS:fileSec') as $fileSec) { + // for each group: + foreach ($fileSec->xpath('METS:fileGrp') as $i=>$group) { + // store by id: + foreach ($group->xpath('METS:file') as $j=>$file) { + $src = $file->xpath('METS:FLocat'); + $src = $src[0]->attributes('xlink', true); + $files[ $file['ID'].'' ] = array( + 'src' => (string) $src['href'], + 'type' => (string) $file['MIMETYPE'], + 'use' => strtolower((string) $group['USE']) + ); + } + } + } + return $files; + } + + /** + * Pull the file details (title, date, etc) from the XML + * + * Data is string indexed by what type of information it is + * + * @param SimpleXMLElement $xml - to be parsed + * + * @return title-indexed array of basic document data + * 'author' => 'Kevin Bacon', etc. + */ + protected function getDocSummary($xml) + { + $data = array(); + foreach ($xml->xpath('//METS:xmlData') as $xmlData) { + if (count($xmlData->children('oai_dc', true)) > 0) { + foreach ($xmlData->children('oai_dc', true) as $doc_data) { + foreach ($doc_data->children('dc', true) as $detail) { + $index = $detail->getName(); + $data[$index] =(string) $detail; + } + } + return $data; + } + } + } + + /** + * Used to AJAX information about a page that may not have been loaded yet. + * + * This is a hardly used fallback and may be a candid for deletion + * + * @return JSON encoded array with information about the images + * associated with the parameter-specified page. + * Indexed by use (size) + */ + public function pageTabsAction() + { + /* TODO + // We don't want to use views or layouts in this controller since + // it is responsible for generating AJAX responses rather than HTML. + $this->_helper->viewRenderer->setNoRender(); + $this->_helper->layout->disableLayout(); + + $page = intval($this->_request->getParam('page')); + // TARGET ID + $id = $this->_request->getParam('id'); + $xml = $this->getXMLRecord($id); + + // GET FILE IDs AND SRCs + $files = $this->getAllFiles($xml); + + // GET PAGES + $pages = $this->getPageStructure($xml); + if ($id >= count($pages)) { + echo ''; + } + + $re = array(); + foreach ($pages[$page]['ids'] as $id) { + $re[strtolower($files[$id]['use'])] = $files[$id]['src']; + } + echo json_encode($re); + */ + } +} -- GitLab