* Updated the Database class to work like a Singleton with a getInstance() method. * The Database class does not have a private constructor so it can still be instantiated in case someone needs to do so. * Replaced Logger class with Log class. * Updated Module to have an instance of the Database object as well as the Model class. * In my perfect vision for usage, the Module classes should never talk directly to the database, but do so via Models, but I know that's asking a lot, so I'm leaving in some options for folks. * Updated documentation.
321 lines
7.2 KiB
PHP
321 lines
7.2 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Database Class File for PICKLES
|
|
*
|
|
* PHP version 5
|
|
*
|
|
* Licensed under the GNU General Public License Version 3
|
|
* Redistribution of these files must retain the above copyright notice.
|
|
*
|
|
* @package PICKLES
|
|
* @author Josh Sherman <josh@phpwithpickles.org>
|
|
* @copyright Copyright 2007-2010, Gravity Boulevard, LLC
|
|
* @license http://www.gnu.org/licenses/gpl.html GPL v3
|
|
* @link http://phpwithpickles.org
|
|
*/
|
|
|
|
/**
|
|
* Database Abstraction Layer for MySQL
|
|
*
|
|
* All database usage inside PICKLES-based sites should be done
|
|
* via the database object that is a part of every model ($this->db).
|
|
* Because the database object can execute raw SQL, there should be
|
|
* no limitations.
|
|
*/
|
|
class Database extends Object
|
|
{
|
|
/**
|
|
* Instance of the Database object
|
|
*
|
|
* Within the PICKLES system, the database instance is shared, but the
|
|
* Database constructor is not private, just in case someone wants to
|
|
* create new Database objects.
|
|
*
|
|
* @static
|
|
* @access private
|
|
* @var object
|
|
*/
|
|
private static $instance;
|
|
|
|
/**
|
|
* Hostname for the MySQL Server
|
|
*
|
|
* @access private
|
|
* @var string
|
|
*/
|
|
private $hostname = 'localhost';
|
|
|
|
/**
|
|
* Username for the MySQL Server
|
|
*
|
|
* @access private
|
|
* @var string
|
|
*/
|
|
private $username = null;
|
|
|
|
/**
|
|
* Password for the MySQL Server
|
|
*
|
|
* @access private
|
|
* @var string
|
|
*/
|
|
private $password = null;
|
|
|
|
/**
|
|
* Database name for the MySQL Server
|
|
*
|
|
* @access private
|
|
* @var string
|
|
*/
|
|
private $database = null;
|
|
|
|
/**
|
|
* Connection resource to MySQL
|
|
*
|
|
* @access private
|
|
* @var object
|
|
*/
|
|
private $connection = null;
|
|
|
|
/**
|
|
* Results object for the executed statement
|
|
*
|
|
* @access private
|
|
* @var object
|
|
*/
|
|
private $results = null;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* Sets up our connection variables
|
|
*
|
|
* @param string $hostname optional hostname to connect to
|
|
* @param string $username optional username to use
|
|
* @param string $password optional password to use
|
|
* @param string $database optional database to connect to
|
|
*/
|
|
public function __construct($hostname = null, $username = null, $password = null, $database = null)
|
|
{
|
|
parent::__construct();
|
|
|
|
$config = $this->config->database;
|
|
|
|
// Loads the credentials and database, arguments first
|
|
if (isset($username, $password, $database))
|
|
{
|
|
$this->username = $username;
|
|
$this->password = $password;
|
|
$this->database = $database;
|
|
}
|
|
elseif (isset($config['username'], $config['password'], $config['database']))
|
|
{
|
|
$this->username = $config['username'];
|
|
$this->password = $config['password'];
|
|
$this->database = $config['database'];
|
|
}
|
|
|
|
// Loads or defaults the host name
|
|
if (isset($hostname))
|
|
{
|
|
$this->hostname = $hostname;
|
|
}
|
|
elseif (isset($config['hostname']))
|
|
{
|
|
$this->hostname = $config['hostname'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get instance of the object
|
|
*
|
|
* Instantiates a new object if one isn't already available, then
|
|
* returns the instance.
|
|
*
|
|
* @static
|
|
* @return object self::$instance instance of the Database
|
|
*/
|
|
public static function getInstance()
|
|
{
|
|
if (!isset(self::$instance) || empty(self::$instance))
|
|
{
|
|
self::$instance = new Database();
|
|
}
|
|
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Opens database connection
|
|
*
|
|
* Establishes a connection to the MySQL database based on the
|
|
* configuration options that are available in the Config object.
|
|
*
|
|
* @return boolean true on success, throws an exception overwise
|
|
*/
|
|
public function open()
|
|
{
|
|
if ($this->connection === null)
|
|
{
|
|
if (isset($this->username, $this->password, $this->database))
|
|
{
|
|
// Creates a new PDO database object (persistent)
|
|
try
|
|
{
|
|
$pdo_attributes = array(
|
|
PDO::ATTR_PERSISTENT => true,
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::NULL_EMPTY_STRING => true
|
|
);
|
|
|
|
$this->connection = new PDO('mysql:host=' . $this->hostname . ';dbname=' . $this->database, $this->username, $this->password, $pdo_attributes);
|
|
}
|
|
catch (PDOException $e)
|
|
{
|
|
throw new Exception($e);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception('There was an error loading the database configuration');
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Closes database connection
|
|
*
|
|
* Sets the connection to null regardless of state.
|
|
*
|
|
* @return boolean always true
|
|
*/
|
|
public function close()
|
|
{
|
|
$this->connection = null;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Executes an SQL Statement
|
|
*
|
|
* Executes a standard or prepared query based on passed parameters.
|
|
* All queries are logged to a file as well as timed and logged in the
|
|
* execution time is over 1 second.
|
|
*
|
|
* @param string $sql statement to execute
|
|
* @param array $input_parameters optional key/values to be bound
|
|
* @return integer ID of the last inserted row or sequence number
|
|
*/
|
|
public function execute($sql, $input_parameters = null)
|
|
{
|
|
$this->open();
|
|
|
|
Log::query($sql);
|
|
|
|
// Checks if the query is blank
|
|
if (trim($sql) != '')
|
|
{
|
|
try
|
|
{
|
|
$start_time = microtime(true);
|
|
|
|
// Executes a standard query
|
|
if ($input_parameters === null)
|
|
{
|
|
$this->results = $this->connection->query($sql);
|
|
}
|
|
// Executes a prepared statement
|
|
else
|
|
{
|
|
$this->results = $this->connection->prepare($sql);
|
|
$this->results->execute($input_parameters);
|
|
}
|
|
|
|
$end_time = microtime(true);
|
|
$duration = $end_time - $start_time;
|
|
|
|
if ($duration >= 1)
|
|
{
|
|
Log::slowQuery("This query took {$duration} seconds to execute:\n\n{$sql}\n\n" . ($input_parameters != null ? print_r($input_parameters, true) : ''));
|
|
}
|
|
}
|
|
catch (PDOException $e)
|
|
{
|
|
throw new Exception($e);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception('No query to execute');
|
|
}
|
|
|
|
return $this->connection->lastInsertId();
|
|
}
|
|
|
|
/**
|
|
* Fetch a single row from the database
|
|
*
|
|
* @param string $sql statement to be executed
|
|
* @param array $input_parameters optional key/values to be bound
|
|
* @param string $return_type optional type of return set
|
|
* @return mixed based on return type
|
|
*/
|
|
public function fetch($sql = null, $input_parameters = null, $return_type = null)
|
|
{
|
|
$this->open();
|
|
|
|
if ($sql !== null)
|
|
{
|
|
$this->execute($sql, $input_parameters);
|
|
}
|
|
|
|
// Pulls the results based on the type
|
|
$results = false;
|
|
switch ($return_type)
|
|
{
|
|
case 'column':
|
|
$results = $this->results->fetchColumn(0);
|
|
break;
|
|
case 'all':
|
|
$results = $this->results->fetchAll(PDO::FETCH_ASSOC);
|
|
break;
|
|
default:
|
|
$results = $this->results->fetch(PDO::FETCH_ASSOC);
|
|
break;
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Fetch a single column from the database
|
|
*
|
|
* This method assumes you want the first column in your select.
|
|
* If you need 2 or more columns you should simply use fetch()
|
|
*
|
|
* @param string $sql statement to be executed
|
|
* @param array $input_parameters optional key/values to be bound
|
|
* @return string
|
|
*/
|
|
public function fetchColumn($sql = null, $input_parameters = null)
|
|
{
|
|
return $this->fetch($sql, $input_parameters, 'column');
|
|
}
|
|
|
|
/**
|
|
* Fetches all rows as an array
|
|
*
|
|
* @param string $sql statement to be executed
|
|
* @param array $input_parameters optional key/values to be bound
|
|
* @return array
|
|
*/
|
|
public function fetchAll($sql = null, $input_parameters = null)
|
|
{
|
|
return $this->fetch($sql, $input_parameters, 'all');
|
|
}
|
|
}
|
|
|
|
?>
|