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