From 9339f9cbef1278bae9af092a56c2392e7ab69476 Mon Sep 17 00:00:00 2001 From: Demian Katz <demian.katz@villanova.edu> Date: Mon, 2 Jul 2012 14:57:54 -0400 Subject: [PATCH] Finished namespacing connection code (untested). --- .../src/VuFind/Connection/OpenLibrary.php | 172 ++++++ .../VuFind/src/VuFind/Connection/Oracle.php | 582 ++++++++++++++++++ 2 files changed, 754 insertions(+) create mode 100644 module/VuFind/src/VuFind/Connection/OpenLibrary.php create mode 100644 module/VuFind/src/VuFind/Connection/Oracle.php diff --git a/module/VuFind/src/VuFind/Connection/OpenLibrary.php b/module/VuFind/src/VuFind/Connection/OpenLibrary.php new file mode 100644 index 00000000000..ea20a82b87f --- /dev/null +++ b/module/VuFind/src/VuFind/Connection/OpenLibrary.php @@ -0,0 +1,172 @@ +<?php +/** + * Open Library Utilities + * + * 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 Support_Classes + * @author Eoghan Ó Carragáin <eoghan.ocarragain@gmail.com> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/system_classes Wiki + */ +namespace VuFind\Connection; +use VuFind\Http\Client as HttpClient; + +/** + * Open Library Utilities + * + * Class for accessing helpful Open Library APIs. + * + * @category VuFind2 + * @package Support_Classes + * @author Eoghan Ó Carragáin <eoghan.ocarragain@gmail.com> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/system_classes Wiki + */ +class OpenLibrary +{ + /** + * Returns an array of elements for each work matching the + * parameters. An API call will be made for each subjectType until + * data is returned + * + * @param string $subject The subject term to be looked for + * @param string $publishedIn Date range in the form YYYY-YYYY + * @param array $subjectTypes An array of subject types to check + * @param bool $ebooks Whether to use ebook filter + * @param bool $details Whether to return full details + * @param int $limit The number of works to return + * @param int $offset Paging offset + * @param bool $publicFullText Only return publically available, full-text + * works + * + * @return array + */ + public function getSubjects( + $subject, $publishedIn, $subjectTypes, $ebooks = true, $details = false, + $limit = 5, $offset = null, $publicFullText = true + ) { + // empty array to hold the result + $result = array(); + + // normalise subject term + $subject = $this->normaliseSubjectString($subject); + if ($ebooks) { + $ebooks = "true"; + } + if ($details) { + $details = "true"; + } + + for ($i = 0; $i < count($subjectTypes); $i++) { + if (empty($result)) { + $subjectType = ""; + $subjectType = $subjectTypes[$i] == "topic" ? "" : + $subjectTypes[$i] . ":"; + + // build url + // ebooks parameter does not work at present, so limit has been set + // to 50 to increase likelihood of full-text, public scans being + // returned. see https://bugs.launchpad.net/openlibrary/+bug/709772 + $url= "http://openlibrary.org/subjects/" . $subjectType . $subject . + ".json?ebooks=" . $ebooks . "&details=" . $details . + "&offset=" . $offset . "&limit=50&published_in=" . $publishedIn; + + // make API call + $result = $this->processSubjectsApi($url, $limit, $publicFullText); + } + } + return $result; + } + + /** + * Return the following array of values for each work: + * title, cover_id, cover_id_type, key, ia, mainAuthor + * + * @param string $url URL to request + * @param int $limit The number of works to return + * @param bool $publicFullText Only return publically available, full-text + * works + * + * @return array + */ + protected function processSubjectsApi($url, $limit, $publicFullText) + { + // empty array to hold the result + $result = array(); + + //find out if there are any reviews + $client = new HttpClient(); + $client->setUri($url); + + $response = $client->setMethod('GET')->send(); + // Was the request successful? + if ($response->isSuccess()) { + // grab the response: + $json = $response->getBody(); + // parse json + $data = json_decode($json, true); + if ($data) { + $i = 1; + foreach ($data['works'] as $work) { + if ($i <= $limit) { + if ($publicFullText && (!$work['public_scan'] + || !$work['has_fulltext']) + ) { + continue; + } + $result[$i]['title'] = $work['title']; + if (isset($work['cover_id'])) { + $result[$i]['cover_id_type'] = 'ID'; + $result[$i]['cover_id'] = $work['cover_id']; + } elseif (isset($work['cover_edition_key'])) { + $result[$i]['cover_id_type'] = 'OLID'; + $result[$i]['cover_id'] = $work['cover_edition_key']; + } + $result[$i]['key'] = $work['key']; + $result[$i]['ia'] = $work['ia']; + $result[$i]['mainAuthor'] = $work['authors'][0]['name']; + $i++; + } + } + } + } + return $result; + } + + /** + * Support function to return a normalised version of the search string + * for use in the API url + * + * @param string $subject Search string to normalise + * + * @return string + */ + protected function normaliseSubjectString($subject) + { + //normalise search term + $subject = str_replace('"', "", $subject); + $subject = str_replace(",", "", $subject); + $subject = trim(strtolower($subject)); + $subject = preg_replace("/\s+/", "_", $subject); + return $subject; + } +} + +?> \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Connection/Oracle.php b/module/VuFind/src/VuFind/Connection/Oracle.php new file mode 100644 index 00000000000..929188bf628 --- /dev/null +++ b/module/VuFind/src/VuFind/Connection/Oracle.php @@ -0,0 +1,582 @@ +<?php +/** + * Oracle support code for VTLS Virtua Driver + * + * PHP version 5 + * + * Copyright (C) University of Southern Queensland 2008. + * + * 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 Support_Classes + * @author Greg Pendlebury <vufind-tech@lists.sourceforge.net> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/system_classes Wiki + */ +namespace VuFind\Connection; + +/** + * Oracle support code for VTLS Virtua Driver + * + * @category VuFind2 + * @package Support_Classes + * @author Greg Pendlebury <vufind-tech@lists.sourceforge.net> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/system_classes Wiki + */ +class Oracle +{ + // Database Handle + protected $dbHandle; + + // Error information + protected $lastError; + protected $lastErrorType; + protected $lastErrorFields; + protected $lastSql; + + /** + * Constructor -- connect to database. + * + * @param string $username Username for connection + * @param string $password Password for connection + * @param string $tns TNS specification for connection + */ + public function __construct($username, $password, $tns) + { + $this->clearError(); + $tmp = error_reporting(1); + if ($this->dbHandle = @oci_connect($username, $password, $tns)) { + error_reporting($tmp); + $this->audit_id = 0; + $this->detail_id = 0; + } else { + error_reporting($tmp); + $this->handleError('connect', oci_error()); + throw new Exception('Oracle connection problem.'); + } + } + + /** + * Get access to the Oracle handle. + * + * @return resource + */ + public function getHandle() + { + return $this->dbHandle; + } + + /** + * Destructor + * + * @return void + */ + public function __destruct() + { + // Close the OCI connection unless we failed to establish it: + if ($this->dbHandle !== false) { + oci_close($this->dbHandle); + } + } + + /** + * Wrapper around oci_parse. + * + * @param string $sql SQL statement to prepare. + * + * @return mixed SQL resource on success, boolean false otherwise. + */ + public function prepare($sql) + { + if ($parsed = @oci_parse($this->dbHandle, $sql)) { + return $parsed; + } else { + $this->handleError('parsing', oci_error($this->dbHandle), $sql); + return false; + } + } + + /** + * Wrapper around oci_new_descriptor. + * + * @return mixed New descriptor on success, boolean false otherwise. + */ + public function prepRowId() + { + if ($new_id = @oci_new_descriptor($this->dbHandle, OCI_D_ROWID)) { + return $new_id; + } else { + $this->handleError('new_descriptor', oci_error($this->dbHandle)); + return false; + } + } + + /** + * Wrapper around oci_bind_by_name. + * + * @param resource $parsed Result returned by prepare() method. + * @param string $place_holder The colon-prefixed bind variable placeholder + * used in the statement. + * @param string $data The PHP variable to be associatd with + * $place_holder + * @param string $data_type The type of $data (string, integer, float, + * long, date, row_id, clob, or blob) + * @param int $length Sets the maximum length for the data. If you + * set it to -1, this function will use the current length of variable to set + * the maximum length. + * + * @return bool + */ + public function bindParam( + $parsed, $place_holder, $data, $data_type = 'string', $length = -1 + ) { + switch ($data_type) { + case 'string': + $oracle_data_type = SQLT_CHR; + break; + case 'integer': + $oracle_data_type = SQLT_INT; + break; + case 'float': + $oracle_data_type = SQLT_FLT; + break; + case 'long': + $oracle_data_type = SQLT_LNG; + break; + // Date is redundant since default is varchar, + // but it's here for clarity. + case 'date': + $oracle_data_type = SQLT_CHR; + break; + case 'row_id': + $oracle_data_type = SQLT_RDD; + break; + case 'clob': + $oracle_data_type = SQLT_CLOB; + break; + case 'blob': + $oracle_data_type = SQLT_BLOB; + break; + default: + $oracle_data_type = SQLT_CHR; + break; + } + + if (@oci_bind_by_name( + $parsed, $place_holder, $data, $length, $oracle_data_type + )) { + return true; + } else { + $this->handleError('binding', oci_error()); + return false; + } + } + + /** + * Same as bindParam(), but variable is parsed by reference to allow for correct + * functioning of the 'RETURNING' sql statement. Annoying, but putting it in two + * separate functions allows the user to pass string literals into bindParam + * without a fatal error. + * + * @param resource $parsed Result returned by prepare() method. + * @param string $place_holder The colon-prefixed bind variable placeholder + * used in the statement. + * @param string &$data The PHP variable to be associatd with + * $place_holder + * @param string $data_type The type of $data (string, integer, float, + * long, date, row_id, clob, or blob) + * @param int $length Sets the maximum length for the data. If you + * set it to -1, this function will use the current length of variable to set + * the maximum length. + * + * @return bool + */ + public function returnParam( + $parsed, $place_holder, &$data, $data_type = 'string', $length = -1 + ) { + switch ($data_type) { + case 'string': + $oracle_data_type = SQLT_CHR; + break; + case 'integer': + $oracle_data_type = SQLT_INT; + break; + case 'float': + $oracle_data_type = SQLT_FLT; + break; + case 'long': + $oracle_data_type = SQLT_LNG; + break; + // Date is redundant since default is varchar, + // but it's here for clarity. + case 'date': + $oracle_data_type = SQLT_CHR; + break; + case 'row_id': + $oracle_data_type = SQLT_RDD; + break; + case 'clob': + $oracle_data_type = SQLT_CLOB; + break; + case 'blob': + $oracle_data_type = SQLT_BLOB; + break; + default: + $oracle_data_type = SQLT_CHR; + break; + } + + if (@oci_bind_by_name( + $parsed, $place_holder, $data, $length, $oracle_data_type + )) { + return true; + } else { + $this->handleError('binding', oci_error()); + return false; + } + } + + /** + * Wrapper around oci_execute. + * + * @param resource $parsed Result returned by prepare() method. + * + * @return bool + */ + public function exec($parsed) + { + // OCI_DEFAULT == DO NOT COMMIT!!! + if (@oci_execute($parsed, OCI_DEFAULT)) { + return true; + } else { + $this->handleError('executing', oci_error($parsed)); + return false; + } + } + + /** + * Wrapper around oci_commit. + * + * @return bool + */ + public function commit() + { + if (@oci_commit($this->dbHandle)) { + return true; + } else { + $this->handleError('commit', oci_error($this->dbHandle)); + return false; + } + } + + /** + * Wrapper around oci_rollback. + * + * @return bool + */ + public function rollback() + { + if (@oci_rollback($this->dbHandle)) { + return true; + } else { + $this->handleError('rollback', oci_error($this->dbHandle)); + return false; + } + } + + /** + * Wrapper around oci_free_statement. + * + * @param resource $parsed Result returned by prepare() method. + * + * @return bool + */ + public function free($parsed) + { + if (@oci_free_statement($parsed)) { + return true; + } else { + $this->handleError('free', oci_error($this->dbHandle)); + return false; + } + } + + /** + * Execute a SQL statement and return the results. + * + * @param string $sql SQL to execute + * @param array $fields Bind parameters (optional) + * + * @return array|bool Results on success, false on error. + */ + public function simpleSelect($sql, $fields = array()) + { + $stmt = $this->prepare($sql); + foreach ($fields as $field => $datum) { + list($column, $type) = explode(":", $field); + $this->bindParam($stmt, ":".$column, $datum, $type); + } + + if ($this->exec($stmt)) { + oci_fetch_all($stmt, $return_array, 0, -1, OCI_FETCHSTATEMENT_BY_ROW); + $this->free($stmt); + return $return_array; + } else { + $this->lastErrorFields = $fields; + $this->free($stmt); + return false; + } + } + + /** + * Delete row(s) from a table. + * + * @param string $table Table to update. + * @param array $fields Fields to use to match rows to delete. + * + * @return bool + */ + public function simpleDelete($table, $fields = array()) + { + $types = array(); + $data = array(); + $clauses = array(); + + // Split all the fields up into arrays + foreach ($fields as $field => $datum) { + list($column, $type) = explode(":", $field); + $types[$column] = $type; + $data[$column] = $datum; + $clauses[] = "$column = :$column"; + } + + // Prepare the SQL for child table - turn the columns in placeholders for + // the bind + $sql = "DELETE FROM $table WHERE ".join(" AND ", $clauses); + $delete = $this->prepare($sql); + + // Bind Variables + foreach (array_keys($data) as $column) { + $this->bindParam($delete, ":".$column, $data[$column], $types[$column]); + } + + // Execute + if ($this->exec($delete)) { + $this->commit(); + $this->free($delete); + return true; + } else { + $this->lastErrorFields = $fields; + $this->free($delete); + return false; + } + } + + /** + * Insert a row into a table. + * + * @param string $table Table to append to. + * @param array $fields Data to write to table. + * + * @return bool + */ + public function simpleInsert($table, $fields = array()) + { + $types = array(); + $data = array(); + $columns = array(); + $values = array(); + + // Split all the fields up into arrays + foreach ($fields as $field => $datum) { + $tmp = explode(":", $field); + $column = array_shift($tmp); + + // For binding + $types[$column] = array_shift($tmp); + $data[$column] = $datum; + + // For building the sql + $columns[] = $column; + // Dates are special + if (count($tmp) > 0 && !is_null($datum)) { + $values[] = "TO_DATE(:$column, '".join(":", $tmp)."')"; + } else { + $values[] = ":$column"; + } + } + + $sql = "INSERT INTO $table (".join(", ", $columns).") VALUES (". + join(", ", $values).")"; + $insert = $this->prepare($sql); + + // Bind Variables + foreach (array_keys($data) as $column) { + $this->bindParam($insert, ":".$column, $data[$column], $types[$column]); + } + + // Execute + if ($this->exec($insert)) { + $this->commit(); + $this->free($insert); + return true; + } else { + $this->lastErrorFields = $fields; + $this->free($insert); + return false; + } + } + + /** + * Execute a simple SQL statement. + * + * @param string $sql SQL to execute + * @param array $fields Bind parameters (optional) + * + * @return bool + */ + public function simpleSql($sql, $fields = array()) + { + $stmt = $this->prepare($sql); + foreach ($fields as $field => $datum) { + list($column, $type) = explode(":", $field); + $this->bindParam($stmt, ":".$column, $datum, $type); + } + if ($this->exec($stmt)) { + $this->commit(); + $this->free($stmt); + return true; + } else { + $this->lastErrorFields = $fields; + $this->free($stmt); + return false; + } + } + + /** + * Clear out internal error tracking details. + * + * @return void + * @access private + */ + protected function clearError() + { + $this->lastError = null; + $this->lastErrorType = null; + $this->lastErrorFields = null; + $this->lastSql = null; + } + + /** + * Store information about an error. + * + * @param string $type Type of error + * @param string $error Detailed error message + * @param string $sql SQL statement that caused error + * + * @return void + * @access private + */ + protected function handleError($type, $error, $sql = '') + { + // All we are doing at the moment is storing it + $this->lastError = $error; + $this->lastErrorType = $type; + $this->lastSql = $sql; + } + + /** + * Error Retrieval -- last error message. + * + * @return string + */ + public function getLastError() + { + return $this->lastError; + } + + /** + * Error Retrieval -- last error type. + * + * @return string + */ + public function getLastErrorType() + { + return $this->lastErrorType; + } + + /** + * Error Retrieval -- SQL that triggered last error. + * + * @return string + */ + public function getLastSql() + { + return $this->lastSql; + } + + /** + * Error Retrieval -- full details formatted as HTML. + * + * @return string + */ + public function getHtmlError() + { + if ($this->lastError == null) { + return "No error found!"; + } + + // Generic stuff + $output = "<b>ORACLE ERROR</b><br/>\n"; + $output .= "Oracle '".$this->lastErrorType."' Error<br />\n"; + $output .= "=============<br />\n"; + foreach ($this->lastError as $key => $value) { + $output .= "($key) => $value<br />\n"; + } + + // Anything special for this error type? + switch ($this->lastErrorType) { + case 'parsing': + $output .= "=============<br />\n"; + $output .= "Offset into SQL:<br />\n"; + $output .= + substr($this->lastError['sqltext'], $this->lastError['offset']). + "\n"; + break; + case 'executing': + $output .= "=============<br />\n"; + $output .= "Offset into SQL:<br />\n"; + $output .= + substr($this->lastError['sqltext'], $this->lastError['offset']). + "<br />\n"; + if (count($this->lastErrorFields) > 0) { + $output .= "=============<br />\n"; + $output .= "Bind Variables:<br />\n"; + foreach ($this->lastErrorFields as $k => $l) { + if (is_array($l)) { + $output .= "$k => (".join(", ", $l).")<br />\n"; + } else { + $output .= "$k => $l<br />\n"; + } + } + } + break; + } + + $this->clearError(); + return $output; + } +} -- GitLab