Merge pull request #1627 from whitepiegon/masterFeature1

feature 844 structure in PDF export
This commit is contained in:
Marc Delisle 2015-04-02 15:34:58 -04:00
commit ca652921bb
3 changed files with 517 additions and 29 deletions

View File

@ -22,6 +22,7 @@ if (! file_exists(TCPDF_INC)) {
require_once 'libraries/plugins/ExportPlugin.class.php';
/* Get the PMA_ExportPdf class */
require_once 'libraries/plugins/export/PMA_ExportPdf.class.php';
require_once 'libraries/transformations.lib.php';
/**
* Handles the export for the PDF class
@ -80,9 +81,8 @@ class ExportPdf extends ExportPlugin
include_once "$props/plugins/ExportPluginProperties.class.php";
include_once "$props/options/groups/OptionsPropertyRootGroup.class.php";
include_once "$props/options/groups/OptionsPropertyMainGroup.class.php";
include_once "$props/options/items/MessageOnlyPropertyItem.class.php";
include_once "$props/options/items/RadioPropertyItem.class.php";
include_once "$props/options/items/TextPropertyItem.class.php";
include_once "$props/options/items/HiddenPropertyItem.class.php";
$exportPluginProperties = new ExportPluginProperties();
$exportPluginProperties->setText('PDF');
@ -101,22 +101,30 @@ class ExportPdf extends ExportPlugin
$generalOptions = new OptionsPropertyMainGroup();
$generalOptions->setName("general_opts");
// create primary items and add them to the group
$leaf = new MessageOnlyPropertyItem();
$leaf->setName("explanation");
$leaf->setText(
__('(Generates a report containing the data of a single table)')
);
$generalOptions->addProperty($leaf);
$leaf = new TextPropertyItem();
$leaf->setName("report_title");
$leaf->setText(__('Report title:'));
$generalOptions->addProperty($leaf);
$leaf = new HiddenPropertyItem();
$leaf->setName("structure_or_data");
$generalOptions->addProperty($leaf);
// add the main group to the root group
// add the group to the root group
$exportSpecificOptions->addProperty($generalOptions);
// what to dump (structure/data/both) main group
$dumpWhat = new OptionsPropertyMainGroup();
$dumpWhat->setName("dump_what");
$dumpWhat->setText(__('Dump table'));
$leaf = new RadioPropertyItem();
$leaf->setName("structure_or_data");
$leaf->setValues(
array(
'structure' => __('structure'),
'data' => __('data'),
'structure_and_data' => __('structure and data')
)
);
$dumpWhat->addProperty($leaf);
// add the group to the root group
$exportSpecificOptions->addProperty($dumpWhat);
// set the options for the export plugin property item
$exportPluginProperties->setOptions($exportSpecificOptions);
$this->properties = $exportPluginProperties;
@ -213,18 +221,107 @@ class ExportPdf extends ExportPlugin
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
$pdf = $this->_getPdf();
$attr = array(
'currentDb' => $db, 'currentTable' => $table,
'dbAlias' => $db_alias, 'tableAlias' => $table_alias,
'aliases' => $aliases
);
$pdf->setAttributes($attr);
$pdf->purpose = __('Dumping Data');
$pdf->mysqlReport($sql_query);
return true;
} // end of the 'PMA_exportData()' function
/**
* Outputs table structure
*
* @param string $db database name
* @param string $table table name
* @param string $crlf the end of line sequence
* @param string $error_url the url to go back in case of error
* @param string $export_mode 'create_table', 'triggers', 'create_view',
* 'stand_in'
* @param string $export_type 'server', 'database', 'table'
* @param bool $do_relation whether to include relation comments
* @param bool $do_comments whether to include the pmadb-style column
* comments as comments in the structure;
* this is deprecated but the parameter is
* left here because export.php calls
* PMA_exportStructure() also for other
* export types which use this parameter
* @param bool $do_mime whether to include mime comments
* @param bool $dates whether to include creation/update/check dates
*
* @return bool Whether it succeeded
*/
public function exportStructure(
$db,
$table,
$crlf,
$error_url,
$export_mode,
$export_type,
$do_relation = false,
$do_comments = false,
$do_mime = false,
$dates = false,
$aliases = array()
) {
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
$pdf = $this->_getPdf();
// getting purpose to show at top
switch($export_mode) {
case 'create_table':
$purpose = __('Table Structure');
break;
case 'triggers':
$purpose = __('Triggers');
break;
case 'create_view':
$purpose = __('View Structure');
break;
case 'stand_in':
$purpose = __('Stand In');
} // end switch
$attr = array(
'currentDb' => $db, 'currentTable' => $table,
'dbAlias' => $db_alias, 'tableAlias' => $table_alias,
'aliases' => $aliases, 'purpose' => $purpose
);
$pdf->setAttributes($attr);
/**
* comment display set true as presently in pdf
* format, no option is present to take user input.
*/
$do_comments = true;
switch($export_mode) {
case 'create_table':
$pdf->getTableDef(
$db, $table, $do_relation, $do_comments, $do_mime, false, $aliases
);
break;
case 'triggers':
$pdf->getTriggers($db, $table);
break;
case 'create_view':
$pdf->getTableDef(
$db, $table, $do_relation, $do_comments, $do_mime, false, $aliases
);
break;
case 'stand_in':
/* export a stand-in definition to resolve view dependencies
* Yet to develop this function
* $pdf->getTableDefStandIn($db, $table, $crlf);
*/
} // end switch
return true;
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */

View File

@ -114,7 +114,8 @@ class PMA_ExportPdf extends PMA_PDF
0,
$this->FontSizePt,
__('Database:') . ' ' . $this->dbAlias . ', '
. __('Table:') . ' ' . $this->tableAlias,
. __('Table:') . ' ' . $this->tableAlias . ', '
. __('Purpose:') . ' ' . $this->purpose,
0, 1, 'L'
);
$l = ($this->lMargin);
@ -273,6 +274,374 @@ class PMA_ExportPdf extends PMA_PDF
$this->tMargin = $topMargin;
}
/**
* Prints triggers
*
* @param string $db database name
* @param string $table table name
*/
public function getTriggers($db, $table)
{
$i=0;
$triggers = $GLOBALS['dbi']->getTriggers($db, $table);
foreach ($triggers as $trigger) {
$i++; break;
}
if ($i==0) return; //prevents printing blank trigger list for any table
unset($this->tablewidths);
unset($this->colTitles);
unset($this->titleWidth);
unset($this->colFits);
unset($this->display_column);
unset($this->colAlign);
/**
* Making table heading
* Keeping column width constant
*/
$this->colTitles[0] = __('Name');
$this->tablewidths[0] = 90;
$this->colTitles[1] = __('Time');
$this->tablewidths[1] = 80;
$this->colTitles[2] = __('Event');
$this->tablewidths[2] = 40;
$this->colTitles[3] = __('Definition');
$this->tablewidths[3] = 240;
for ($columns_cnt = 0; $columns_cnt < 4; $columns_cnt++) {
$this->colAlign[$columns_cnt] = 'L';
$this->display_column[$columns_cnt] = true;
}
// Starting to fill table with required info
$this->setY($this->tMargin);
$this->AddPage();
$this->SetFont(PMA_PDF_FONT, '', 9);
$l = $this->lMargin;
$startheight = $h = $this->dataY;
$startpage = $currpage = $this->page;
// calculate the whole width
$fullwidth = 0;
foreach ($this->tablewidths as $width) {
$fullwidth += $width;
}
$row = 0;
$tmpheight = array();
$maxpage = $this->page;
$triggers = $GLOBALS['dbi']->getTriggers($db, $table);
foreach ($triggers as $trigger) {
$data [] = $trigger['name'];
$data [] = $trigger['action_timing'];
$data [] = $trigger['event_manipulation'];
$data [] = $trigger['definition'];
$this->page = $currpage;
// write the horizontal borders
$this->Line($l, $h, $fullwidth+$l, $h);
// write the content and remember the height of the highest col
foreach ($data as $col => $txt) {
$this->page = $currpage;
$this->SetXY($l, $h);
if ($this->tablewidths[$col] > 0) {
$this->MultiCell(
$this->tablewidths[$col],
$this->FontSizePt,
$txt,
0,
$this->colAlign[$col]
);
$l += $this->tablewidths[$col];
}
if (! isset($tmpheight[$row . '-' . $this->page])) {
$tmpheight[$row . '-' . $this->page] = 0;
}
if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) {
$tmpheight[$row . '-' . $this->page] = $this->GetY();
}
if ($this->page > $maxpage) {
$maxpage = $this->page;
}
}
// get the height we were in the last used page
$h = $tmpheight[$row . '-' . $maxpage];
// set the "pointer" to the left margin
$l = $this->lMargin;
// set the $currpage to the last page
$currpage = $maxpage;
unset($data);
$row++;
}
// draw the borders
// we start adding a horizontal line on the last page
$this->page = $maxpage;
$this->Line($l, $h, $fullwidth+$l, $h);
// now we start at the top of the document and walk down
for ($i = $startpage; $i <= $maxpage; $i++) {
$this->page = $i;
$l = $this->lMargin;
$t = ($i == $startpage) ? $startheight : $this->tMargin;
$lh = ($i == $maxpage) ? $h : $this->h-$this->bMargin;
$this->Line($l, $t, $l, $lh);
foreach ($this->tablewidths as $width) {
$l += $width;
$this->Line($l, $t, $l, $lh);
}
}
// set it to the last page, if not it'll cause some problems
$this->page = $maxpage;
}
/**
* Print $table's CREATE definition
*
* @param string $db the database name
* @param string $table the table name
* @param bool $do_relation whether to include relation comments
* @param bool $do_comments whether to include the pmadb-style column
* comments as comments in the structure;
* this is deprecated but the parameter is
* left here because export.php calls
* PMA_exportStructure() also for other
* export types which use this parameter
* @param bool $do_mime whether to include mime comments
* @param bool $view whether we're handling a view
* @param bool $aliases Aliases of db/table/columns
*/
public function getTableDef(
$db,
$table,
$do_relation,
$do_comments,
$do_mime,
$view = false,
$aliases = array()
) {
// set $cfgRelation here, because there is a chance that it's modified
// since the class initialization
global $cfgRelation;
unset($this->tablewidths);
unset($this->colTitles);
unset($this->titleWidth);
unset($this->colFits);
unset($this->display_column);
unset($this->colAlign);
/**
* Gets fields properties
*/
$GLOBALS['dbi']->selectDb($db);
/**
* All these three checks do_relation, do_comment and do_mime is
* not required. As presently all are set true by default.
* But when, methods to take user input will be developed,
* it will be of use
*/
// Check if we can use Relations
if ($do_relation) {
// Find which tables are related with the current one and write it in
// an array
$res_rel = PMA_getForeigners($db, $table);
if ($res_rel && count($res_rel) > 0) {
$have_rel = true;
} else {
$have_rel = false;
}
} else {
$have_rel = false;
} // end if
//column count and table heading
$this->colTitles[0] = __('Column');
$this->tablewidths[0] = 90;
$this->colTitles[1] = __('Type');
$this->tablewidths[1] = 80;
$this->colTitles[2] = __('Null');
$this->tablewidths[2] = 40;
$this->colTitles[3] = __('Default');
$this->tablewidths[3] = 120;
for ($columns_cnt = 0; $columns_cnt < 4; $columns_cnt++) {
$this->colAlign[$columns_cnt] = 'L';
$this->display_column[$columns_cnt] = true;
}
if ($do_relation && $have_rel) {
$this->colTitles[$columns_cnt] = __('Links to');
$this->display_column[$columns_cnt] = true;
$this->colAlign[$columns_cnt] = 'L';
$this->tablewidths[$columns_cnt] = 120;
$columns_cnt++;
}
if ($do_comments /*&& $cfgRelation['commwork']*/) {
$this->colTitles[$columns_cnt] = __('Comments');
$this->display_column[$columns_cnt] = true;
$this->colAlign[$columns_cnt] = 'L';
$this->tablewidths[$columns_cnt] = 120;
$columns_cnt++;
}
if ($do_mime && $cfgRelation['mimework']) {
$this->colTitles[$columns_cnt] = __('MIME');
$this->display_column[$columns_cnt] = true;
$this->colAlign[$columns_cnt] = 'L';
$this->tablewidths[$columns_cnt] = 120;
$columns_cnt++;
}
// Starting to fill table with required info
$this->setY($this->tMargin);
$this->AddPage();
$this->SetFont(PMA_PDF_FONT, '', 9);
// Now let's start to write the table structure
if ($do_comments) {
$comments = PMA_getComments($db, $table);
}
if ($do_mime && $cfgRelation['mimework']) {
$mime_map = PMA_getMIME($db, $table, true);
}
$columns = $GLOBALS['dbi']->getColumns($db, $table);
/**
* Get the unique keys in the table.
* Presently, this information is not used. We will have to find out
* way of displaying it.
*/
$unique_keys = array();
$keys = $GLOBALS['dbi']->getTableIndexes($db, $table);
foreach ($keys as $key) {
if ($key['Non_unique'] == 0) {
$unique_keys[] = $key['Column_name'];
}
}
// some things to set and 'remember'
$l = $this->lMargin;
$startheight = $h = $this->dataY;
$startpage = $currpage = $this->page;
// calculate the whole width
$fullwidth = 0;
foreach ($this->tablewidths as $width) {
$fullwidth += $width;
}
$row = 0;
$tmpheight = array();
$maxpage = $this->page;
// fun begin
foreach ($columns as $column) {
$extracted_columnspec
= PMA_Util::extractColumnSpec($column['Type']);
$type = $extracted_columnspec['print_type'];
if (empty($type)) {
$type = ' ';
}
if (! isset($column['Default'])) {
if ($column['Null'] != 'NO') {
$column['Default'] = 'NULL';
}
}
$data [] = $column['Field'];
$data [] = $type;
$data [] = ($column['Null'] == '' || $column['Null'] == 'NO')
? 'No'
: 'Yes';
$data [] = isset($column['Default']) ? $column['Default'] : '';
$field_name = $column['Field'];
if ($do_relation && $have_rel) {
$data [] = isset($res_rel[$field_name])
? $res_rel[$field_name]['foreign_table']
. ' (' . $res_rel[$field_name]['foreign_field']
. ')'
: '';
}
if ($do_comments) {
$data [] = isset($comments[$field_name])
? $comments[$field_name]
: '';
}
if ($do_mime) {
$data [] = isset($mime_map[$field_name])
? $mime_map[$field_name]['mimetype']
: '';
}
$this->page = $currpage;
// write the horizontal borders
$this->Line($l, $h, $fullwidth+$l, $h);
// write the content and remember the height of the highest col
foreach ($data as $col => $txt) {
$this->page = $currpage;
$this->SetXY($l, $h);
if ($this->tablewidths[$col] > 0) {
$this->MultiCell(
$this->tablewidths[$col],
$this->FontSizePt,
$txt,
0,
$this->colAlign[$col]
);
$l += $this->tablewidths[$col];
}
if (! isset($tmpheight[$row . '-' . $this->page])) {
$tmpheight[$row . '-' . $this->page] = 0;
}
if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) {
$tmpheight[$row . '-' . $this->page] = $this->GetY();
}
if ($this->page > $maxpage) {
$maxpage = $this->page;
}
}
// get the height we were in the last used page
$h = $tmpheight[$row . '-' . $maxpage];
// set the "pointer" to the left margin
$l = $this->lMargin;
// set the $currpage to the last page
$currpage = $maxpage;
unset($data);
$row++;
}
// draw the borders
// we start adding a horizontal line on the last page
$this->page = $maxpage;
$this->Line($l, $h, $fullwidth+$l, $h);
// now we start at the top of the document and walk down
for ($i = $startpage; $i <= $maxpage; $i++) {
$this->page = $i;
$l = $this->lMargin;
$t = ($i == $startpage) ? $startheight : $this->tMargin;
$lh = ($i == $maxpage) ? $h : $this->h-$this->bMargin;
$this->Line($l, $t, $l, $lh);
foreach ($this->tablewidths as $width) {
$l += $width;
$this->Line($l, $t, $l, $lh);
}
}
// set it to the last page, if not it'll cause some problems
$this->page = $maxpage;
}
/**
* MySQL report
*

View File

@ -13,7 +13,6 @@ require_once 'libraries/Theme.class.php';
require_once 'libraries/Config.class.php';
require_once 'libraries/php-gettext/gettext.inc';
require_once 'libraries/config.default.php';
require_once 'libraries/properties/options/items/MessageOnlyPropertyItem.class.php';
require_once 'export.php';
/**
* tests for ExportPdf class
@ -108,7 +107,8 @@ class PMA_ExportPdf_Test extends PHPUnit_Framework_TestCase
);
$generalOptionsArray = $options->getProperties();
$generalOptions = $generalOptionsArray[0];
$generalOptions = array_shift($generalOptionsArray);
$this->assertInstanceOf(
'OptionsPropertyMainGroup',
@ -124,18 +124,6 @@ class PMA_ExportPdf_Test extends PHPUnit_Framework_TestCase
$property = array_shift($generalProperties);
$this->assertInstanceOf(
'MessageOnlyPropertyItem',
$property
);
$this->assertEquals(
'explanation',
$property->getName()
);
$property = array_shift($generalProperties);
$this->assertInstanceOf(
'TextPropertyItem',
$property
@ -146,12 +134,46 @@ class PMA_ExportPdf_Test extends PHPUnit_Framework_TestCase
$property->getName()
);
$generalOptions = array_shift($generalOptionsArray);
$this->assertInstanceOf(
'OptionsPropertyMainGroup',
$generalOptions
);
$this->assertEquals(
'dump_what',
$generalOptions->getName()
);
$this->assertEquals(
'Dump table',
$generalOptions->getText()
);
$generalProperties = $generalOptions->getProperties();
$property = array_shift($generalProperties);
$this->assertInstanceOf(
'HiddenPropertyItem',
'RadioPropertyItem',
$property
);
$this->assertEquals(
'structure_or_data',
$property->getName()
);
$this->assertEquals(
array(
'structure' => __('structure'),
'data' => __('data'),
'structure_and_data' => __('structure and data')
),
$property->getValues()
);
}
/**