date_format = $date_format; if ($datetime_format) $this -> datetime_format = $datetime_format; if ($locale_time) $this -> locale_time = $locale_time; try { // Connect to database $this -> pdo = new PDO($dsn, $user, $password, $options); $this -> fpdo = new Query($this -> pdo); // Register the debug query handler to log it $this -> fpdo -> debug = array(self :: class, 'debug_query'); Log :: trace("DB connection established (DSN: '%s')", $dsn); } catch(Exception $e) { Log :: error("Fail to connect to DB (DSN : '%s') : %s", $dsn, $e->getMessage()); Log :: fatal(I18n::_('Unable to connect to the database.')); } } /** * Debug a query * @param \Envms\FluentPDO\Queries\Base $q * @return void */ public static function debug_query($q) { self :: $total_query_time += intval(ceil($q->getExecutionTime() * 1000000000)); $msg = "# DB query"; if ($q->getResult()) $msg .= sprintf( " (%0.3f ms; rows = %d)", $q->getExecutionTime() * 1000, $q->getResult()->rowCount() ); $msg .= ": ".$q->getQuery(); $parameters = $q->getParameters(); if ($parameters) { if (is_array($parameters)) { $msg .= "\n# Parameters: '" . implode("', '", $parameters) . "'"; } else { // @phpstan-ignore-line $msg .= "\n# Parameters: '" . vardump($parameters) . "'"; } } Log :: debug($msg); } /** * Set autocommit (only available on OCI, Firebird or MySQL connection) * @param bool $value * @see https://www.php.net/manual/en/pdo.setattribute.php * @return void */ public function set_autocommit($value) { $this -> pdo -> setAttribute(PDO::ATTR_AUTOCOMMIT, $value); } /* * Simple request helpers */ /** * 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) * @return array|false */ public function get_one($table, $where, $fields=null) { try { $query = $this -> fpdo -> from($table) -> where($where); if ($fields) $query -> select(null) -> select($fields); if ($query->execute() === false) // @phpstan-ignore-line 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() ); } return false; } /** * 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 * @return array|false */ public function get_many( $table, $where=null, $fields=null, $order_by=null, $limit=null ) { try { $query = $this -> fpdo -> from($table); 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 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() ); } return false; } /** * Helper to insert a row in a table * @param string $table The table name * @param array $values The values of the row * @param boolean $want_id Set to true if you want to retreive the ID of the inserted row * @return bool|int The ID of the inserted row if $want_id, or true/false in case of success/error */ public function insert($table, $values, $want_id=false) { try { $id = $this -> fpdo -> insertInto($table) -> values($values) -> execute(); } catch (Exception $e) { Log :: error( "Error occured inserting row in the table %s of the database: %s\nValues:\n%s", $table, $e->getMessage(), vardump($values) ); return false; } if ($id !== false) { Log::debug('Row insert in table %s with ID #%s', $table, $id); return $want_id?$id:true; } return false; } /** * Helper to update a row in database * @param string $table The table name * @param array $changes Associative array of changes * @param array|string $where WHERE clause(s) as expected by Envms\FluentPDO\Query * @param null|int|false $expected_row_changes The number of expected row affected by the query * or false if you don't want to check it (optional, * default: null == 1) * @return bool */ public function update($table, $changes, $where, $expected_row_changes=null) { if (is_null($expected_row_changes)) $expected_row_changes = 1; try { $result = $this -> fpdo -> update($table) -> set($changes) -> where($where) -> execute(); } catch (Exception $e) { Log :: error( "Error occured updating %s in the table %s of the database (where %s): %s\nChanges:\n%s", $expected_row_changes == 1?'row':'rows', $table, is_array($where)? preg_replace("/\n */", " ", print_r($where, true)): vardump($where), $e->getMessage(), vardump($changes) ); return false; } if (!is_int($result)) return false; if ($expected_row_changes === false) return true; return $expected_row_changes == $result; } /** * Helper to delete one or multiple rows in 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 null|int|false $expected_row_changes The number of expected row affected by the query * or false if you don't want to check it (optional, * default: null == 1) * @return bool */ public function delete($table, $where, $expected_row_changes=null) { if (is_null($expected_row_changes)) $expected_row_changes = 1; try { $result = $this -> fpdo -> deleteFrom($table) -> where($where) -> execute(); } catch (Exception $e) { Log :: error( "Error occured deleting %s in the table %s of the database (where %s): %s", $expected_row_changes == 1?'one row':'some rows', $table, is_array($where)? preg_replace("/\n */", " ", print_r($where, true)): vardump($where), $e->getMessage() ); return false; } // Bad return type declared in \Envms\FluentPDO\Queries\Delete // @phpstan-ignore-next-line if (!is_int($result)) return false; // @phpstan-ignore-next-line if ($expected_row_changes === false) return true; return $expected_row_changes == $result; } /* * Handle date/datetime format */ public function set_locale() { if ($this -> locale_time) setlocale(LC_TIME, $this -> locale_time); } public function date2time($date) { $this -> set_locale(); $pdate = strptime($date, $this -> date_format); return mktime( $pdate['tm_hour'], $pdate['tm_min'], $pdate['tm_sec'], $pdate['tm_mon'] + 1, $pdate['tm_mday'], $pdate['tm_year'] + 1900 ); } public function time2date($time) { $this -> set_locale(); return strftime($this -> date_format, $time); } public function datetime2time($date) { $this -> set_locale(); $pdate = strptime($date, $this -> datetime_format); return mktime( $pdate['tm_hour'], $pdate['tm_min'], $pdate['tm_sec'], $pdate['tm_mon'] + 1, $pdate['tm_mday'], $pdate['tm_year'] + 1900 ); } public function time2datetime($time) { $this -> set_locale(); return strftime($this -> datetime_format, $time); } /** * Helper method to format row info * @param array $row The raw row info * @param array $datetime_fields List of field in datetime format * @param array $date_fields List of field in date format * @return array */ public function format_row_info($row, $datetime_fields=null, $date_fields=null) { // Convert datetime fields if (is_array($datetime_fields)) foreach($datetime_fields as $field) if ($row[$field]) $row[$field] = $this -> datetime2time($row[$field]); // Convert date fields if (is_array($date_fields)) foreach($date_fields as $field) if ($row[$field]) $row[$field] = $this -> date2time($row[$field]); return $row; } }