460 lines
12 KiB
PHP
460 lines
12 KiB
PHP
<?php
|
|
|
|
use Unidecode\Unidecode;
|
|
|
|
try {
|
|
$pdo = new PDO($db_dsn, $db_user, $db_pwd, $db_options);
|
|
$pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
$fpdo = new FluentPDO($pdo);
|
|
|
|
$fpdo -> debug = function ($q) {
|
|
$time = sprintf('%0.3f', $q->getTime() * 1000) . ' ms';
|
|
$rows = ($q->getResult()) ? $q->getResult()->rowCount() : 0;
|
|
$query = $q->getQuery();
|
|
$msg = "# DB query ($time; rows = $rows) : $query";
|
|
|
|
$parameters = $q->getParameters();
|
|
if ($parameters) {
|
|
if (is_array($parameters)) {
|
|
$msg .= "\n# Parameters: '" . implode("', '", $parameters) . "'";
|
|
}
|
|
else {
|
|
$msg .= "\n# Parameters: '" . vardump($parameters) . "'";
|
|
}
|
|
}
|
|
|
|
logging('DEBUG',$msg);
|
|
};
|
|
}
|
|
catch(Exception $e) {
|
|
logging('ERROR',"Fail to connect to DB (DSN : '$db_dsn') : ".$e->getMessage());
|
|
logging("FATAL", _('Unable to connect to the database.'));
|
|
}
|
|
|
|
/*
|
|
* Handle date/datetime format
|
|
*/
|
|
function db_date2time($date) {
|
|
global $db_date_format;
|
|
setlocale(LC_TIME, "fr_FR");
|
|
$pdate = strptime($date, $db_date_format);
|
|
return mktime(
|
|
$pdate['tm_hour'], $pdate['tm_min'], $pdate['tm_sec'],
|
|
$pdate['tm_mon'] + 1, $pdate['tm_mday'], $pdate['tm_year'] + 1900
|
|
);
|
|
}
|
|
|
|
function db_time2date($time) {
|
|
global $db_date_format;
|
|
setlocale(LC_TIME, "fr_FR");
|
|
return strftime($db_date_format, $time);
|
|
}
|
|
|
|
function db_datetime2time($date) {
|
|
global $db_datetime_format;
|
|
setlocale(LC_TIME, "fr_FR");
|
|
$pdate = strptime($date, $db_datetime_format);
|
|
return mktime(
|
|
$pdate['tm_hour'], $pdate['tm_min'], $pdate['tm_sec'],
|
|
$pdate['tm_mon'] + 1, $pdate['tm_mday'], $pdate['tm_year'] + 1900
|
|
);
|
|
}
|
|
|
|
function db_time2datetime($time) {
|
|
global $db_datetime_format;
|
|
setlocale(LC_TIME, "fr_FR");
|
|
return strftime($db_datetime_format, $time);
|
|
}
|
|
|
|
/*
|
|
* Helper to format row info from DB
|
|
*/
|
|
function _format_row_info($row, $datetime_fields) {
|
|
// Convert datetime fields
|
|
foreach($datetime_fields as $field)
|
|
if ($row[$field])
|
|
$row[$field] = db_datetime2time($row[$field]);
|
|
return $row;
|
|
}
|
|
|
|
/*
|
|
* Methods to handle items
|
|
*/
|
|
function get_items($orderby='id', $raw_values=false) {
|
|
global $fpdo;
|
|
try {
|
|
$query = $fpdo -> from('item')
|
|
-> orderBy($orderby);
|
|
|
|
$result = $query -> execute();
|
|
if ($result !== false) {
|
|
$info = $result -> fetchAll();
|
|
if ($info === false)
|
|
return null;
|
|
if ($raw_values)
|
|
return $info;
|
|
|
|
$items = array();
|
|
foreach ($info as $item)
|
|
$items[$item['id']] = _format_row_info($item, array('date'));
|
|
return $items;
|
|
}
|
|
}
|
|
catch (Exception $e) {
|
|
logging('ERROR', "Error retreiving items info from database : ".$e->getMessage());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function get_item($id, $raw_values=false) {
|
|
global $fpdo;
|
|
try {
|
|
$query = $fpdo -> from('item')
|
|
-> where('id', $id);
|
|
|
|
$result = $query -> execute();
|
|
if ($result !== false) {
|
|
$info = $result -> fetch();
|
|
if ($info === false)
|
|
return null;
|
|
if ($raw_values)
|
|
return $info;
|
|
|
|
return _format_row_info($info, array('date'));
|
|
}
|
|
}
|
|
catch (Exception $e) {
|
|
logging('ERROR', "Error retreiving item #$id info from database : ".$e->getMessage());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function add_item($values) {
|
|
global $fpdo;
|
|
$values['date'] = db_time2datetime(time());
|
|
try {
|
|
$result = $fpdo -> insertInto('item')
|
|
-> values($values)
|
|
-> execute();
|
|
|
|
if ($result !== false) {
|
|
$item = get_item($result);
|
|
logging('INFO', "New item #$result added");
|
|
trigger_hook('item_added', $item);
|
|
return $item;
|
|
}
|
|
}
|
|
catch (Exception $e) {
|
|
logging('ERROR', "Error creating item in database : ".$e->getMessage());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function update_item($id, $changes) {
|
|
global $fpdo;
|
|
|
|
if (!is_array($changes))
|
|
return false;
|
|
if (empty($changes))
|
|
return true;
|
|
$item = get_item($id, true);
|
|
if (!is_array($item)) return false;
|
|
|
|
if (isset($changes['date']) && !is_null($changes['date']))
|
|
$changes['date'] = db_time2datetime($changes['date']);
|
|
|
|
try {
|
|
$result = $fpdo -> update('item')
|
|
-> set($changes)
|
|
-> where('id', $id)
|
|
-> execute();
|
|
|
|
if ($result !== false) {
|
|
logging('INFO', "Item #$id updated");
|
|
trigger_hook('item_updated', $item);
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception $e) {
|
|
logging('ERROR', "Error updating item #$id in database : ".$e->getMessage());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function change_item_status($id, $status) {
|
|
if (update_item($id, array('status' => $status))) {
|
|
logging('INFO', "Status of item #$id changed to $status.");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function archive_item($id) {
|
|
return change_item_status($id, 'archived');
|
|
}
|
|
|
|
function delete_item($id) {
|
|
global $fpdo;
|
|
try {
|
|
$result = $fpdo -> deleteFrom('item')
|
|
-> where('id', $id)
|
|
-> execute();
|
|
|
|
if ($result !== false) {
|
|
logging('INFO', "Item #$id deleted");
|
|
return True;
|
|
}
|
|
}
|
|
catch (Exception $e) {
|
|
logging('ERROR', "Error deleting item #$id from database : ".$e->getMessage());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function search_items($params) {
|
|
global $fpdo, $db_dsn;
|
|
|
|
// Detect PgSQL backend
|
|
$is_pgsql = (strpos($db_dsn, "pgsql:") === 0);
|
|
|
|
$where = array();
|
|
if (isset($params['status']) && $params['status'] && $params['status'] != 'all')
|
|
$where['status'] = $params['status'];
|
|
|
|
$patterns_where = array();
|
|
if (isset($params['pattern']) && $params['pattern']) {
|
|
foreach(preg_split('/\s+/', trim($params['pattern'])) as $word) {
|
|
if (!$word) continue;
|
|
$patterns_word=array();
|
|
|
|
// If numeric pattern ?
|
|
if (preg_match('/^[0-9]+$/', $word)) {
|
|
// Numeric pattern
|
|
$word = intval($word);
|
|
$patterns_word['id = ?'] = $word;
|
|
}
|
|
else {
|
|
// Text pattern
|
|
foreach (array('name', 'description') as $field) {
|
|
if ($is_pgsql) {
|
|
$word = Unidecode::unidecode($word);
|
|
$patterns_word["unaccent($field) ILIKE ?"] = "%$word%";
|
|
}
|
|
else
|
|
$patterns_word["$field LIKE ?"] = "%$word%";
|
|
}
|
|
}
|
|
$patterns_where[] = $patterns_word;
|
|
}
|
|
}
|
|
|
|
$order='id';
|
|
$orders=array('id', 'name', 'date', 'status', 'description');
|
|
if (isset($params['order'])) {
|
|
if (!in_array($order, $orders))
|
|
return -1;
|
|
$order=$params['order'];
|
|
}
|
|
|
|
$order_direction='DESC';
|
|
if (isset($params['order_direction']) && $params['order_direction']) {
|
|
if (!in_array($params['order_direction'], array('ASC', 'DESC')))
|
|
return -1;
|
|
$order_direction=$params['order_direction'];
|
|
}
|
|
|
|
$orderby="$order $order_direction";
|
|
|
|
$limit = "";
|
|
$offset = 0;
|
|
if (!isset($params['all'])) {
|
|
$page=1;
|
|
$nb_by_page=10;
|
|
if (isset($params['page']) && $params['page']>0) {
|
|
if (isset($params['nb_by_page']) && $params['nb_by_page']>0) {
|
|
$nb_by_page=intval($params['nb_by_page']);
|
|
}
|
|
$page=intval($params['page']);
|
|
}
|
|
$offset=($page-1)*$nb_by_page;
|
|
$limit=$nb_by_page;
|
|
}
|
|
|
|
try {
|
|
$query = $fpdo -> from('item');
|
|
if (!empty($where))
|
|
$query -> where($where);
|
|
foreach ($patterns_where as $patterns_word)
|
|
call_user_func_array(
|
|
array($query, 'where'),
|
|
array_merge(
|
|
array('('.implode(' OR ', array_keys($patterns_word)).')'),
|
|
array_values($patterns_word)
|
|
)
|
|
);
|
|
$result = $query -> orderBy($orderby)
|
|
-> limit($limit)
|
|
-> offset($offset)
|
|
-> execute();
|
|
|
|
if ($result !== false) {
|
|
$rows = $result -> fetchAll();
|
|
$items = array();
|
|
foreach ($rows as $row) {
|
|
$items[] = _format_row_info($row, array('date'));
|
|
}
|
|
if (is_array($items)) {
|
|
if (empty($limit)) {
|
|
return array(
|
|
'count' => count($items),
|
|
'first' => 1,
|
|
'last' => count($items),
|
|
'nb_pages' => 1,
|
|
'page' => 1,
|
|
'items' => $items
|
|
);
|
|
}
|
|
else {
|
|
$query_count = $fpdo -> from('item')
|
|
-> select(null)
|
|
-> select('count(*) as count');
|
|
if (!empty($where))
|
|
$query_count -> where($where);
|
|
foreach ($patterns_where as $patterns_word)
|
|
call_user_func_array(
|
|
array($query_count, 'where'),
|
|
array_merge(
|
|
array('('.implode(' OR ', array_keys($patterns_word)).')'),
|
|
array_values($patterns_word)
|
|
)
|
|
);
|
|
|
|
$result_count = $query_count -> execute();
|
|
|
|
if ($result_count === false) {
|
|
logging('DEBUG', 'search_items() : search for count in DB return false');
|
|
return False;
|
|
}
|
|
$count = $result_count -> fetch();
|
|
return array(
|
|
'count' => $count['count'],
|
|
'first' => $offset+1,
|
|
'last' => (
|
|
$offset+$nb_by_page<$count['count']?
|
|
$offset+$nb_by_page:$count['count']),
|
|
'nb_pages' => ceil($count['count']/$nb_by_page),
|
|
'page' => $page,
|
|
'items' => $items,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
logging('ERROR', 'search_items() : search in DB return false');
|
|
}
|
|
catch (Exception $e) {
|
|
log_exception($e, "An exception occured searching items with params ".preg_replace("/\n[ \t]*/"," ",print_r($params,1))." infos from database : ");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function export_items($fd=null) {
|
|
if (!$fd) $fd = fopen('php://output', 'w');
|
|
fputcsv(
|
|
$fd,
|
|
array (
|
|
'id',
|
|
'name',
|
|
'date',
|
|
'status',
|
|
'description',
|
|
)
|
|
);
|
|
$items = get_items();
|
|
foreach($items as $item) {
|
|
fputcsv(
|
|
$fd,
|
|
array(
|
|
$item['id'],
|
|
$item['name'],
|
|
$item['date'],
|
|
$item['status'],
|
|
$item['description'],
|
|
)
|
|
);
|
|
}
|
|
return True;
|
|
}
|
|
|
|
function restore_items($fd=null) {
|
|
global $fpdo;
|
|
if (!$fd) $fd = fopen('php://stdin', 'r');
|
|
try {
|
|
$result = $fpdo -> deleteFrom('item')
|
|
-> execute();
|
|
if ($result === false) {
|
|
logging('ERROR', "An unknown error occured truncating item table in database.");
|
|
return false;
|
|
}
|
|
}
|
|
catch (Exception $e) {
|
|
logging('ERROR', "Error truncating item table in database : ".$e->getMessage());
|
|
return false;
|
|
}
|
|
|
|
$first_row = false;
|
|
$line = 0;
|
|
$restored = 0;
|
|
$error = false;
|
|
$datetime_fields = array (
|
|
'date',
|
|
);
|
|
// Map fields to support hold CSV files format
|
|
$mapping = array (
|
|
'creation_date' => 'date',
|
|
'desc' => 'description',
|
|
);
|
|
|
|
while (($row = fgetcsv($fd)) !== FALSE) {
|
|
$line++;
|
|
if ($first_row === false) {
|
|
$first_row = $row;
|
|
continue;
|
|
}
|
|
try {
|
|
$values = array();
|
|
for ($i=0; $i < count($first_row); $i++) {
|
|
if (!$row[$i]) continue;
|
|
$field = (
|
|
array_key_exists($first_row[$i], $mapping)?
|
|
$mapping[$first_row[$i]]:
|
|
$first_row[$i]);
|
|
$value = (in_array($field, $datetime_fields)?db_time2datetime($row[$i]):$row[$i]);
|
|
$values[$field] = $value;
|
|
}
|
|
$result = $fpdo -> insertInto('item')
|
|
-> values($values)
|
|
-> execute();
|
|
|
|
if ($result !== false) {
|
|
$restored++;
|
|
}
|
|
else {
|
|
logging('ERROR', "Unkwown error occured restoring item from line #$line :\n".print_r($values, true));
|
|
$error = true;
|
|
}
|
|
}
|
|
catch (Exception $e) {
|
|
logging(
|
|
'ERROR',
|
|
"Error restoring item from line #$line : ".$e->getMessage()."\n".print_r($values, true));
|
|
$error = true;
|
|
}
|
|
}
|
|
logging('INFO', "$restored items restored");
|
|
|
|
// Trigger hooks
|
|
trigger_hook('items_restored');
|
|
|
|
return !$error;
|
|
}
|