Add analytics
[bus.git] / busui / owa / includes / Log-1.12.2 / Log / mdb2.php
blob:a/busui/owa/includes/Log-1.12.2/Log/mdb2.php -> blob:b/busui/owa/includes/Log-1.12.2/Log/mdb2.php
  <?php
  /**
  * $Header$
  *
  * @version $Revision: 204814 $
  * @package Log
  */
   
  /** PEAR's MDB2 package */
  require_once 'MDB2.php';
  MDB2::loadFile('Date');
   
  /**
  * The Log_mdb2 class is a concrete implementation of the Log:: abstract class
  * which sends messages to an SQL server. Each entry occupies a separate row
  * in the database.
  *
  * This implementation uses PEAR's MDB2 database abstraction layer.
  *
  * CREATE TABLE log_table (
  * id INT NOT NULL,
  * logtime TIMESTAMP NOT NULL,
  * ident CHAR(16) NOT NULL,
  * priority INT NOT NULL,
  * message VARCHAR(200),
  * PRIMARY KEY (id)
  * );
  *
  * @author Lukas Smith <smith@backendmedia.com>
  * @author Jon Parise <jon@php.net>
  * @since Log 1.9.0
  * @package Log
  */
  class Log_mdb2 extends Log
  {
  /**
  * Variable containing the DSN information.
  * @var mixed
  * @access private
  */
  var $_dsn = '';
   
  /**
  * Array containing our set of DB configuration options.
  * @var array
  * @access private
  */
  var $_options = array('persistent' => true);
   
  /**
  * Object holding the database handle.
  * @var object
  * @access private
  */
  var $_db = null;
   
  /**
  * Resource holding the prepared statement handle.
  * @var resource
  * @access private
  */
  var $_statement = null;
   
  /**
  * Flag indicating that we're using an existing database connection.
  * @var boolean
  * @access private
  */
  var $_existingConnection = false;
   
  /**
  * String holding the database table to use.
  * @var string
  * @access private
  */
  var $_table = 'log_table';
   
  /**
  * String holding the name of the ID sequence.
  * @var string
  * @access private
  */
  var $_sequence = 'log_id';
   
  /**
  * Maximum length of the $ident string. This corresponds to the size of
  * the 'ident' column in the SQL table.
  * @var integer
  * @access private
  */
  var $_identLimit = 16;
   
  /**
  * Set of field types used in the database table.
  * @var array
  * @access private
  */
  var $_types = array(
  'id' => 'integer',
  'logtime' => 'timestamp',
  'ident' => 'text',
  'priority' => 'text',
  'message' => 'clob'
  );
   
  /**
  * Constructs a new sql logging object.
  *
  * @param string $name The target SQL table.
  * @param string $ident The identification field.
  * @param array $conf The connection configuration array.
  * @param int $level Log messages up to and including this level.
  * @access public
  */
  function Log_mdb2($name, $ident = '', $conf = array(),
  $level = PEAR_LOG_DEBUG)
  {
  $this->_id = md5(microtime());
  $this->_table = $name;
  $this->_mask = Log::UPTO($level);
   
  /* If an options array was provided, use it. */
  if (isset($conf['options']) && is_array($conf['options'])) {
  $this->_options = $conf['options'];
  }
   
  /* If a specific sequence name was provided, use it. */
  if (!empty($conf['sequence'])) {
  $this->_sequence = $conf['sequence'];
  }
   
  /* If a specific sequence name was provided, use it. */
  if (isset($conf['identLimit'])) {
  $this->_identLimit = $conf['identLimit'];
  }
   
  /* Now that the ident limit is confirmed, set the ident string. */
  $this->setIdent($ident);
   
  /* If an existing database connection was provided, use it. */
  if (isset($conf['db'])) {
  $this->_db = &$conf['db'];
  $this->_existingConnection = true;
  $this->_opened = true;
  } elseif (isset($conf['singleton'])) {
  $this->_db = &MDB2::singleton($conf['singleton'], $this->_options);
  $this->_existingConnection = true;
  $this->_opened = true;
  } else {
  $this->_dsn = $conf['dsn'];
  }
  }
   
  /**
  * Opens a connection to the database, if it has not already
  * been opened. This is implicitly called by log(), if necessary.
  *
  * @return boolean True on success, false on failure.
  * @access public
  */
  function open()
  {
  if (!$this->_opened) {
  /* Use the DSN and options to create a database connection. */
  $this->_db = &MDB2::connect($this->_dsn, $this->_options);
  if (PEAR::isError($this->_db)) {
  return false;
  }
   
  /* Create a prepared statement for repeated use in log(). */
  if (!$this->_prepareStatement()) {
  return false;
  }
   
  /* We now consider out connection open. */
  $this->_opened = true;
  }
   
  return $this->_opened;
  }
   
  /**
  * Closes the connection to the database if it is still open and we were
  * the ones that opened it. It is the caller's responsible to close an
  * existing connection that was passed to us via $conf['db'].
  *
  * @return boolean True on success, false on failure.
  * @access public
  */
  function close()
  {
  /* If we have a statement object, free it. */
  if (is_object($this->_statement)) {
  $this->_statement->free();
  $this->_statement = null;
  }
   
  /* If we opened the database connection, disconnect it. */
  if ($this->_opened && !$this->_existingConnection) {
  $this->_opened = false;
  return $this->_db->disconnect();
  }
   
  return ($this->_opened === false);
  }
   
  /**
  * Sets this Log instance's identification string. Note that this
  * SQL-specific implementation will limit the length of the $ident string
  * to sixteen (16) characters.
  *
  * @param string $ident The new identification string.
  *
  * @access public
  * @since Log 1.8.5
  */
  function setIdent($ident)
  {
  $this->_ident = substr($ident, 0, $this->_identLimit);
  }
   
  /**
  * Inserts $message to the currently open database. Calls open(),
  * if necessary. Also passes the message along to any Log_observer
  * instances that are observing this Log.
  *
  * @param mixed $message String or object containing the message to log.
  * @param string $priority The priority of the message. Valid
  * values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
  * PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
  * PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
  * @return boolean True on success or false on failure.
  * @access public
  */
  function log($message, $priority = null)
  {
  /* If a priority hasn't been specified, use the default value. */
  if ($priority === null) {
  $priority = $this->_priority;
  }
   
  /* Abort early if the priority is above the maximum logging level. */
  if (!$this->_isMasked($priority)) {
  return false;
  }
   
  /* If the connection isn't open and can't be opened, return failure. */
  if (!$this->_opened && !$this->open()) {
  return false;
  }
   
  /* If we don't already have a statement object, create one. */
  if (!is_object($this->_statement) && !$this->_prepareStatement()) {
  return false;
  }
   
  /* Extract the string representation of the message. */
  $message = $this->_extractMessage($message);
   
  /* Build our set of values for this log entry. */
  $values = array(
  'id' => $this->_db->nextId($this->_sequence),
  'logtime' => MDB2_Date::mdbNow(),
  'ident' => $this->_ident,
  'priority' => $priority,
  'message' => $message
  );
   
  /* Execute the SQL query for this log entry insertion. */
  $this->_db->expectError(MDB2_ERROR_NOSUCHTABLE);
  $result = &$this->_statement->execute($values);
  $this->_db->popExpect();
   
  /* Attempt to handle any errors. */
  if (PEAR::isError($result)) {
  /* We can only handle MDB2_ERROR_NOSUCHTABLE errors. */
  if ($result->getCode() != MDB2_ERROR_NOSUCHTABLE) {
  return false;
  }
   
  /* Attempt to create the target table. */
  if (!$this->_createTable()) {
  return false;
  }
   
  /* Recreate our prepared statement resource. */
  $this->_statement->free();
  if (!$this->_prepareStatement()) {
  return false;
  }
   
  /* Attempt to re-execute the insertion query. */
  $result = $this->_statement->execute($values);
  if (PEAR::isError($result)) {
  return false;
  }
  }
   
  $this->_announce(array('priority' => $priority, 'message' => $message));
   
  return true;
  }
   
  /**
  * Create the log table in the database.
  *
  * @return boolean True on success or false on failure.
  * @access private
  */
  function _createTable()
  {
  $this->_db->loadModule('Manager', null, true);
  $result = $this->_db->manager->createTable(
  $this->_table,
  array(
  'id' => array('type' => $this->_types['id']),
  'logtime' => array('type' => $this->_types['logtime']),
  'ident' => array('type' => $this->_types['ident']),
  'priority' => array('type' => $this->_types['priority']),
  'message' => array('type' => $this->_types['message'])
  )
  );
  if (PEAR::isError($result)) {
  return false;
  }
   
  $result = $this->_db->manager->createIndex(
  $this->_table,
  'unique_id',
  array('fields' => array('id' => true), 'unique' => true)
  );
  if (PEAR::isError($result)) {
  return false;
  }
   
  return true;
  }
   
  /**
  * Prepare the SQL insertion statement.
  *
  * @return boolean True if the statement was successfully created.
  *
  * @access private
  * @since Log 1.9.0
  */
  function _prepareStatement()
  {
  $this->_statement = &$this->_db->prepare(
  'INSERT INTO ' . $this->_table .
  ' (id, logtime, ident, priority, message)' .
  ' VALUES(:id, :logtime, :ident, :priority, :message)',
  $this->_types, MDB2_PREPARE_MANIP);
   
  /* Return success if we didn't generate an error. */
  return (PEAR::isError($this->_statement) === false);
  }
  }