diff --git a/src/Db.php b/src/Db.php index 63be9f4..aa37e98 100644 --- a/src/Db.php +++ b/src/Db.php @@ -129,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} $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; @@ -162,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} $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 + */ + 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} $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>|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