Skip to content

Commit

Permalink
Merge pull request #17 from GrumpyCrouton/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
GrumpyCrouton authored Oct 19, 2022
2 parents fa396f7 + f7b740b commit ee7a10b
Showing 1 changed file with 151 additions and 93 deletions.
244 changes: 151 additions & 93 deletions grumpypdo.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,161 +9,219 @@ class GrumpyPdo extends \PDO
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
);
public function __construct($hostname, $username, $password, $database, $attributes = array() , $charset = "utf8")

private $verified_tables = [];

public function __construct($hostname, $username, $password, $database, $attributes = array(), $dsn_prefix = "mysql", $dsn_param_string = "")
{
parent::__construct(
"{$dsn_prefix}:host={$hostname};dbname={$database};{$dsn_param_string}",
$username,
$password,
array_replace($this->default_attributes, $attributes)
);
}

/**
* @var string - A parameterized query string using either anonymous placeholders or named placeholders.
* @var array - A key value pair of values to pass to the query. Should reflect the placeholders placed in the query, including position when using anonymous placeholders.
*/
public function run($query, $values = array())
{
$active_attrs = $this->default_attributes;
if (!empty($attributes))
if (!$values)
{
array_replace($active_attrs, $attributes);
return $this->query($query);
}
parent::__construct("mysql:host={$hostname};dbname={$database};charset={$charset}", $username, $password, $active_attrs);
if (is_array($values[0]))
{
return $this->multi($query, $values);
}
$stmt = $this->prepare($query);
$stmt->execute($values);
return $stmt;
}

/**
* @var string - A table name, which must already exist in your database.
* @var array - A key value pair of values to insert into the database on the specified table
*
* Query will be generated with named placeholders.
* It takes a table name and an array of data to insert into the table
*
* @param table The table to insert into
* @param inserts Array of key => value pairs
*
* @return The return value is the result of the query.
*/
public function insert($table, $inserts)
{
$is_multi_set = !empty($inserts[0]) && is_array($inserts[0]);
if(!$this->verify_table($table)) {
throw new Exception('The given table does not exist in the database');
}
$single_data_set = $is_multi_set ? $inserts[0] : $inserts;

$set_keys = array_keys($is_multi_set ? $inserts[0] : $inserts);
if(!$this->verify_columns($table, $set_keys)) {
throw new Exception('One or more of the supplied columns do not exist in the supplied table');
if(!$this->verifyTablesAndColumns($table, $set_keys = array_keys($single_data_set))) {
return false;
}

$query_keys = [];
$query_placeholders = [];
foreach($set_keys as $key) {
$query_placeholders[] = ":{$key}";
$query_keys[] = "`$key`";
if(!$is_multi_set) {
$inserts = array_values($inserts);
} else {
foreach($inserts as &$i) {
$i = array_values($i);
}
}

$query_keys = implode(', ', $query_keys);
$query_placeholders = implode(', ', $query_placeholders);
$query_keys = implode('`, `', $set_keys);
$query_placeholders = implode(', ', array_fill(0, count($set_keys), "?"));

return $this->run("INSERT INTO {$table} ({$query_keys}) VALUES ({$query_placeholders})", $inserts);
return $this->run("INSERT INTO `{$table}` (`{$query_keys}`) VALUES ({$query_placeholders})", $inserts);
}

/**
* @var string - A table name, which must already exist in your database.
* @var array - A key value pair of values to pass to the queries SET clause.
* @var array - A key value pair of values to pass to the queries WHERE clause. Each set will be separated by 'AND'.
* @var array - An array of key => value pairs used to generate the SET clause.
* @var array - An array of key => value pairs to generate the WHERE clause. Each set will be separated by ' AND '.
*/
public function update($table, $updates, $where)
{
if(!$this->verify_table($table)) {
throw new Exception('The given table does not exist in the database');
}

$columns = array_merge(array_keys($updates), array_keys($where));
if(!$this->verify_columns($table, $columns)) {
throw new Exception('One or more of the supplied columns do not exist in the supplied table');
if(!$this->verifyTablesAndColumns($table, $columns)) {
return false;
}

$query_params = array_merge(array_values($updates), array_values($where));
$set_clause_parts = [];
$where_clause_parts = [];

foreach(array_keys($updates) as $key) {
$set_clause_parts[] = "`{$key}`=?";
/* Creating a query string for the SET and WHERE clauses, and an array of parameters. */
$p = [];
$d = [['v' => $updates, 's' => ', '], ['v' => $where, 's' => ' AND ']];
foreach($d as &$s) {
foreach(array_keys($s['v']) as $k) {
$s['c'][] = "`{$k}`=?";
}
$s['c'] = implode($d['s'], $s['c']);
$p = array_merge($p, array_values($s['v']));
}
foreach(array_keys($where) as $key) {
$where_clause_parts[] = "`{$key}`=?";
}

$set_clause = implode(', ', $set_clause_parts);
$where_clause = implode(' AND ', $where_clause_parts);

return $this->run("UPDATE {$table} SET {$set_clause} WHERE {$where_clause}", $query_params);
return $this->run("UPDATE `{$table}` SET {$d[0]['c']} WHERE {$d[1]['c']}", $p);
}

/**
* @var string - A parameterized query string using either anonymous placeholders or named placeholders.
* @var array - A key value pair of values to pass to the query. Should reflect the placeholders placed in the query, including position when using anonymous placeholders.
* @return The first row of the result set.
* Read https://www.php.net/manual/en/pdostatement.fetch.php for more options
*/
public function run($query, $values = array())
public function row($query, $values = array(), $mode = null, $cursorOrientation = null, $cursorOffset = 0)
{
if (!$values)
{
return $this->query($query);
}
if (is_array($values[0]))
{
return $this->multi($query, $values);
}
$stmt = $this->prepare($query);
$stmt->execute($values);
return $stmt;
return $this->run($query, $values)->fetch($mode, $cursorOrientation, $cursorOffset);
}
/**
* Quick queries
* Allows you to run a query without chaining the return type manually. This allows for slightly shorter syntax.
*/

/**
* Fetch a singular row from the database in a flat array.
/**
* @return The $column column of the first row of the result set.
* Read https://www.php.net/manual/en/pdostatement.fetchcolumn.php for more options
*/
public function row($query, $values = array())
public function cell($query, $values = array(), $column = 0)
{
return $this->run($query, $values)->fetch();
return $this->run($query, $values)->fetchColumn($column);
}

/**
* Fetch a single cell from the database. Doesn't support multiple rows.
*/
public function cell($query, $values = array())
* @return An array of all the rows in the result set.
* Read https://www.php.net/manual/en/pdostatement.fetchall.php for more options
*/
public function all($query, $values = array(), $mode = null, $c = null, $args = null)
{
return $this->run($query, $values)->fetchColumn();
$qry = $this->run($query, $values);
switch($mode) {
case \PDO::FETCH_COLUMN:
return $qry->fetchAll($mode, $c);
case \PDO::FETCH_CLASS:
return $qry->fetchAll($mode, $c, $args);
case \PDO::FETCH_FUNC:
return $qry->fetchAll($mode, $c);
default:
return $qty->fetchAll($mode);
}
}

/**
* Fetch all of the results from the database into a multidimensional array.
*/
public function all($query, $values = array())
* @return An array of values from a single column in the result set.
*/
public function column($query, $values = array())
{
return $this->run($query, $values)->fetchAll();
return $this->all($query, $values, \PDO::FETCH_COLUMN);
}

/**
* Fetch a single column from the database. Similar to $this->cell, except can have multiple rows.
*/
public function column($query, $values = array())
* @return An array with the values grouped by the value of the first column in the result set.
* The values in each set a set of arrays similar to the all() method
*/
public function group($query, $values = array())
{
return $this->run($query, $values)->fetchAll(\PDO::FETCH_COLUMN);
return $this->all($query, $values, \PDO::FETCH_GROUP);
}

/**
* Private Methods
* Methods called internally, and should not be used directly.
/**
* @return An array of the result of the query as a key-value pair. The first column is the index,
* the second column is the value. Does not support duplicate indexes
*/
public function keypair($query, $values = array())
{
return $this->all($query, $values, \PDO::FETCH_KEY_PAIR);
}

/**
* Used to verify if a table exists in the currently selected database or not.
/**
* @return An array of the result of the query as key-value pairs. The first column is the index,
* the value is an array of all of the values from the second column.
*/
private function verify_table($table)
public function keypairs($query, $values = array())
{
return in_array($table, $this->column("SHOW TABLES"));
return $this->all($query, $values, \PDO::FETCH_GROUP|\PDO::FETCH_COLUMN);
}

/**
* Used to determine if columns exist in a certain table in the selected database or not.
*/
private function verify_columns($table, $columns)
* It checks if the table exists in the database, if it does, it checks if the columns exist in the
* table.
*
* @param verify_table The table to verify
* @param verify_columns An array of columns to verify exist in the table
*
* @return a boolean value.
*/
private function verifyTablesAndColumns($verify_table, $verify_columns)
{
$db_columns = $this->column("SHOW COLUMNS FROM `{$table}`");
return !array_diff($columns, $db_columns);
$tables = &$this->verified_tables;
if(!array_key_exists($verify_table, $tables)) {
$tables = array_fill_keys(array_keys(array_flip($this->column('SHOW TABLES'))), null);
}
if($exists = array_key_exists($verify_table, $tables) && empty($tables[$verify_table])) {
$tables[$verify_table] = $this->column("SHOW COLUMNS FROM `{$verify_table}`");
} else {
throw new Exception('The given table does not exist in the database');
}
$columns_valid = !array_diff($verify_columns, $tables[$verify_table]);
if(!$columns_valid) {
throw new Exception('One or more of the supplied columns do not exist in the supplied table');
}
return $columns_valid;
}

/**
* Used to handle running queries with multiple data sets. Automatically used when passing an array of data sets to $this->run
* Can only be used for insert queries
*
* @param query The query to execute
* @param values The data sets associated with the query, an array of key => value pairs
*/
private function multi($query, $values = array())
{
if(substr(strtolower($query), 0, 6) !== "insert") {
throw new Exception('Multi data sets can only be used with insert queries');
}
$stmt = $this->prepare($query);
foreach ($values as $value)
try
{
$stmt->execute($value);
$this->beginTransaction();
foreach ($values as $value)
{
$stmt->execute($value);
}
$this->commit();
return $stmt;
} catch(Exception $e) {
$pdo->rollback();
throw $e;
}
return $stmt;
}
}

0 comments on commit ee7a10b

Please sign in to comment.