<?php

/**
 * SOAP Service class to manage the books table
 *
 * @author John Coggeshall <john@zend.com>
 * 
 * @throws SoapFault
 */
class BookManager {
	
	private $objDB;

	const DB_USERNAME="demo";
	const DB_PASSWORD="password";
	const DB_DATABASE="myoracle";
	
	/**
	 * Object Constructor: Establishes DB connection
	 *
	 */
	function __construct() {
		
		$this->objDB = oci_connect(self::DB_USERNAME,
		                           self::DB_PASSWORD,
		                           self::DB_DATABASE);
       
		if($this->objDB === false) {
			throw new SoapFault(-1, "Failed to connect to database backend (reason: " . 
                                         oci_error() . ")");
		}
	}

	/**
	 * Private method to return the DB connection and make sure it exists
	 *
	 * @return unknown
	 */
	private function getDB() {
		if(!$this->objDB) {
			throw new SoapFault(-1, "No valid database connection");
		}
		
		return $this->objDB;
	}
	
	/**
	 * Add a new book to the database
	 *
	 * @param string $isbn The ISBN serial number for the book (32 char max)
	 * @param string $author The name of the primary author (50 char max)
	 * @param string $title The title of the book (50 char max)
	 * @param float $price The price of the book in USD
	 * 
	 * @return mixed SOAP Fault on error, true on success
	 */
	public function addBook($isbn, $author, $title, $price) {

		$query = "INSERT INTO books (isbn, author, title, price)
		               VALUES (:isbn, :author, :title, :price)";
		
		$stmt = oci_parse($this->getDB(), $query);
		
		if(!$stmt) {
			throw new SoapFault(-1, "Failed to prepare query (reason: "  . 
                                         oci_error($stmt) . ")");
		}
		
		// The numbers 32, 50, 50 are the max column lengths
		oci_bind_by_name($stmt, "isbn", $isbn, 32);
		oci_bind_by_name($stmt, "author", $author, 50);
		oci_bind_by_name($stmt, "title", $title, 50);
		oci_bind_by_name($stmt, "price", $price);
		
		if(!oci_execute($stmt)) {
			oci_rollback($this->getDB());
			throw new SoapFault(-1, "Failed to execute query (reason: " . 
                                         oci_error($stmt) . ")");
		}
		
		oci_commit($this->getDB());
		
		return true;
	}
	
	/**
	 * Delete a book from the database by ISBN
	 *
	 * @param string $isbn The ISBN serial number of the book to delete
	 * 
	 * @return mixed SOAP Fault on error, true on success
	 */
	public function delBook($isbn) {
		
		$query = "DELETE FROM books
		                WHERE isbn = :isbn";
		
		$stmt = oci_parse($this->getDB(), $query);
		
		if(!$stmt) {
			throw new SoapFault(-1, "Failed to prepare query (reason: " . 
                                          oci_error($stmt) . ")");
		}
		
		oci_bind_by_name($stmt, "isbn", $isbn, 32);

		if(!oci_execute($stmt)) {
			oci_rollback($this->getDB());
			throw new SoapFault(-1, "Failed to execute query (reason: " .  
                                          oci_error($stmt) . ")");
		}
		
		oci_commit($this->getDB());
		
		return true;
	}
	
	/**
	 * Return a list of books with a specific substring in their title
	 *
	 * @param string $name The name of the author
	 * 
	 * @return mixed SOAP Fault on error, an array of ISBN numbers on success
	 */
	public function findBookISBNByTitle($title) {
		
		$query = "SELECT isbn
		            FROM books
		           WHERE title LIKE :titlefragment";

		$stmt = oci_parse($this->getDB(), $query);
		
		if(!$stmt) {
			throw new SoapFault(-1, "Failed to prepare query (reason: " . 
                                         oci_error($stmt) . ")");
		}
		
		$bindVar = "%$title%";
		
		oci_bind_by_name($stmt, ":titlefragment", $bindVar, 50);
		
		if(!oci_execute($stmt)) {
			throw new SoapFault(-1, "Failed to execute query (reason: " .  
                                         oci_error($stmt) . ")");
		}		
		
		$rows = array();
		
		while($row = oci_fetch_array($stmt, OCI_ASSOC)) {
			$rows[] = $row['ISBN'];
		}
		
		return $rows;
	}
	
	/**
	 * Return a list of books written by a specific author
	 *
	 * @param mixed $author SOAP Fault on error, on array of ISBN numbers on success
	 */
	public function findBookISBNByAuthor($author) {

		$query = "SELECT isbn
		            FROM books
		           WHERE author = :author";

		$stmt = oci_parse($this->getDB(), $query);
		
		if(!$stmt) {
			throw new SoapFault(-1, "Failed to prepare query (reason: " . 
                                         oci_error($stmt) . ")");
		}
		
		oci_bind_by_name($stmt, ":author", $author, 50);
		
		if(!oci_execute($stmt)) {
			throw new SoapFault(-1, "Failed to execute query (reason: " . 
                                          oci_error($stmt) . ")");
		}		
		
		$rows = array();
		
		while($row = oci_fetch_array($stmt, OCI_ASSOC)) {
			$rows[] = $row['ISBN'];
		}
		
		return $rows;		
	}
	
	/**
	 * Return a list of all ISBN numbers in the database
	 *
	 * @return array An array of ISBN numbers in the database
	 */
	public function listAllBooks() {
		
		$query = "SELECT isbn FROM books";

		$stmt = oci_parse($this->getDB(), $query);
		
		if(!$stmt) {
			throw new SoapFault(-1, "Failed to prepare query (reason: " . 
                                         oci_error($stmt) . ")");
		}
		
		if(!oci_execute($stmt)) {
			throw new SoapFault(-1, "Failed to execute query (reason: " . 
                                         oci_error($stmt) . ")");
		}		
		
		$rows = array();
		
		while($row = oci_fetch_array($stmt, OCI_ASSOC)) {
			$rows[] = $row['ISBN'];
		}
		
		return $rows;
	}
	
	/**
	 * Return the details of a specific book by ISBN
	 *
	 * @param string $isbn The ISBN of the book to retrieve the details on
	 * 
	 * @return mixed SOAP Fault on error, an array of key/value pairs for the ISBN on  
	 *               success
	 */
	public function getBookByISBN($isbn) {
		
		$query = "SELECT *
		            FROM books
		           WHERE isbn = :isbn";
		
		$stmt = oci_parse($this->getDB(), $query);
		
		if(!$stmt) {
			throw new SoapFault(-1, "Failed to prepare query (reason: " . 
                                          oci_error($stmt) . ")");
		}
		
		oci_bind_by_name($stmt, ":isbn", $isbn, 32);
		
		if(!oci_execute($stmt)) {
			throw new SoapFault(-1, "Failed to execute query (reason: " . 
                                         oci_error($stmt) . ")");
		}		
		
		$row = oci_fetch_array($stmt, OCI_ASSOC);		
		return $row;		
	}
}

?>

<?php

require_once 'BookManager.class.php';

$server = new SoapServer("bookman.wsdl");
$server->setClass("BookManager");
$server->handle();

?>