Created
July 23, 2017 17:12
-
-
Save lars3003/31bddab78139414dd11414af52f4002d to your computer and use it in GitHub Desktop.
Simple database wrapper for PDO and MySQL.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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