From 2f388847980524aa31a27955e1f780ad0097bdc1 Mon Sep 17 00:00:00 2001 From: Benjamin Renard Date: Sun, 18 Feb 2024 17:21:54 +0100 Subject: [PATCH] Adjust example to use DBObject and CSV export --- example/composer.json | 3 +- example/includes/cli.php | 61 ++--- example/includes/core.php | 3 +- example/includes/functions.php | 6 +- example/includes/templates.php | 10 +- example/includes/url-helpers.php | 6 +- example/includes/url-public.php | 63 +++--- example/src/Db.php | 374 ------------------------------- example/src/Db/Item.php | 172 ++++++++++++++ example/templates/form.tpl | 24 +- example/templates/search.tpl | 55 ++++- example/templates/show.tpl | 12 +- phpstan.neon | 5 - 13 files changed, 314 insertions(+), 480 deletions(-) delete mode 100644 example/src/Db.php create mode 100644 example/src/Db/Item.php diff --git a/example/composer.json b/example/composer.json index fa0f244..04552c6 100644 --- a/example/composer.json +++ b/example/composer.json @@ -22,7 +22,8 @@ } ], "require": { - "brenard/eesyphp": "@dev" + "brenard/eesyphp": "@dev", + "brenard/php-unidecode": "dev-master" }, "config": { "allow-plugins": { diff --git a/example/includes/cli.php b/example/includes/cli.php index 8d2a281..39e772a 100644 --- a/example/includes/cli.php +++ b/example/includes/cli.php @@ -6,6 +6,7 @@ use EesyPHP\Date; use EesyPHP\Log; use EesyPHPExample\Db; +use EesyPHPExample\Db\Item; use function EesyPHP\___; @@ -23,15 +24,15 @@ if (php_sapi_name() != "cli") **/ function print_item_info($item) { - printf(_("Item #%s:\n"), $item['id']); - printf("\t"._("ID: %s")."\n", $item['id']); - printf("\t"._("Name: '%s'")."\n", $item['name']); - printf("\t"._("Date: %s")."\n", Date :: format($item['date'])); + printf(_("Item #%s:\n"), $item->id); + printf("\t"._("ID: %s")."\n", $item->id); + printf("\t"._("Name: '%s'")."\n", $item->name); + printf("\t"._("Date: %s")."\n", Date :: format($item->date)); printf( "\t"._("Description: %s")."\n", - ($item['description']?"'".$item['description']."'":_("Not set")) + ($item->description?"'".$item->description."'":_("Not set")) ); - printf("\t"._("Status: %s")."\n", $item['status']); + printf("\t"._("Status: %s")."\n", $item->status); return true; } @@ -40,11 +41,11 @@ function print_item_info($item) { * Common CLI commands **/ -$orderbys = array('id', 'name', 'date', 'status', 'description'); function cli_list($command_args) { global $orderbys; $params = array( - 'order' => $orderbys[0], + 'filters' => [], + 'order' => Item :: default_order(), 'order_direction' => 'ASC', 'all' => true, ); @@ -54,7 +55,7 @@ function cli_list($command_args) { case '-o': case '--orderby': $i++; - if(!in_array($command_args[$i], $orderbys)) + if(!in_array($command_args[$i], Item :: possible_orders())) Cli :: usage('Invalid --orderby clause'); $params['order'] = $command_args[$i]; break; @@ -67,7 +68,7 @@ function cli_list($command_args) { $i++; if(!check_status($command_args[$i])) Cli :: usage('Invalid -s/--status clause'); - $params['status'] = $command_args[$i]; + $params['filters']['status'] = $command_args[$i]; break; default: $patterns[] = $command_args[$i]; @@ -77,7 +78,7 @@ function cli_list($command_args) { if (!empty($patterns)) $params['pattern'] = implode(' ', $patterns); - $items = Db :: search_items($params); + $items = Item :: search($params); if (!is_array($items)) { Log :: error("Invalid DB info return.\n"); return False; @@ -101,11 +102,11 @@ function cli_list($command_args) { foreach($items['items'] as $info) { $tbl->addRow( array( - $info['id'], - $info['name'], - Date :: format($info['date']), - $info['status'], - ($info['description']?$info['description']:''), + $info->id, + $info->name, + Date :: format($info->date), + $info->status, + ($info->description?$info->description:''), ) ); } @@ -120,7 +121,7 @@ Cli :: add_command( ___("[patterns]"), array( ___("-o|--orderby Ordering list criterion. Possible values:"), - " - ".implode("\n - ", $orderbys), + " - ".implode("\n - ", Item :: possible_orders()), ___("-r|--reverse Reverse order"), ___("-s|--status Filter on status. Possible values:"), " - ".implode("\n - ", array_keys($status_list)), @@ -132,7 +133,7 @@ function cli_show($command_args) { Cli :: usage(_('You must provide a valid ID.')); $item_id = $command_args[0]; - $item = Db :: get_item($item_id); + $item = Item :: get($item_id); if (!$item) Log :: fatal(_("Item #%s not found."), $item_id); @@ -157,7 +158,7 @@ function cli_delete($command_args) { // Check exist $item_id = $command_args[0]; - $item = Db :: get_item($item_id); + $item = Item :: get($item_id); if (!$item) Log :: fatal(_("Item #%s not found."), $item_id); @@ -173,7 +174,7 @@ function cli_delete($command_args) { } echo "\n"; - if (!Db :: delete_item($item['id'])) + if (!$item -> delete()) Log :: fatal(_("An error occurred deleting item #%d."), $item_id); return True; @@ -187,7 +188,7 @@ Cli :: add_command( function cli_export($command_args) { $fd = fopen((count($command_args) >= 1?$command_args[0]:'php://output'), 'w'); - Db :: export_items($fd); + Item :: export($fd); fclose($fd); Log :: info("Items export to '".(count($command_args) >= 1?$command_args[0]:'STDOUT')."'."); } @@ -200,7 +201,7 @@ Cli :: add_command( function cli_restore($command_args) { $fd = fopen((count($command_args) >= 1?$command_args[0]:'php://stdin'), 'r'); - Db :: restore_items($fd); + Item :: restore($fd); fclose($fd); Log :: info( "Items restored from '%s'", @@ -243,33 +244,33 @@ function cli_cron($command_args) { 'Invalid $item_max_age value set in configuration: it\'s must be a positive integer.'); Log :: debug("cli_cron(): item max age = $item_max_age day(s)"); - $limit = time() - ($item_max_age * 86400); + $limit = Date :: from_timestamp(time() - ($item_max_age * 86400)); Log :: debug("Handle items expiration with creation date limit ".Date :: format($limit)."."); - $items = Db :: search_items(array('all' => true)); + $items = Item :: search(array('all' => true)); $error = false; foreach($items['items'] as $item) { - if ($item['date'] < $limit) { + if ($item -> date < $limit) { if ($just_try) { Log :: debug('Just-try mode: do not really delete item #%s (%s, creation date: %s)', - $item['id'], $item['name'], Date :: format($item['date']) + $item->id, $item->name, Date :: format($item->date) ); } - else if (Db :: delete_item($item['id'])) { + else if ($item->delete()) { Log :: info('Item #%s (%s) deleted (creation date: %s)', - $item['id'], $item['name'], Date :: format($item['date']) + $item->id, $item->name, Date :: format($item->date) ); } else { Log :: error('Fail to delete item "%s" (%s, creation date: %s)', - $item['id'], $item['name'], Date :: format($item['date']) + $item->id, $item->name, Date :: format($item->date) ); $error = true; } } else { Log :: debug('Item "%s" (%s) still valid (creation date: %s)', - $item['id'], $item['name'], Date :: format($item['date']) + $item->id, $item->name, Date :: format($item->date) ); } } diff --git a/example/includes/core.php b/example/includes/core.php index 364f730..773a7e3 100644 --- a/example/includes/core.php +++ b/example/includes/core.php @@ -1,10 +1,9 @@ $value) { - if ($value != $item[$key]) + if ($value != $item->$key) $changes[$key] = $value; } } @@ -113,7 +113,7 @@ function can_delete($item) { } function can_do($item, $status=array()) { - return in_array($item['status'], $status); + return in_array($item->status, $status); } # vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/example/includes/templates.php b/example/includes/templates.php index f56b959..0304a4d 100644 --- a/example/includes/templates.php +++ b/example/includes/templates.php @@ -44,16 +44,16 @@ function smarty_item_status($params) { 'refused' => 'danger', 'archived' => 'secondary', ); - if (array_key_exists($params['item']['status'], $status2class)) { - $class = $status2class[$params['item']['status']]; + if (array_key_exists($params['item']->status, $status2class)) { + $class = $status2class[$params['item']->status]; } else $class='danger'; echo ""; echo ( - array_key_exists($params['item']['status'], $status_list)? - $status_list[$params['item']['status']]: - "Inconnu (".$params['item']['status'].")" + array_key_exists($params['item']->status, $status_list)? + $status_list[$params['item']->status]: + "Inconnu (".$params['item']->status.")" ); echo ""; } diff --git a/example/includes/url-helpers.php b/example/includes/url-helpers.php index 67ef0bd..39590f9 100644 --- a/example/includes/url-helpers.php +++ b/example/includes/url-helpers.php @@ -4,14 +4,14 @@ use EesyPHP\Check; use EesyPHP\Log; use EesyPHP\Tpl; -use EesyPHPExample\Db; +use EesyPHPExample\Db\Item; function get_item_from_url($id, $fatal=false) { if (!Check :: id($id)) Log :: fatal(_('Invalid element identifier.')); - $item = Db :: get_item($id); - if(!is_array($item)) { + $item = Item :: get($id); + if(!$item instanceof Item) { $error = sprintf(_("Item #%s not found."), $id); if ($fatal) Log :: fatal($error); diff --git a/example/includes/url-public.php b/example/includes/url-public.php index 806226d..001d06d 100644 --- a/example/includes/url-public.php +++ b/example/includes/url-public.php @@ -5,7 +5,7 @@ use EesyPHP\Log; use EesyPHP\Tpl; use EesyPHP\Url; -use EesyPHPExample\Db; +use EesyPHPExample\Db\Item; use function EesyPHP\vardump; @@ -28,7 +28,7 @@ function handle_search($request) { ) { $_SESSION['search']=array( 'pattern' => false, - 'status' => 'all', + 'filters' => ['status' => 'all'], 'order' => 'name', 'order_direction' => 'ASC', ); @@ -40,7 +40,7 @@ function handle_search($request) { $status_list['all'] = _('Any'); if (isset($_REQUEST['status'])) { if (check_status($_REQUEST['status']) || $_REQUEST['status'] == 'all') - $_SESSION['search']['status'] = $_REQUEST['status']; + $_SESSION['search']['filters']['status'] = $_REQUEST['status']; else Tpl :: assign('status_error', true); } @@ -82,7 +82,7 @@ function handle_search($request) { } // Nb par page - $nbs_by_page=array(10,25,50,100,500); + $nbs_by_page = array(10,25,50,100,500); if (isset($_REQUEST['nb_by_page']) && in_array(intval($_REQUEST['nb_by_page']),$nbs_by_page)) { $_SESSION['search']['nb_by_page']=intval($_REQUEST['nb_by_page']); $_SESSION['search']['page']=1; @@ -92,7 +92,7 @@ function handle_search($request) { } Log :: debug('Search params : '.vardump($_SESSION['search'])); - $result = Db :: search_items($_SESSION['search']); + $result = Item :: search($_SESSION['search']); if (!is_array($result)) Tpl :: fatal_error( _("An error occurred while listing the items. ". @@ -138,10 +138,7 @@ function handle_show($request) { 'js/myconfirm.js', ); - Tpl :: display( - "show.tpl", _("Element %s"), - (is_array($item)?$item['name']:"#".$request -> id) - ); + Tpl :: display("show.tpl", _("Element %s"), $item->name); } Url :: add_url_handler('|^item/(?P[0-9]+)$|', 'handle_show'); @@ -156,10 +153,11 @@ function handle_create($request) { $info = array(); $field_errors = handle_item_post_data($info); if (isset($_POST['submit']) && empty($field_errors)) { - $item = Db :: add_item($info); - if (is_array($item)) { - Tpl :: add_message(_("The element '%s' has been created."), $item['name']); - Url :: redirect('item/'.$item['id']); + $item = new Item(); + $item -> apply($info); + if ($item->save()) { + Tpl :: add_message(_("The element '%s' has been created."), $item->name); + Url :: redirect('item/'.$item->id); } Tpl :: add_error(_("An error occurred while saving this item.")); } @@ -182,28 +180,29 @@ function handle_modify($request) { global $status_list; $item = get_item_from_url($request -> id); - if(!is_array($item)) + if(!$item) Url :: error_404(); if (!can_modify($item)) { Tpl :: add_error(_('You cannot edit this item.')); - Url :: redirect('item/'.$item['id']); + Url :: redirect('item/'.$item->id); } $info = array(); $field_errors = handle_item_post_data($info); if (isset($_POST['submit']) && empty($field_errors)) { $changes = array(); foreach ($info as $key => $value) { - if ($value != $item[$key]) + if ($value != $item->$key) $changes[$key] = $value; } Log :: debug('Changes : '.vardump($changes)); if (empty($changes)) { - Tpl :: add_message(_("You have not made any changes to element '%s'."), $item['name']); - Url :: redirect('item/'.$item['id']); + Tpl :: add_message(_("You have not made any changes to element '%s'."), $item->name); + Url :: redirect('item/'.$item->id); } - if (Db :: update_item($item['id'], $changes) === true) { - Tpl :: add_message(_("The element '%s' has been updated successfully."), $item['name']); - Url :: redirect('item/'.$item['id']); + $item->apply($changes); + if ($item->save()) { + Tpl :: add_message(_("The element '%s' has been updated successfully."), $item->name); + Url :: redirect('item/'.$item->id); } Tpl :: add_error(_("An error occurred while updating this item.")); } @@ -215,11 +214,11 @@ function handle_modify($request) { _("There are errors preventing this item from being saved. ". "Please correct them before attempting to save your changes.")); Tpl :: assign('info', (!empty($info)?$info:$item)); - Tpl :: assign('item_id', $item['id']); + Tpl :: assign('item_id', $item->id); Tpl :: assign('field_errors', $field_errors); Tpl :: assign('status_list', $status_list); - Tpl :: display("form.tpl", _("Element %s: Modification"), $item['name']); + Tpl :: display("form.tpl", _("Element %s: Modification"), $item->name); } Url :: add_url_handler('|^item/(?P[0-9]+)/modify$|', 'handle_modify'); @@ -230,23 +229,23 @@ Url :: add_url_handler('|^item/(?P[0-9]+)/modify$|', 'handle_modify'); */ function handle_archive($request) { $item = get_item_from_url($request -> id); - if(!is_array($item)) { + if(!$item) { Tpl :: add_error(_("Item #%s not found."), $request -> id); Url :: redirect('item'); } - if ($item['status'] == 'archived') { + if ($item->status == 'archived') { Tpl :: add_message(_("This item is already archived.")); } else if (!can_archive($item)) { Tpl :: add_error(_('You cannot archive this item.')); } - else if (Db :: archive_item($item['id']) === true) { - Tpl :: add_message(_("The element '%s' has been archived successfully."), $item['name']); + else if ($item->archive()) { + Tpl :: add_message(_("The element '%s' has been archived successfully."), $item->name); } else { Tpl :: add_error(_('An error occurred while archiving this item.')); } - Url :: redirect('item/'.$item['id']); + Url :: redirect('item/'.$item->id); } Url :: add_url_handler('|^item/(?P[0-9]+)/archive$|', 'handle_archive'); @@ -257,18 +256,18 @@ Url :: add_url_handler('|^item/(?P[0-9]+)/archive$|', 'handle_archive'); */ function handle_delete($request) { $item = get_item_from_url($request -> id); - if(!is_array($item)) { + if(!$item) { Tpl :: add_error(_("Item #%s not found."), $request -> id); } else if (!can_delete($item)) { Tpl :: add_error(_('You cannot delete this item.')); } - else if (Db :: delete_item($item['id']) === true) { - Tpl :: add_message(_("The element '%s' has been deleted successfully."), $item['name']); + else if ($item->delete()) { + Tpl :: add_message(_("The element '%s' has been deleted successfully."), $item->name); } else { Tpl :: add_error(_('An error occurred while deleting this item.')); - Url :: redirect('item/'.$item['id']); + Url :: redirect('item/'.$item->id); } Url :: redirect('item'); } diff --git a/example/src/Db.php b/example/src/Db.php deleted file mode 100644 index 80d3efc..0000000 --- a/example/src/Db.php +++ /dev/null @@ -1,374 +0,0 @@ -getMessage()); - } - return false; - } - - static public function get_item($id, $raw_values=false) { - try { - $info = self :: get_one('item', array('id' => $id)); - - if (!is_array($info)) - return false; - - if ($raw_values) - return $info; - - return self :: format_row_info($info, array('date')); - } - catch (Exception $e) { - Log :: error("Error retrieving item #$id info from database : ".$e->getMessage()); - } - return false; - } - - static public function add_item($values) { - $values['date'] = self :: time2datetime(time()); - try { - $result = self :: $fpdo -> insertInto('item') - -> values($values) - -> execute(); - - if ($result !== false) { - $item = self :: get_item($result); - Log :: info("New item #$result added"); - Hook :: trigger('item_added', $item); - return $item; - } - } - catch (Exception $e) { - Log :: error("Error creating item in database : ".$e->getMessage()); - } - return false; - } - - static public function update_item($id, $changes) { - if (!is_array($changes)) - return false; - if (empty($changes)) - return true; - $item = self :: get_item($id, true); - if (!is_array($item)) return false; - - if (isset($changes['date']) && $changes['date']) - $changes['date'] = self :: time2datetime($changes['date']); - - try { - $result = self :: $fpdo -> update('item') - -> set($changes) - -> where('id', $id) - -> execute(); - - if ($result !== false) { - Log :: info("Item #$id updated"); - Hook :: trigger('item_updated', $item); - return true; - } - } - catch (Exception $e) { - Log :: error("Error updating item #$id in database : ".$e->getMessage()); - } - return false; - } - - static public function change_item_status($id, $status) { - if (self :: update_item($id, array('status' => $status))) { - Log :: info("Status of item #$id changed to $status."); - return true; - } - return false; - } - - static public function archive_item($id) { - return self :: change_item_status($id, 'archived'); - } - - static public function delete_item($id) { - try { - $result = self :: $fpdo -> deleteFrom('item') - -> where('id', $id) - -> execute(); - - if ($result !== false) { - Log :: info("Item #$id deleted"); - return True; - } - } - catch (Exception $e) { - Log :: error("Error deleting item #$id from database : ".$e->getMessage()); - } - return false; - } - - static public function search_items($params) { - // Detect PgSQL backend - $is_pgsql = (strpos(App::get('db.dsn', '', 'string'), "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 = ""; - $page = 1; - $nb_by_page = 10; - $offset = 0; - if (!isset($params['all'])) { - 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 = self :: $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) { - Log :: error('search_items() : search in DB return false'); - return false; - } - - $rows = $result -> fetchAll(); - $items = array(); - foreach ($rows as $row) { - $items[] = self :: format_row_info($row, array('date')); - } - if (isset($params['all'])) { - return array( - 'count' => count($items), - 'first' => 1, - 'last' => count($items), - 'nb_pages' => 1, - 'page' => 1, - 'items' => $items - ); - } - $query_count = self :: $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) { - Log :: 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, - ); - } - catch (Exception $e) { - Log :: exception( - $e, "An exception occurred searching items with params %s infos from database : ", - preg_replace("/\n[ \t]*/", " ", print_r($params, true)) - ); - } - return false; - } - - static public function export_items($fd=null) { - if (!$fd) $fd = fopen('php://output', 'w'); - fputcsv( - $fd, - array ( - 'id', - 'name', - 'date', - 'status', - 'description', - ) - ); - $items = self :: get_items(); - foreach($items as $item) { - fputcsv( - $fd, - array( - $item['id'], - $item['name'], - $item['date'], - $item['status'], - $item['description'], - ) - ); - } - return True; - } - - static public function restore_items($fd=null) { - if (!$fd) $fd = fopen('php://stdin', 'r'); - try { - $result = self :: $fpdo -> deleteFrom('item') - -> execute(); - if ($result === false) { - Log :: error("An unknown error occurred truncating item table in database."); - return false; - } - } - catch (Exception $e) { - Log :: 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)?self :: time2datetime($row[$i]):$row[$i]); - $values[$field] = $value; - } - $result = self :: $fpdo -> insertInto('item') - -> values($values) - -> execute(); - - if ($result !== false) { - $restored++; - } - else { - Log :: error("Unknown error occurred restoring item from line #$line :\n".print_r($values, true)); - $error = true; - } - } - catch (Exception $e) { - Log :: error( - "Error restoring item from line #$line : ".$e->getMessage()."\n".print_r($values, true)); - $error = true; - } - } - Log :: info("$restored items restored"); - - // Trigger hooks - Hook :: trigger('items_restored'); - - return !$error; - } -} diff --git a/example/src/Db/Item.php b/example/src/Db/Item.php new file mode 100644 index 0000000..bf4d9d6 --- /dev/null +++ b/example/src/Db/Item.php @@ -0,0 +1,172 @@ + new AttrInt(['autoincrement' => true]), + 'name' => new AttrStr(['required' => true]), + 'date' => new AttrTimestamp(['default' => 'time']), + 'status' => new AttrStr(['required' => true, 'default' => 'pending']), + 'description' => new AttrStr(), + ]; + } + + /** + * Change item status in DB + * @param string $status New item status + * @return bool + */ + public function change_status($status) { + $this->status = $status; + if ($this -> save()) { + Log :: info("Status of item #$this->id changed to $status."); + return true; + } + return false; + } + + /** + * Set item as archived in DB + * @return bool + */ + public function archive() { + return $this -> change_status('archived'); + } + + + /** + * Compute WHERE clauses from word pattern + * @throws \EesyPHP\Db\DbException + * @return array + */ + public static function word_to_filters($word) { + $patterns_word = []; + // 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 (self :: DB_CLASS :: is_pgsql()) { + $word = Unidecode::unidecode($word); + $patterns_word["unaccent($field) ILIKE ?"] = "%$word%"; + } + else + $patterns_word["$field LIKE ?"] = "%$word%"; + } + } + return $patterns_word; + } + + /** + * Search objects + * @throws \EesyPHP\Db\DbException + * @see \EesyPHP\Db\DbObject::search() + * @return array|false The search result as an array, or False in case of error. + */ + public static function search($params) { + if ( + $params && + isset($params['filters']) && + isset($params['filters']['status']) && + $params['filters']['status'] == 'all' + ) + unset($params['filters']['status']); + return parent :: search($params); + } + + /** + * Export items + * @param resource|null $fd The file pointer where to export (optional, default: php://output) + * @param array>|null $items Items to export + * @param array $schema The object schema (optional) + * @return boolean + */ + static function export($fd=null, $items=null, $schema=null) { + $schema = $schema ? $schema : static :: get_schema(); + $export = new CSV(static :: csv_export_fields($schema)); + $items = $items?$items:static :: list(); + if ($items === false) + return false; + $rows = []; + foreach ($items as $item) { + $row = []; + foreach($schema as $attr => $attr_type) + $row[$attr] = $item->$attr; + $rows[] = $row; + } + return $export->export($rows, $fd); + } + + static function restore($fd=null, $schema=null) { + $schema = $schema ? $schema : static :: get_schema(); + $import = new CSV(static :: csv_export_fields($schema)); + $items = $import->load($fd); + if ($items === false) { + Log :: error("Error loading items."); + return false; + } + + if (!$items) { + Log :: error("No item loaded."); + return false; + } + + try { + if (self :: DB_CLASS :: truncate(self :: TABLE)) { + Log :: debug("Table %s truncated", self :: TABLE); + } + else { + Log :: error("An unknown error occurred truncating table %s in database.", self :: TABLE); + return false; + } + } + catch (\Exception $e) { + Log :: error("Error truncating item table in database : ".$e->getMessage()); + return false; + } + + $success = true; + foreach($items as $item) { + $obj = new Item(); + $obj->apply($item); + $success = $success && $obj->save(); + } + + // Trigger hooks + Hook :: trigger('items_restored'); + return $success; + } +} diff --git a/example/templates/form.tpl b/example/templates/form.tpl index 3b93c41..a7fa301 100644 --- a/example/templates/form.tpl +++ b/example/templates/form.tpl @@ -7,9 +7,11 @@
- {if array_key_exists('name', $field_errors)}
{$field_errors['name']}
{/if} + {if array_key_exists('name', $field_errors)} +
{$field_errors['name']}
+ {/if}
@@ -18,22 +20,30 @@
- {if array_key_exists('status', $field_errors)}
{$field_errors['status']}
{/if} + {if array_key_exists('status', $field_errors)} +
{$field_errors['status']}
+ {/if}
- - {if array_key_exists('description', $field_errors)}
{$field_errors['description']}
{/if} + + {if array_key_exists('description', $field_errors)} +
{$field_errors['description']}
+ {/if}
- {t}Back{/t} + + {t}Back{/t} + - {t}Reset{/t} + + + {t}Reset{/t} +
@@ -46,8 +51,12 @@ - - + + @@ -55,14 +64,36 @@ {foreach $result.items as $item} - - + + diff --git a/example/templates/show.tpl b/example/templates/show.tpl index ea32d01..5873539 100644 --- a/example/templates/show.tpl +++ b/example/templates/show.tpl @@ -5,7 +5,7 @@
- {$item.name} + {$item->name}
@@ -14,7 +14,7 @@
- {format_time time=$item.date} + {format_time time=$item->date}
@@ -32,7 +32,7 @@
- {if $item.description}{$item.description|escape:'htmlall'}{else}{t}Unspecified.{/t}{/if} + {if $item->description}{$item->description|escape:'htmlall'}{else}{t}Unspecified.{/t}{/if}
@@ -40,8 +40,8 @@
{t}Back{/t} - {if can_modify($item)} {t}Modify{/t}{/if} - {if can_archive($item)} {t}Archive{/t}{/if} - {if can_delete($item)} {t}Delete{/t}{/if} + {if can_modify($item)} {t}Modify{/t}{/if} + {if can_archive($item)} {t}Archive{/t}{/if} + {if can_delete($item)} {t}Delete{/t}{/if}
{/block} diff --git a/phpstan.neon b/phpstan.neon index 69f620a..9743727 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -32,8 +32,3 @@ parameters: - message: "#Call to static method isError\\(\\) on an unknown class PEAR\\.#" path: src/Email.php - - - message: "#Variable \\$status_list might not be defined\\.#" - paths: - - example/includes/cli.php -
{table_ordered_th url="{$request->current_url}" order="date" text="{t}Date{/t}" search=$search}{table_ordered_th url="{$request->current_url}" order="name" text="{t}Name{/t}" search=$search} + {table_ordered_th url="{$request->current_url}" order="date" text="{t}Date{/t}" search=$search} + + {table_ordered_th url="{$request->current_url}" order="name" text="{t}Name{/t}" search=$search} + {t}Status{/t} {t}Actions{/t}
{format_time time=$item.date}{$item.name}{format_time time=$item->date} + + {$item->name} + + {item_status item=$item} - {t}View{/t} - {if can_modify($item)} {t}Modify{/t}{/if} - {if can_archive($item)} {t}Archive{/t}{/if} - {if can_delete($item)} {t}Delete{/t}{/if} + + {t}View{/t} + + {if can_modify($item)} + + {t}Modify{/t} + + {/if} + {if can_archive($item)} + + {t}Archive{/t} + + {/if} + {if can_delete($item)} + + {t}Delete{/t} + + {/if}