? 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
> <?php
> // $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;
> }
