Compare commits

...

2 commits

Author SHA1 Message Date
Benjamin Renard
ea66e9d217
DB: add support of joins in get_many() / get_one() helper methods 2023-08-21 15:28:19 +02:00
Benjamin Renard
28e6397f58
DB: fix handling failed query in debug_query method 2023-08-21 15:27:15 +02:00

View file

@ -85,7 +85,10 @@ class Db {
* @return void
*/
public static function debug_query($q) {
self :: $total_query_time += intval(ceil($q->getExecutionTime() * 1000000000));
$error = $q->getMessage();
// Execution time not available in case of execution error
if (!$error)
self :: $total_query_time += intval(ceil($q->getExecutionTime() * 1000000000));
$msg = "# DB query";
if ($q->getResult())
$msg .= sprintf(
@ -104,6 +107,8 @@ class Db {
$msg .= "\n# Parameters: '" . vardump($parameters) . "'";
}
}
if ($error)
$msg .= "\n# ERROR: $error";
Log :: debug($msg);
}
@ -124,31 +129,29 @@ class Db {
/**
* Helper to retreive one row from a table of the database
* @param string $table The table name
* @param array|string $where WHERE clause(s) as expected by Envms\FluentPDO\Query
* @param array|string|null $fields The expected fields as string (separeted by comma) or an
* array (optional, default: all table fields will be returned)
* @param string $table The table name
* @param array|string $where WHERE clause(s) as expected by Envms\FluentPDO\Query
* @param array|string|null $fields The expected fields as string (separeted by comma) or an
* array (optional, default: all table fields will be returned)
* @param array<array{0: 'LEFT'|'RIGHT'|'INNER'|'OUTER'|'FULL', 1: string, 2: string}>|array{0: 'LEFT'|'RIGHT'|'INNER'|'OUTER'|'FULL', 1: string, 2: string} $joins Join specification as array (see apply_joins())
* @return array|false
*/
public function get_one($table, $where, $fields=null) {
public function get_one($table, $where, $fields=null, $joins=null) {
try {
$query = $this -> fpdo -> from($table) -> where($where);
if ($joins)
self :: apply_joins($query, $joins);
if ($fields)
$query -> select(null) -> select($fields);
if ($query->execute() === false) // @phpstan-ignore-line
if ($query->execute() === false)
return false;
$return = $query->fetchAll();
if (is_array($return) && count($return) == 1)
return $return[0];
}
catch (Exception $e) {
Log :: error(
"Error occured getting one row of the table %s in database (where %s): %s",
$table,
is_array($where)?
preg_replace("/\n */", " ", print_r($where, true)):
vardump($where),
$e->getMessage()
self :: _log_simple_select_query_error(
false, $table, $e, $where, $fields, null, null, $joins
);
}
return false;
@ -157,44 +160,125 @@ class Db {
/**
* Helper to retreive multiple rows from a table of the database
* @param string $table The table name
* @param array|string $where WHERE clause(s) as expected by Envms\FluentPDO\Query
* @param array|string|null $fields The expected fields as string (separeted by comma) or an
* array (optional, default: all table fields will be returned)
* @param string|null $order_by An optional ORDER clause as a string
* @param string|null $limit An optional LIMIT clause as a string
* @param string $table The table name
* @param array|string $where WHERE clause(s) as expected by Envms\FluentPDO\Query
* @param array|string|null $fields The expected fields as string (separeted by comma) or an
* array (optional, default: all table fields will be returned)
* @param string|null $order_by An optional ORDER clause as a string
* @param string|null $limit An optional LIMIT clause as a string
* @param array<array{0: 'LEFT'|'RIGHT'|'INNER'|'OUTER'|'FULL', 1: string, 2: string}>|array{0: 'LEFT'|'RIGHT'|'INNER'|'OUTER'|'FULL', 1: string, 2: string} $joins Join specification as array (see apply_joins())
* @return array|false
*/
public function get_many(
$table, $where=null, $fields=null, $order_by=null, $limit=null
$table, $where=null, $fields=null, $order_by=null, $limit=null, $joins=null
) {
try {
$query = $this -> fpdo -> from($table);
if ($joins)
self :: apply_joins($query, $joins);
if ($fields)
$query -> select(null) -> select($fields);
if ($where)
$query -> where($where);
if ($order_by)
$query -> orderBy($order_by);
if ($query->execute() === false) // @phpstan-ignore-line
if ($query->execute() === false)
return false;
$return = $query->fetchAll();
if (is_array($return))
return $return;
}
catch (Exception $e) {
Log :: error(
"Error occured getting rows of the table %s in database (where %s): %s",
$table,
is_array($where)?
preg_replace("/\n */", " ", print_r($where, true)):
vardump($where),
$e->getMessage()
self :: _log_simple_select_query_error(
false, $table, $e, $where, $fields, $order_by, $limit, $joins
);
}
return false;
}
/**
* Mapping of JOIN type with corresponding query object method
* @var array<string,string>
*/
private static $join_type_to_query_method = array(
'LEFT' => 'leftJoin',
'RIGHT' => 'rightJoin',
'INNER' => 'innerJoin',
'OUTER' => 'outerJoin',
'FULL' => 'fullJoin',
);
/**
* Apply JOIN clauses on a query object
* @param \Envms\FluentPDO\Query $query The reference of the query object
* @param array<array{0: 'LEFT'|'RIGHT'|'INNER'|'OUTER'|'FULL', 1: string, 2: string}>|array{0: 'LEFT'|'RIGHT'|'INNER'|'OUTER'|'FULL', 1: string, 2: string} $joins Join specification as array: ['type', 'table', 'ON clause']
* - type: LEFT, RIGHT, INNER, OUTER or FULL
* - table: the joined table name
* - ON clause: the ON clause (ex: "user.id = article.user_id")
* @return void
*/
public static function apply_joins(&$query, &$joins) {
if (!$joins) return;
if (isset($joins[0]) && !is_array($joins[0]))
$joins = [$joins];
foreach ($joins as $join) {
if (!is_array($join) || count($join) != 3) {
throw new Exception(sprintf("Invalid JOIN clause provided: %s", vardump($join)));
}
if (!array_key_exists(strtoupper($join[0]), self :: $join_type_to_query_method)) {
throw new Exception(sprintf("Invalid JOIN type '%s'", $join[0]));
}
$method = self :: $join_type_to_query_method[strtoupper($join[0])];
call_user_func([$query, $method], sprintf("%s ON %s", $join[1], $join[2]));
}
}
/**
* Helper to log error during simple select query
* @param bool $multiple True if expected multiple rows, False instead
* @param string $table The table name
* @param Exception $e The exception
* @param array|string $where WHERE clause(s) as expected by Envms\FluentPDO\Query
* @param array|string|null $fields The expected fields as string (separeted by comma) or an
* array (optional, default: all table fields will be returned)
* @param string|null $order_by An optional ORDER clause as a string
* @param string|null $limit An optional LIMIT clause as a string
* @param array<array<string>>|null $joins Join specification as array (see apply_joins())
* @return void
*/
private function _log_simple_select_query_error(
$multiple, $table, $e, $where=null, $fields=null, $order_by=null, $limit=null, $joins=null
) {
$msg = "Error occured getting %s of the table %s";
$params = [
$multiple?"rows":"one row",
$table,
];
if (is_array($joins)) {
foreach($joins as $join) {
$msg .= ", %s join with table %s on '%s'";
$params = array_merge($params, $join);
}
}
$extra_clauses = [];
if ($where)
$extra_clauses['where'] = (
is_array($where)?
preg_replace("/\n */", " ", print_r($where, true)):
vardump($where)
);
if ($fields)
$extra_clauses['selected fields'] = is_array($fields)?implode(',', $fields):$fields;
if ($order_by)
$extra_clauses['order by'] = $order_by;
if ($limit)
$extra_clauses['limit'] = $limit;
$msg .= "in database (%s): %s";
$params[] = implode_with_keys($extra_clauses);
$params[] = $e->getMessage();
Log :: error($msg, $params);
}
/**
* Helper to insert a row in a table
* @param string $table The table name