DB: add support of joins in get_many() / get_one() helper methods

This commit is contained in:
Benjamin Renard 2023-08-21 15:28:19 +02:00
parent 28e6397f58
commit ea66e9d217
Signed by: bn8
GPG key ID: 3E2E1CE1907115BC

View file

@ -129,31 +129,29 @@ class Db {
/** /**
* Helper to retreive one row from a table of the database * Helper to retreive one row from a table of the database
* @param string $table The table name * @param string $table The table name
* @param array|string $where WHERE clause(s) as expected by Envms\FluentPDO\Query * @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 * @param array|string|null $fields The expected fields as string (separeted by comma) or an
* array (optional, default: all table fields will be returned) * 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 * @return array|false
*/ */
public function get_one($table, $where, $fields=null) { public function get_one($table, $where, $fields=null, $joins=null) {
try { try {
$query = $this -> fpdo -> from($table) -> where($where); $query = $this -> fpdo -> from($table) -> where($where);
if ($joins)
self :: apply_joins($query, $joins);
if ($fields) if ($fields)
$query -> select(null) -> select($fields); $query -> select(null) -> select($fields);
if ($query->execute() === false) // @phpstan-ignore-line if ($query->execute() === false)
return false; return false;
$return = $query->fetchAll(); $return = $query->fetchAll();
if (is_array($return) && count($return) == 1) if (is_array($return) && count($return) == 1)
return $return[0]; return $return[0];
} }
catch (Exception $e) { catch (Exception $e) {
Log :: error( self :: _log_simple_select_query_error(
"Error occured getting one row of the table %s in database (where %s): %s", false, $table, $e, $where, $fields, null, null, $joins
$table,
is_array($where)?
preg_replace("/\n */", " ", print_r($where, true)):
vardump($where),
$e->getMessage()
); );
} }
return false; return false;
@ -162,44 +160,125 @@ class Db {
/** /**
* Helper to retreive multiple rows from a table of the database * Helper to retreive multiple rows from a table of the database
* @param string $table The table name * @param string $table The table name
* @param array|string $where WHERE clause(s) as expected by Envms\FluentPDO\Query * @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 * @param array|string|null $fields The expected fields as string (separeted by comma) or an
* array (optional, default: all table fields will be returned) * array (optional, default: all table fields will be returned)
* @param string|null $order_by An optional ORDER clause as a string * @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|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 * @return array|false
*/ */
public function get_many( 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 { try {
$query = $this -> fpdo -> from($table); $query = $this -> fpdo -> from($table);
if ($joins)
self :: apply_joins($query, $joins);
if ($fields) if ($fields)
$query -> select(null) -> select($fields); $query -> select(null) -> select($fields);
if ($where) if ($where)
$query -> where($where); $query -> where($where);
if ($order_by) if ($order_by)
$query -> orderBy($order_by); $query -> orderBy($order_by);
if ($query->execute() === false) // @phpstan-ignore-line if ($query->execute() === false)
return false; return false;
$return = $query->fetchAll(); $return = $query->fetchAll();
if (is_array($return)) if (is_array($return))
return $return; return $return;
} }
catch (Exception $e) { catch (Exception $e) {
Log :: error( self :: _log_simple_select_query_error(
"Error occured getting rows of the table %s in database (where %s): %s", false, $table, $e, $where, $fields, $order_by, $limit, $joins
$table,
is_array($where)?
preg_replace("/\n */", " ", print_r($where, true)):
vardump($where),
$e->getMessage()
); );
} }
return false; 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 * Helper to insert a row in a table
* @param string $table The table name * @param string $table The table name