Skip to content

Instantly share code, notes, and snippets.

@lars3003
Created July 23, 2017 17:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lars3003/31bddab78139414dd11414af52f4002d to your computer and use it in GitHub Desktop.
Save lars3003/31bddab78139414dd11414af52f4002d to your computer and use it in GitHub Desktop.
Simple database wrapper for PDO and MySQL.
<?php
/**
* A simple Wrapper designed to ease using PDO and MySQL.
*
* @disclaimer This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. Use at your own risk.
*
* @author Lars Goossens (https://github.com/lars3003)
* @license WTFPL http://sam.zoy.org/wtfpl/COPYING
*/
namespace Lars3003\Gists\PHP;
use Exception, PDO, PDOException, PDOStatement;
/**
* Class PDODatabase
*
* Example usage:
* $database = new PDODatabase('localhost','mydb','john_doe','supersecret');
* $users = $database->selectOne('last_name, first_name', 'customers', 'last_name = :lastName', Array(':lastName' => 'Doe');
* foreach ($users as $user){
* echo($user['first name'] . ' ' . $user['last_name']);
* }
*/
class PDODatabase
{
/**
* @var PDO
*/
protected $dbh;
/**
* @var string
*/
protected $error;
/**
* @var PDOStatement
*/
protected $statement;
/**
* The desired fetchMode, defaults to PDO::FETCH_ASSOC
*
* @var int
*/
protected $fetchMode = PDO::FETCH_ASSOC;
/**
* PDODatabase constructor.
* @param string $host the hostname, e.g. 'localhost'
* @param string $dbname the name of the database
* @param string $user name of the mysql user
* @param string $pass password of the mysql user
*/
public function __construct($host, $dbname, $user, $pass)
{
try {
# MySQL with PDO_MYSQL
$this->dbh = new PDO("mysql:host=" . $host . ";dbname=" . $dbname, $user, $pass);
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->dbh->setAttribute(PDO::ATTR_PERSISTENT, true);
$this->dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->dbh->exec("set names utf8");
} catch (PDOException $e) {
$this->error = $e->getMessage();
}
}
/**
* checks the parameters for data type and binds them to the query
*
* @param string $query the MySQL query
* @param array $bindings an array of the bindings as key/value pairs (key=PDO variable, value= value)
* @return bool whether the binding was successful
*/
private function prepareAndBind($query, $bindings)
{
$this->prepareStatement($query);
if ($this->statement !== false) {
$success = false;
if (!empty($bindings)) {
foreach ($bindings as $param => $value) {
switch (true) {
case is_int($value):
$type = PDO::PARAM_INT;
break;
case is_bool($value):
//can't use PDO::PARAM_BOOL due to a bug!
$type = PDO::PARAM_INT;
break;
case is_null($value):
$type = PDO::PARAM_NULL;
break;
case is_string($value):
$type = PDO::PARAM_STR;
break;
default:
$type = false;
}
if ($type !== false) {
if ($this->statement->bindValue($param, $value, $type) === false) {
$this->error = $this->throwStatementError();
return false;
} else {
$success = true;
}
}
}
} else {
$success = true;
}
return $success;
} else {
$this->error = $this->throwPDOError();
return false;
}
}
private function prepareStatement($query)
{
$this->statement = $this->dbh->prepare($query);
}
/**
* @param int $fetchMode the desired fetch mode, e.g. PDO::FETCH_ASSOC
*/
public function setFetchMode(int $fetchMode)
{
$this->fetchMode = $fetchMode;
}
/**
* returns the last error that occurred with PDO
*
* @return array
*/
private function throwPDOError()
{
return $this->dbh->errorInfo();
}
/**
* returns the last error occurring with a statement
*
* @return array
*/
private function throwStatementError()
{
return $this->statement->errorInfo();
}
/**
* outputs the error
*
* @return string
*/
public function getError(): string
{
return $this->error;
}
/**
* Check if a table exists in the current database.
*
* @param string $table Table to search for.
* @return bool TRUE if table exists, FALSE if no table found.
*/
function tableExists($table)
{
// Try a select statement against the table
// Run it in try/catch in case PDO is in ERRMODE_EXCEPTION.
try {
$result = $this->dbh->query("SELECT 1 FROM $table LIMIT 1");
} catch (Exception $e) {
// We got an exception == table not found
$this->error = $this->throwStatementError();
return FALSE;
}
// Result is either boolean FALSE (no table found) or TRUE (table found)
if ($result) {
return TRUE;
} else {
return FALSE;
}
}
/**
* function selectOne
*
* selects one row from the database
*
* @param string $selectedFields the fields to be selected, as used in a MySQL query, e.g. 'first_name, last_name, zip, city'
* @param string $fromTable the table to be selected from, e.g. 'customers'
* @param string $whereArgs (optional) the arguments to match, e.g. 'user_id = :userId'
* @param array $bindings an array of the bindings as key/value pairs
* (e.g. array(":userId"=>1))
* @return array|object|bool an array or object depending on the fetch mode, OR (bool) FALSE, if an error occurred, OR NULL if the resultset is empty
*/
public function selectOne($selectedFields, $fromTable, $whereArgs = '', $bindings = array())
{
$query = 'SELECT ';
$query .= $selectedFields;
$query .= ' FROM ';
$query .= $fromTable;
if (!empty($whereArgs)) {
$query .= ' WHERE ';
$query .= $whereArgs;
}
$query .= ' LIMIT 1';
$this->dbh->beginTransaction(); //begin transaction
if ($this->prepareAndBind($query, $bindings) && $this->statement->execute()) {
$result = $this->statement->fetch($this->fetchMode);
if ($result === false) { //this should only happen if an empty resultset is returned
$result = null;
}
} else { //this happens if something serious occurred
$this->error = $this->throwStatementError();
$result = false;
}
$this->dbh->commit(); //end transaction
return $result;
}
/**
* function selectMany
*
* selects many rows from the database
*
* @param string $selectedFields the fields to be selected, as used in a MySQL query, e.g. 'first_name, last_name, zip, city'
* @param string $fromTable the table to be selected from, e.g. 'customers'
* @param string $whereArgs (optional) the arguments to match, e.g. 'user_id = :userId'
* @param array $bindings (optional) an array of the bindings as key/value pairs (key=PDO variable, value= value) (e.g. array(":userId"=>1))
* @param string $groupBy (optional) columns to group by, e.g. 'city'
* @param string $orderBy (optional) columns to order by, e.g. 'last_name DESC, first_name DESC'
* @param string $limit (optional)
* @return array|object|bool an array or object depending on the fetch mode, OR (bool) FALSE, if an error occurred, OR NULL if the resultset is empty
*/
public function selectMany($selectedFields, $fromTable, $whereArgs = '', $bindings = array(), $groupBy = '', $orderBy = '', $limit = '')
{
$query = 'SELECT ';
$query .= $selectedFields;
$query .= ' FROM ';
$query .= $fromTable;
if (!empty($whereArgs)) {
$query .= ' WHERE ';
$query .= $whereArgs;
}
if (!empty($groupBy)) {
$query .= ' GROUP BY ';
$query .= $groupBy;
}
if (!empty($orderBy)) {
$query .= ' ORDER BY ';
$query .= $orderBy;
}
if (!empty($limit)) {
$query .= ' LIMIT ';
$query .= $limit;
}
$this->dbh->beginTransaction(); //begin transaction
if ($this->prepareAndBind($query, $bindings) && $this->statement->execute()) {
$result = $this->statement->fetchAll($this->fetchMode);
} else {
$this->error = $this->throwStatementError();
$result = false;
}
$this->dbh->commit(); //end transaction
return $result;
}
/**
* function selectSingleValue
*
* returns a single value from one row. The difference to selectOne with one column is: here you get the value directly and not wrapped in an object/array
*
* @param string $selectedField the field to select, e.g. 'username'
* @param string $fromTable the table to select from, e.g. 'customers'
* @param string $whereArgs the where clause of the SQL statement, e.g. ':user_id = 1'
* @param array $bindings (optional) an array of the bindings as key/value pairs (e.g. array(":userId"=>1))
* @return mixed a single value
* (e.g. $user = 1 )
*/
public function selectSingleValue($selectedField, $fromTable, $whereArgs = '', $bindings = array())
{
$query = 'SELECT ';
$query .= $selectedField;
$query .= ' FROM ';
$query .= $fromTable;
if (!empty($whereArgs)) {
$query .= ' WHERE ';
$query .= $whereArgs;
}
$query .= ' LIMIT 1';
$this->dbh->beginTransaction(); //begin transaction
if ($this->prepareAndBind($query, $bindings) && $this->statement->execute()) {
$result = $this->statement->fetch(PDO::FETCH_ASSOC)[$selectedField];
if ($result === false) { //this should only happen if an empty resultset is returned
$result = null;
}
} else {
$result = false;
}
$this->dbh->commit(); //end transaction
return $result;
}
/**
* function insert
*
* @param string $intoTable the table to insert into, e.g. 'customers'
* @param string $fields the fields of the table to be inserted, e.g. 'first_name, last_name, zip, city'
* @param string $values the values to be inserted into the fields, e.g. ':firstName, :lastName, :zip, :city'
* @param string $doOnDuplicate (optional) what to be updated on duplicate key, e.g. 'first_name = :firstName, last_name = :lastName, zip = :zip, city = :city'
* @param array $bindings (optional) an array of the bindings as key/value pairs (e.g. array(':firstName'=>'John', ':lastName' => 'Doe'))
* @return int|bool if insert was successful: id of last inserted row, else FALSE
*/
public function insert($intoTable, $fields, $values, $doOnDuplicate = '', $bindings = array())
{
$query = 'INSERT INTO ' . $intoTable . '(' . $fields . ')' . ' VALUES (' . $values . ')';
if (!empty($updateFields)) {
$query .= ' ON DUPLICATE KEY UPDATE ';
$query .= $updateFields;
}
$this->dbh->beginTransaction(); //begin transaction
if ($this->prepareAndBind($query, $bindings) && $this->statement->execute()) {
$result = $this->dbh->lastInsertId();
} else {
$this->error = $this->throwStatementError();
$result = false;
}
$this->dbh->commit(); //end transaction
return $result;
}
/**
* function update
*
* @param string $table the table to update, e.g. 'customers'
* @param string $setValues the values to set, e.g. 'first_name = :firstName, last_name = :lastName'
* @param string $whereArgs the condition for the rows to update, e.g. 'id = :userId'
* @param array $bindings (optional) an array of the bindings as key/value pairs (key=MYSQL-variable-name, value:variable content)
* (e.g. array(':firstName' => 'John', ':lastName' => 'Doe', ':userId' => 1))
* @return int|bool number of rows affected or FALSE if unsuccessful
*/
public function update($table, $setValues, $whereArgs = '', $bindings = array())
{
$query = 'UPDATE ' . $table . ' SET ' . $setValues;
if (!empty($whereArgs)) {
$query .= ' WHERE ' . $whereArgs;
}
$this->dbh->beginTransaction(); //begin transaction
if ($this->prepareAndBind($query, $bindings) && $this->statement->execute()) {
$result = $this->statement->rowCount();
} else {
$this->error = $this->throwStatementError();
$result = false;
}
$this->dbh->commit(); //end transaction
return $result;
}
/**
* function delete
*
* deletes selected records from a table
*
* @param string $fromTable the table to delete from, e.g. 'customers'
* @param string $whereArgs (optional) the condition on what to delete, e.g. 'user_id = :userId'
* @param array $bindings (optional) an array of the bindings as key/value pairs (key=MYSQL-variable-name, value:variable content)
* (e.g. array(":id"=>1))
* @return int|bool number of rows affected or FALSE if unsuccessful
*/
public function delete($fromTable, $whereArgs = '', $bindings = array())
{
$query = 'DELETE FROM ' . $fromTable;
if (!empty($whereArgs)) {
$query .= ' WHERE ' . $whereArgs;
}
$this->dbh->beginTransaction(); //begin transaction
if ($this->prepareAndBind($query, $bindings) && $this->statement->execute()) {
$result = $this->statement->rowCount();
} else {
$this->error = $this->throwStatementError();
$result = false;
}
$this->dbh->commit(); //end transaction
return $result;
}
/**
* function truncate
*
* @param string $tableName name of the table to be truncated
*
* @return bool whether the truncate was successful or not
*/
public function truncate($tableName)
{
$query = "TRUNCATE table " . $tableName;
$this->dbh->beginTransaction(); //begin transaction
if ($this->prepareAndBind($query, "") && $this->statement->execute()) {
$result = true;
} else {
$this->error = $this->throwStatementError();
$result = false;
}
$this->dbh->commit(); //end transaction
return $result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment