? tw_exportable.patch Index: tw.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/tw/tw.module,v retrieving revision 1.1.2.31 diff -r1.1.2.31 tw.module 466a467,473 > $items['admin/content/tw/export'] = array( > 'title' => 'Code for hook_views_data()', > 'page callback' => 'tw_export', > 'access arguments' => array(TW_ACCESS), > 'type' => MENU_CALLBACK, > 'file' => 'tw_pages.inc', > ); Index: tw.views.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/tw/tw.views.inc,v retrieving revision 1.1.2.13 diff -r1.1.2.13 tw.views.inc 9,124c9 < /** < * Implementation of hook_views_data() < */ < function tw_views_data() { < $tables = array(); < < // Create table definitions for each import table < $sql = "SELECT * FROM {tw_tables}"; < $tblresult = db_query($sql); < while ($tblrow = db_fetch_object($tblresult)) { < // Table Wizard stores the true DB table name - Drupal knows the name without < // the table prefix (if there is one). We'll use the true name for display < $tablename = $tblrow->tablename; < $dbconnection = $tblrow->dbconnection; < if ($dbconnection == 'default') { < $rawtablename = schema_unprefix_table($tablename); < $disptablename = $tablename; < } < else { < $rawtablename = $tablename; < $disptablename = $dbconnection . '.' . $tablename; < } < $twtid = $tblrow->twtid; < $table = array(); < // Add each viewable column to the table definition < // Note that we include the primary key column even if it's empty - this means < // the table is totally empty, and we need to have at least one column present < // to prevent errors in the view < $sql = "SELECT twcid, colname, primarykey, secure, coltype < FROM {tw_columns} < WHERE twtid=%d AND ignorecol=0 < ORDER BY weight"; < $colresult = db_query($sql, $twtid); < $pk = array(); < while ($colrow = db_fetch_object($colresult)) { < $colname = $colrow->colname; < $table[$colname] = array( < 'title' => $colname, < 'help' => $colname, < // TODO: Truncate text at 80 characters. < // TODO: Better yet, do some jQuery magic to expand to the full text < 'field' => array( < 'handler' => 'views_handler_field', < 'click sortable' => TRUE, < ), < 'filter' => array( < 'handler' => _tw_views_handler_type($colrow->coltype), < 'allow empty' => TRUE, < ), < // TODO: Add support for arguments < //'argument' < 'sort' => array( < 'handler' => 'views_handler_sort' < ), < ); < if ($colrow->primarykey) { < $pk[] = $colname; < } < } < // Any table with a single primary key column can be a base table < if (count($pk) == 1) { < $table['table'] = array( < 'group' => t($disptablename), < 'base' => array( < 'field' => $pk[0], < 'title' => t('Database table @tablename', array('@tablename' => $disptablename)), < 'help' => t('Table managed by the Table Wizard'), < 'weight' => 10, < 'database' => $dbconnection, < ), < ); < } < $tables[$rawtablename] = $table; < } < < // Now that all tables are present, fill in relationships defined by foreign keys < $sql = "SELECT twt1.tablename tbl1, twc1.colname col1, twt2.tablename tbl2, twc2.colname col2 < FROM {tw_relationships} twr < INNER JOIN {tw_columns} twc1 ON twr.leftcol=twc1.twcid < INNER JOIN {tw_tables} twt1 ON twc1.twtid=twt1.twtid < INNER JOIN {tw_columns} twc2 ON twr.rightcol=twc2.twcid < INNER JOIN {tw_tables} twt2 ON twc2.twtid=twt2.twtid < ORDER BY tbl1, col1, tbl2, col2"; < $result = db_query($sql); < < // To allow multiple joins from one tbl/col, must use an alias and < // 'relationship field' for the left side < $i = 0; < while ($row = db_fetch_array($result)) { < extract($row); < $rawtbl1 = schema_unprefix_table($tbl1); < $rawtbl2 = schema_unprefix_table($tbl2); < if (!isset($tables[$rawtbl1][$col1]['relationship'])) { < $tables[$rawtbl1][$col1]['title'] = t("$col1 (joins to $tbl2)"); < $tables[$rawtbl1][$col1]['relationship'] = array( < 'base' => $rawtbl2, < 'base field' => $col2, < 'label' => t("Join $tbl1 to $tbl2"), < ); < } < else { < $i++; < $mungedcol = $col1 . '_' . $i; < $tables[$rawtbl1][$mungedcol] = $tables[$rawtbl1][$col1]; < $tables[$rawtbl1][$mungedcol]['title'] = t("$col1 (joins to $tbl2)"); < $tables[$rawtbl1][$mungedcol]['real field'] = $col1; < $tables[$rawtbl1][$mungedcol]['relationship'] = array( < 'base' => $rawtbl2, < 'base field' => $col2, < 'relationship field' => $col1, < 'label' => t("Join $tbl1 to $tbl2"), < ); < } < } < return $tables; < } --- > require_once drupal_get_path('module', 'tw') . '/tw_tablebuild.inc'; 127c12,15 < * Return a views handler based on the column type. --- > * Implementation of hook_views_data(). > * > * Utilizes shared table building functions to generate the full views data > * array. 129,144c17,19 < function _tw_views_handler_type($sqltype) { < preg_match('/^[a-zA-Z]+/', $sqltype, $matches); < $type = tw_column_type($matches[0]); < switch ($type) { < case 'numeric': < $filter = 'views_handler_filter_numeric'; < break; < case 'datetime': < $filter = 'views_handler_filter_date'; < break; < default: < $filter = 'views_handler_filter_string'; < break; < } < < return $filter; --- > function tw_views_data() { > $tables = _tw_generate_views_table_data(); > return _tw_generate_views_columnar_data($tables); Index: tw_pages.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/tw/tw_pages.inc,v retrieving revision 1.1.2.32 diff -r1.1.2.32 tw_pages.inc 122a123,126 > $form['export'] = array( > '#type' => 'submit', > '#value' => t('Export selected tables'), > ); 160a165 > $output .= drupal_render($form['export']); 180c185,189 < } --- > } > elseif ($type == 'export') { > $twtids = array_values(array_filter($form_state['values']['checks'])); > $form_state['redirect'] = 'admin/content/tw/export/' . implode('-', $twtids); > } 802a812,878 > > function tw_export($twtids = array()) { > require_once drupal_get_path('module', 'tw') . '/tw_tablebuild.inc'; > if (empty($twtids)) { > return drupal_access_denied(); > } > $twtids = explode('-', check_plain($twtids)); > foreach ($twtids as $twtid) { > if (!is_numeric($twtid)) { > // Crude but effecive security measure > return drupal_not_found(); > } > } > return drupal_get_form('tw_export_form', $twtids); > } > > function tw_export_form(&$form_state, $twtids) { > $tables = _tw_generate_views_table_data($twtids, TRUE); > $tables = _tw_generate_views_columnar_data($tables, $twtids); > $code = tw_data_export($tables); > $lines = substr_count($code, "\n"); > $form['code'] = array( > '#type' => 'textarea', > '#title' => t('Table Wizard generated code for hook_views_data() implementation'), > '#default_value' => $code, > '#rows' => $lines + 1, > ); > return $form; > } > > function tw_data_export($tables) { > $output = ' $data = array();' . "\n"; > foreach ($tables as $table => $data) { > $output .= ' $data[\'' . $table . '\'] = '; > $output .= _tw_data_export($data, ' '); > $output .= ";\n"; > } > $output .= ' return $data;'; > return $output; > } > > function _tw_data_export($var, $prefix = '') { > if (is_array($var)) { > if (empty($var)) { > $output = 'array()'; > } > else { > $output = "array(\n"; > foreach ($var as $key => $value) { > $output .= " '$key' => " . _tw_data_export($value, ' ') . ",\n"; > } > $output .= ')'; > } > } > else if (is_bool($var)) { > $output = $var ? 'TRUE' : 'FALSE'; > } > else { > $output = var_export($var, TRUE); > } > > if ($prefix) { > $output = str_replace("\n", "\n$prefix", $output); > } > > return $output; > } Index: tw_tablebuild.inc =================================================================== RCS file: tw_tablebuild.inc diff -N tw_tablebuild.inc 0a1,160 > // $Id$ > > /** > * @file > * Shared functions used by tw's views hook implementations and exporter to > * generate metadata for hook_views_data(). > */ > > /** > * Return a views handler based on the column type. > */ > function _tw_views_handler_type($sqltype) { > preg_match('/^[a-zA-Z]+/', $sqltype, $matches); > $type = tw_column_type($matches[0]); > switch ($type) { > case 'numeric': > $filter = 'views_handler_filter_numeric'; > break; > case 'datetime': > $filter = 'views_handler_filter_date'; > break; > default: > $filter = 'views_handler_filter_string'; > break; > } > > return $filter; > } > > function _tw_generate_views_table_data($twtids = NULL, $export = FALSE) { > $sql = "SELECT * FROM {tw_tables}"; > if (!is_null($twtids)) { > // If a specific subset of tables are requested, add the appropriate > // constraining WHERE clause > $ph = array_fill(0, count($twtids), '%d'); > $sql .= ' WHERE twtid IN (' . implode(', ', $ph) . ')'; > $tblresult = db_query($sql, $twtids); > } > else { > $tblresult = db_query($sql); > } > > // Use slightly different helptext when generating for export vs. tw data hook > $help = $export ? > t('Views data hook implementation generated by the Table Wizard') : > t('Table managed by the Table Wizard'); > > $tables = array(); > while ($tblrow = db_fetch_object($tblresult)) { > // Table Wizard stores the true DB table name - Drupal knows the name without > // the table prefix (if there is one). We'll use the true name for display > $tablename = $tblrow->tablename; > $dbconnection = $tblrow->dbconnection; > if ($dbconnection == 'default') { > $rawtablename = schema_unprefix_table($tablename); > $disptablename = $tablename; > } > else { > $rawtablename = $tablename; > $disptablename = $dbconnection . '.' . $tablename; > } > $twtid = $tblrow->twtid; > $table = array(); > // Add each viewable column to the table definition > // Note that we include the primary key column even if it's empty - this means > // the table is totally empty, and we need to have at least one column present > // to prevent errors in the view > $sql = "SELECT twcid, colname, primarykey, secure, coltype > FROM {tw_columns} > WHERE twtid=%d AND ignorecol=0 > ORDER BY weight"; > $colresult = db_query($sql, $twtid); > $pk = array(); > while ($colrow = db_fetch_object($colresult)) { > $colname = $colrow->colname; > $table[$colname] = array( > 'title' => $colname, > 'help' => $colname, > // TODO: Truncate text at 80 characters. > // TODO: Better yet, do some jQuery magic to expand to the full text > 'field' => array( > 'handler' => 'views_handler_field', > 'click sortable' => TRUE, > ), > 'filter' => array( > 'handler' => _tw_views_handler_type($colrow->coltype), > 'allow empty' => TRUE, > ), > // TODO: Add support for arguments > //'argument' > 'sort' => array( > 'handler' => 'views_handler_sort' > ), > ); > if ($colrow->primarykey) { > $pk[] = $colname; > } > } > // Any table with a single primary key column can be a base table > if (count($pk) == 1) { > $table['table'] = array( > 'group' => t($disptablename), > 'base' => array( > 'field' => $pk[0], > 'title' => t('Database table @tablename', array('@tablename' => $disptablename)), > 'help' => $help, > 'weight' => 10, > 'database' => $dbconnection, > ), > ); > } > $tables[$rawtablename] = $table; > } > return $tables; > } > > function _tw_generate_views_columnar_data($tables, $twtids = NULL) { > $where = is_null($twtids) ? '' : 'WHERE twt1.twtid IN (' . implode(', ', array_fill(0, count($twtids), '%d')) . ') '; > // Now that all tables are present, fill in relationships defined by foreign keys > $sql = "SELECT twt1.tablename tbl1, twc1.colname col1, twt2.tablename tbl2, twc2.colname col2 > FROM {tw_relationships} twr > INNER JOIN {tw_columns} twc1 ON twr.leftcol=twc1.twcid > INNER JOIN {tw_tables} twt1 ON twc1.twtid=twt1.twtid > INNER JOIN {tw_columns} twc2 ON twr.rightcol=twc2.twcid > INNER JOIN {tw_tables} twt2 ON twc2.twtid=twt2.twtid > {$where}ORDER BY tbl1, col1, tbl2, col2"; > $result = is_null($twtids) ? db_query($sql) : db_query($sql, $twtids); > > // To allow multiple joins from one tbl/col, must use an alias and > // 'relationship field' for the left side > $i = 0; > while ($row = db_fetch_array($result)) { > extract($row); > $rawtbl1 = schema_unprefix_table($tbl1); > $rawtbl2 = schema_unprefix_table($tbl2); > if (!isset($tables[$rawtbl1][$col1]['relationship'])) { > $tables[$rawtbl1][$col1]['title'] = t("$col1 (joins to $tbl2)"); > $tables[$rawtbl1][$col1]['relationship'] = array( > 'base' => $rawtbl2, > 'base field' => $col2, > 'label' => t("Join $tbl1 to $tbl2"), > ); > } > else { > $i++; > $mungedcol = $col1 . '_' . $i; > $tables[$rawtbl1][$mungedcol] = $tables[$rawtbl1][$col1]; > $tables[$rawtbl1][$mungedcol]['title'] = t("$col1 (joins to $tbl2)"); > $tables[$rawtbl1][$mungedcol]['real field'] = $col1; > $tables[$rawtbl1][$mungedcol]['relationship'] = array( > 'base' => $rawtbl2, > 'base field' => $col2, > 'relationship field' => $col1, > 'label' => t("Join $tbl1 to $tbl2"), > ); > } > } > return $tables; > }