$row = $pdo_s->fetch(PDO::FETCH_ASSOC); if ($row !== false) { /* * TODO: Uncomment when we take the time to filter only used parameters! * (currently, values here that are not used cause PDO exception!) // prepare argument to PDO prepare, if it ever may be needed if( count($options_pending_sql) > 0 ) { foreach( $row as $col => $value ) $opt_pdo_params[":$col"] = $value; } */ // read each column foreach ($row as $col => $value) { if ($auto_cols) { $json_columns[] = array('column' => $col, 'name' => TableClass::ident_to_name($col), 'control' => "text"); end($json_columns); $names_xlat[$col] = key($json_columns); // = the same as count($json_row)-1, but... // just in case PHP changes its algorithm } if (!$no_req_ids) { if (isset($names_xlat[$col])) { if ($json_columns[$names_xlat[$col]]['control'] == "number") { $value = strpos($value, '.') !== false ? floatval($value) : intval($value); } // required otherwise the "number" control won't display this! $json_columns[$names_xlat[$col]]['value'] = $value; } else { if (isset($button_columns[$col])) { $button_columns[$col][0] = $value;
// ============================================================================ // #### Tables ############################################################## // ============================================================================ $select_client = "SELECT ClientID, Name FROM Clients ORDER BY Name ASC"; $select_trip = "SELECT TripID, Title FROM Trips ORDER BY Title ASC"; $select_country = "SELECT CountryID, Name FROM Countries ORDER BY Name ASC"; $select_currency = "SELECT CurrencyID, NameISO FROM Currencies ORDER BY NameISO ASC"; /** * Table keys should *not* contain: * * Forward slashes ('/') -- confuses AngularJS router arguments, even * though this is not used at this time * * Pipes ('|') -- confuses automatically generated keys when table=* * * Newlines ('\n') or carriage returns ('\r') -- may confuse their * usage in HTML/HTTP */ TableClass::$data_tables = array('clients' => array('source' => 'sqlite_demos', 'table' => "Clients", 'name' => "Customers", 'col_id' => 'ClientID', 'col_list' => array(array('Name', 'ContactPhone', 'ContactEmail'), array('Name')), 'col_name' => 'Name', 'col_names' => array('Name' => array("Name", "text"), 'Address' => array("Street address", "textaddr"), 'CountryID' => array("Country", "select", '', $select_country), 'TaxNumber' => array("Tax number", "text"), 'ContactPhone' => array("Telephone", "tel"), 'ContactEmail' => array("E-mail", "email"), 'PreferCurrencyID' => array("Preferred currency", "select", '', $select_currency)), 'editable' => TableClass::EDITABLE_ON_REQUEST | TableClass::CAN_INSERT, 'buttons' => array(array('Purchases', 'list:sales', 'Purchases made by this client', array('ClientID', 'ClientID')))), 'client-sales' => array('unlisted' => true, 'source' => 'sqlite_demos', 'table' => "Clients", 'name' => "Customers", 'col_id' => 'ClientID', 'col_list' => array(array('Name', 'ContactPhone', 'ContactEmail'), array('Name')), 'col_name' => 'Name', 'col_names' => array('Name' => array("Name", "text"), 'Address' => array("Street address", "textaddr"), 'CountryID' => array("Country", "select", '', $select_country), 'TaxNumber' => array("Tax number", "text"), 'ContactPhone' => array("Telephone", "tel"), 'ContactEmail' => array("E-mail", "email"), 'PreferCurrencyID' => array("Preferred currency", "select", '', $select_currency)), 'editable' => TableClass::EDITABLE_ON_REQUEST | TableClass::CAN_INSERT, 'buttons' => array(array('Purchases', 'list:sales', 'Purchases made by this client', array('ClientID', 'ClientID'))), 'filter_list_before' => 'filter_clientsales_list_before'), 'sales' => array('source' => 'sqlite_demos', 'table' => "Sales", 'col_id' => 'SaleID', 'col_list' => array(array('ClientName', 'TripCountryName', 'OnDate'), array('-OnDate')), 'col_name' => 'OnDate', 'col_names' => array('ClientID' => array("Customer", "select", '', $select_client), 'TripID' => array("Trip package", "select", '', $select_trip), 'OnDate' => array("Date travelled", "date"), 'Description' => array("Special requests", "textarea", "Describe any special needs of the customer/trip."), 'Price' => array("Price to bill", "number"), 'PriceCurrencyID' => array("Price currency", "select", '', $select_currency)), 'editable' => TableClass::EDITABLE_ON_REQUEST | TableClass::CAN_INSERT | TableClass::CAN_DELETE, 'filter_list_before' => 'filter_sales_list_before', 'buttons' => array(array('Customer', 'read:clients', 'Show this customer', 'ClientID'), array('Trip package', 'read:trips', 'Show this trip package', 'TripID'))), 'trips' => array('source' => 'sqlite_demos', 'table' => "Trips", 'name' => "Trip Packages", 'col_id' => 'TripID', 'col_list' => array(array('TripCountryName', 'Title', 'UntilDate'), array('TripCountryName', 'Title', '-UntilDate')), 'col_name' => 'Title', 'col_names' => array('Title' => array("Package title", "text", "Title used to summarize this trip package in lists."), 'DestinationCountryID' => array("Trip to", "select", '', $select_country), 'Description' => array("Description", "textarea", "Describe the points of interest visited, provide some history and background, and describe what services this trip package consists of."), 'Price' => array("Price to bill", "number"), 'PriceCurrencyID' => array("Price currency", "select", '', $select_currency), 'UntilDate' => array("Available until", "date", "Date when this trip was/will be no longer available. Leave empty if not yet known.")), 'editable' => TableClass::EDITABLE_ON_REQUEST | TableClass::CAN_INSERT | TableClass::CAN_DELETE, 'filter_list_before' => 'filter_trips_list_before'), 'countries' => array('source' => 'sqlite_demos', 'table' => "Countries", 'name' => "Selectable Countries", 'col_id' => 'CountryID', 'col_list' => array(array('Name'), array('Name')), 'col_names' => array('Name' => array("Name", "text")), 'editable' => TableClass::EDITABLE_ON_REQUEST | TableClass::CAN_INSERT | TableClass::CAN_DELETE, 'buttons' => array(array('Customers living in this country', 'list:clients', 'Customers living in this country', array('CountryID', 'CountryID')), array('Customers traveled to this country', 'list:client-sales', 'Customers that have traveled to this country', array('CountryID', 'TripCountryID')), array('Trip packages to this country', 'list:trips', 'Available trips to this country', array('CountryID', 'DestinationCountryID')))), 'currencies' => array('source' => 'sqlite_demos', 'table' => "Currencies", 'name' => "Selectable Currencies", 'col_id' => 'CurrencyID', 'col_list' => array(array('NameISO', 'Name'), array('NameISO')), 'col_names' => array('NameISO' => array("3-letter 'ISO' name", "text"), 'Name' => array("Full name", "text")), 'editable' => TableClass::EDITABLE_ON_REQUEST | TableClass::CAN_INSERT | TableClass::CAN_DELETE, 'buttons' => array(array('Customers paying in this currency', 'list:clients', 'Customers that prefer to pay in this currency', array('CurrencyID', 'PreferCurrencyID')), array('Sales in this currency', 'list:sales', 'Sales made in this currency', array('CurrencyID', 'PriceCurrencyID')), array('Trip packages in this currency', 'list:trips', 'Available trips in this currency', array('CurrencyID', 'PriceCurrencyID'))))); // Reset the demo database every hour, on the hour (can be removed in production) // ============================================================================ $browseStorage_demo = @TableClass::$data_sources['sqlite_demos']['file']; if (is_string($browseStorage_demo)) { $browseStorage_demo_dir = dirname($browseStorage_demo) . PATH_SEPARATOR; $browseStorage_demo_file = basename($browseStorage_demo); $browseStorage_demo_ext = strrchr($browseStorage_demo_file, '.'); $browseStorage_demo_file = substr($browseStorage_demo_file, 0, -strlen($browseStorage_demo_ext)); $browseStorage_demo_original = $browseStorage_demo_dir . $browseStorage_demo_file . '-original' . $browseStorage_demo_ext; $browseStorage_demo_copy = $browseStorage_demo_dir . $browseStorage_demo_file . '-copy' . $browseStorage_demo_ext; if (file_exists($browseStorage_demo_original) && gmdate('YmdH', filemtime($browseStorage_demo_original)) != gmdate('YmdH') && !file_exists($browseStorage_demo_copy)) { touch($browseStorage_demo_original); // "atomic" duplication: copy($browseStorage_demo_original, $browseStorage_demo_copy); chmod($browseStorage_demo_copy, 0666);
} $group_name = strval(@$tab['group']); if (!$nogroups) { $group_key = array_search($group_name, $groups_xlat, true); if ($group_key === false) { $groups_xlat[] = $group_name; end($groups_xlat); $group_key = key($groups_xlat); // = the same as count($groups_xlat)-1, but... // just in case PHP changes its algorithm } } if (!isset($json_groups[$group_key])) { $json_groups[$group_key] = array('name' => $group_name, 'tables' => array()); } $name = strlen(@$tab['name']) > 0 ? strval($tab['name']) : TableClass::ident_to_name($tab['table']); $icon = strval(@$tab['icon']); if ($tab['table'] === '*') { $tab_obj = new TableClass($table_key); if ($tab_obj->src_type != TableClass::TYPE_PDO) { throw new Exception(sprintf($tab_obj->error_sprintf, "Can't retrieve all tables for a non-relational-database (SQL) data source ['table'] in")); } $pdo_s = $tab_obj->src->query("SHOW TABLES"); foreach ($pdo_s->fetchAll(PDO::FETCH_COLUMN, 0) as $tab_name) { if (!preg_match('/\\A[a-zA-Z_][a-zA-Z0-9_]*\\z/', $tab_name)) { continue; } $json_groups[$group_key]['tables'][] = array('table_key' => "{$table_key}|{$tab_name}", 'name' => $name, 'icon' => $icon); } } else { $json_groups[$group_key]['tables'][] = array('table_key' => $table_key, 'name' => $name, 'icon' => $icon);
} // Note that $_REQUEST was not updated! // ============================================================================ // #### Write data to table ################################################# // ============================================================================ /** * This will store the array that will be turned into JSON to be returned. * See the description at the top of this file for the syntax. * @var array */ $json = array('error' => false); // Prepare arguments to be passed to the "before" filter // ==================================================================== $table_key = strval(@$_POST['table_key']); // New browseStorage\TableClass object $tab_obj = new TableClass($table_key); $tab =& $tab_obj->tab; // shortcut // Get configured table primary keys (IDs) $config_ids = $tab_obj->config_ids(); // Retrieve IDs from $_POST into array(column_id => value) $req_ids = $tab_obj->req_ids($config_ids); $no_req_ids = count($req_ids) <= 0; // Get configured table column names $config_names = $tab_obj->config_names(); $auto_cols = count($config_names) <= 0; // Prepare list of columns values to write $req_col_values = $tab_obj->req_col_values(); // Security and sanity checks // ==================================================================== // Read-only table security check
$json = array('error' => false, 'name' => "*", 'can_edit' => 0, 'can_insert' => false, 'can_delete' => false, 'row_start' => 0, 'row_cols' => array('col_id' => array(), 'col_list' => array(), 'names_list' => array()), 'rows' => array()); /** * Shortcut (reference) into `$json['row_cols']`. * @var array */ $json_row_cols =& $json['row_cols']; /** * Shortcut (reference) into `$json['rows']`. * @var array */ $json_rows =& $json['rows']; // Prepare arguments to be passed to the "before" filter // ==================================================================== $table_key = strval(@$_POST['table_key']); // New browseStorage\TableClass object $tab_obj = new TableClass($table_key); $tab =& $tab_obj->tab; // shortcut // Get configured table primary keys (IDs) $config_ids = $tab_obj->config_ids(); // Get configured table list columns if (!is_array(@$tab['col_list']) || (count($tab['col_list']) - 1 & ~1) != 0) { // i.e., !=(1 or 2) throw new \Exception(sprintf($tab_obj->error_sprintf, "Missing key ['col_list'] (array) in")); } // $config_list_cols = $tab['col_list'][0]; $config_list_order = @$tab['col_list'][1]; // if (!is_array($config_list_cols)) { $config_list_cols = array(strval($config_list_cols));