2 /* vim: set expandtab sw=4 ts=4 sts=4: */
8 include_once("Export_Relation_Schema.class.php");
11 * This Class is EPS Library and
12 * helps in developing structure of EPS Schema Export
18 * @see http://php.net/manual/en/book.xmlwriter.php
25 public $stringCommands;
28 * The "PMA_EPS" constructor
30 * Upon instantiation This starts writing the EPS Document.
31 * %!PS-Adobe-3.0 EPSF-3.0 This is the MUST first comment to include
32 * it shows/tells that the Post Script document is purely under
33 * Document Structuring Convention [DSC] and is Compliant
34 * Encapsulated Post Script Document
39 function __construct()
41 $this->stringCommands
= "";
42 $this->stringCommands
.= "%!PS-Adobe-3.0 EPSF-3.0 \n";
48 * @param string value sets the title text
52 function setTitle($value)
54 $this->stringCommands
.= '%%Title: ' . $value . "\n";
60 * @param string value sets the author
64 function setAuthor($value)
66 $this->stringCommands
.= '%%Creator: ' . $value . "\n";
70 * Set document creation date
72 * @param string value sets the date
76 function setDate($value)
78 $this->stringCommands
.= '%%CreationDate: ' . $value . "\n";
82 * Set document orientation
84 * @param string value sets the author
88 function setOrientation($value)
90 $this->stringCommands
.= "%%PageOrder: Ascend \n";
93 $this->stringCommands
.= '%%Orientation: ' . $value . "\n";
96 $this->stringCommands
.= '%%Orientation: ' . $value . "\n";
98 $this->stringCommands
.= "%%EndComments \n";
99 $this->stringCommands
.= "%%Pages 1 \n";
100 $this->stringCommands
.= "%%BoundingBox: 72 150 144 170 \n";
104 * Set the font and size
106 * font can be set whenever needed in EPS
108 * @param string value sets the font name e.g Arial
109 * @param integer value sets the size of the font e.g 10
113 function setFont($value,$size)
115 $this->font
= $value;
116 $this->fontSize
= $size;
117 $this->stringCommands
.= "/".$value." findfont % Get the basic font\n";
118 $this->stringCommands
.= "".$size." scalefont % Scale the font to $size points\n";
119 $this->stringCommands
.= "setfont % Make it the current font\n";
125 * @return string return the font name e.g Arial
136 * @return string return the size of the font e.g 10
139 function getFontSize()
141 return $this->fontSize
;
147 * drawing the lines from x,y source to x,y destination and set the
148 * width of the line. lines helps in showing relationships of tables
150 * @param integer x_from The x_from attribute defines the start
151 left position of the element
152 * @param integer y_from The y_from attribute defines the start
153 right position of the element
154 * @param integer x_to The x_to attribute defines the end
155 left position of the element
156 * @param integer y_to The y_to attribute defines the end
157 right position of the element
158 * @param integer lineWidth sets the width of the line e.g 2
162 function line($x_from=0, $y_from=0, $x_to=0, $y_to=0, $lineWidth=0)
164 $this->stringCommands
.= $lineWidth . " setlinewidth \n";
165 $this->stringCommands
.= $x_from . ' ' . $y_from . " moveto \n";
166 $this->stringCommands
.= $x_to . ' ' . $y_to . " lineto \n";
167 $this->stringCommands
.= "stroke \n";
173 * drawing the rectangle from x,y source to x,y destination and set the
174 * width of the line. rectangles drawn around the text shown of fields
176 * @param integer x_from The x_from attribute defines the start
177 left position of the element
178 * @param integer y_from The y_from attribute defines the start
179 right position of the element
180 * @param integer x_to The x_to attribute defines the end
181 left position of the element
182 * @param integer y_to The y_to attribute defines the end
183 right position of the element
184 * @param integer lineWidth sets the width of the line e.g 2
188 function rect($x_from, $y_from, $x_to, $y_to, $lineWidth)
190 $this->stringCommands
.= $lineWidth . " setlinewidth \n";
191 $this->stringCommands
.= "newpath \n";
192 $this->stringCommands
.= $x_from . " " . $y_from . " moveto \n";
193 $this->stringCommands
.= "0 " . $y_to . " rlineto \n";
194 $this->stringCommands
.= $x_to . " 0 rlineto \n";
195 $this->stringCommands
.= "0 -" . $y_to . " rlineto \n";
196 $this->stringCommands
.= "closepath \n";
197 $this->stringCommands
.= "stroke \n";
201 * Set the current point
203 * The moveto operator takes two numbers off the stack and treats
204 * them as x and y coordinates to which to move. The coordinates
205 * specified become the current point.
207 * @param integer x The x attribute defines the
208 left position of the element
209 * @param integer y The y attribute defines the
210 right position of the element
214 function moveTo($x, $y)
216 $this->stringCommands
.= $x . ' ' . $y . " moveto \n";
220 * Output/Display the text
222 * @param string text The string to be displayed
228 $this->stringCommands
.= '(' . $text . ") show \n";
232 * Output the text at specified co-ordinates
234 * @param string text The string to be displayed
235 * @param integer x The x attribute defines the
236 left position of the element
237 * @param integer y The y attribute defines the
238 right position of the element
242 function showXY($text, $x, $y)
244 $this->moveTo($x, $y);
249 * get width of string/text
251 * EPS text width is calcualted depending on font name
252 * and font size. It is very important to know the width of text
253 * because rectangle is drawn around it.
255 * This is a bit hardcore method. I didn't found any other better than this.
256 * if someone found better than this. would love to hear that method
258 * @param string text string that width will be calculated
259 * @param integer font name of the font like Arial,sans-serif etc
260 * @param integer fontSize size of font
261 * @return integer width of the text
264 function getStringWidth($text,$font,$fontSize)
267 * Start by counting the width, giving each character a modifying value
270 $count = $count +
((strlen($text) - strlen(str_replace(array("i","j","l"),"",$text)))*0.23);//ijl
271 $count = $count +
((strlen($text) - strlen(str_replace(array("f"),"",$text)))*0.27);//f
272 $count = $count +
((strlen($text) - strlen(str_replace(array("t","I"),"",$text)))*0.28);//tI
273 $count = $count +
((strlen($text) - strlen(str_replace(array("r"),"",$text)))*0.34);//r
274 $count = $count +
((strlen($text) - strlen(str_replace(array("1"),"",$text)))*0.49);//1
275 $count = $count +
((strlen($text) - strlen(str_replace(array("c","k","s","v","x","y","z","J"),"",$text)))*0.5);//cksvxyzJ
276 $count = $count +
((strlen($text) - strlen(str_replace(array("a","b","d","e","g","h","n","o","p","q","u","L","0","2","3","4","5","6","7","8","9"),"",$text)))*0.56);//abdeghnopquL023456789
277 $count = $count +
((strlen($text) - strlen(str_replace(array("F","T","Z"),"",$text)))*0.61);//FTZ
278 $count = $count +
((strlen($text) - strlen(str_replace(array("A","B","E","K","P","S","V","X","Y"),"",$text)))*0.67);//ABEKPSVXY
279 $count = $count +
((strlen($text) - strlen(str_replace(array("w","C","D","H","N","R","U"),"",$text)))*0.73);//wCDHNRU
280 $count = $count +
((strlen($text) - strlen(str_replace(array("G","O","Q"),"",$text)))*0.78);//GOQ
281 $count = $count +
((strlen($text) - strlen(str_replace(array("m","M"),"",$text)))*0.84);//mM
282 $count = $count +
((strlen($text) - strlen(str_replace("W","",$text)))*.95);//W
283 $count = $count +
((strlen($text) - strlen(str_replace(" ","",$text)))*.28);//" "
284 $text = str_replace(" ","",$text);//remove the " "'s
285 $count = $count +
(strlen(preg_replace("/[a-z0-9]/i","",$text))*0.3); //all other chrs
288 $font = strtolower($font);
291 * no modifier for arial and sans-serif
297 * .92 modifer for time, serif, brushscriptstd, and californian fb
301 case 'brushscriptstd':
302 case 'californian fb':
306 * 1.23 modifier for broadway
312 $textWidth = $count*$fontSize;
313 return ceil($textWidth*$modifier);
324 $this->stringCommands
.= "showpage \n";
328 * Output EPS Document for download
330 * @param string fileName name of the eps document
334 function showOutput($fileName)
336 // if(ob_get_clean()){
339 header('Content-type: image/x-eps');
340 header('Content-Disposition: attachment; filename="'.$fileName.'.eps"');
341 $output = $this->stringCommands
;
347 * Table preferences/statistics
349 * This class preserves the table co-ordinates,fields
350 * and helps in drawing/generating the Tables in EPS.
364 private $_showInfo = false;
368 public $fields = array();
369 public $heightCell = 0;
370 public $currentCell = 0;
372 public $primary = array();
375 * The "Table_Stats" constructor
377 * @param string tableName The table name
378 * @param string font The font name
379 * @param integer fontSize The font size
380 * @param integer same_wide_width The max width among tables
381 * @param boolean showKeys Whether to display keys or not
382 * @param boolean showInfo Whether to display table position or not
383 * @global object The current eps document
384 * @global integer The current page number (from the
385 * $cfg['Servers'][$i]['table_coords'] table)
386 * @global array The relations settings
387 * @global string The current db name
389 * @see PMA_EPS, Table_Stats::Table_Stats_setWidth,
390 Table_Stats::Table_Stats_setHeight
392 function __construct($tableName, $font, $fontSize, $pageNumber, &$same_wide_width, $showKeys = false, $showInfo = false)
394 global $eps, $cfgRelation, $db;
396 $this->_tableName
= $tableName;
397 $sql = 'DESCRIBE ' . PMA_backquote($tableName);
398 $result = PMA_DBI_try_query($sql, null, PMA_DBI_QUERY_STORE
);
399 if (!$result ||
!PMA_DBI_num_rows($result)) {
400 $eps->dieSchema($pageNumber,"EPS",sprintf(__('The %s table doesn\'t exist!'), $tableName));
405 * check to see if it will load all fields or only the foreign keys
408 $indexes = PMA_Index
::getFromTable($this->_tableName
, $db);
409 $all_columns = array();
410 foreach ($indexes as $index) {
411 $all_columns = array_merge($all_columns, array_flip(array_keys($index->getColumns())));
413 $this->fields
= array_keys($all_columns);
415 while ($row = PMA_DBI_fetch_row($result)) {
416 $this->fields
[] = $row[0];
420 $this->_showInfo
= $showInfo;
423 $this->_setHeightTable($fontSize);
425 // setWidth must me after setHeight, because title
426 // can include table height which changes table width
427 $this->_setWidthTable($font,$fontSize);
428 if ($same_wide_width < $this->width
) {
429 $same_wide_width = $this->width
;
433 $sql = 'SELECT x, y FROM '
434 . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($cfgRelation['table_coords'])
435 . ' WHERE db_name = \'' . PMA_sqlAddslashes($db) . '\''
436 . ' AND table_name = \'' . PMA_sqlAddslashes($tableName) . '\''
437 . ' AND pdf_page_number = ' . $pageNumber;
438 $result = PMA_query_as_controluser($sql, false, PMA_DBI_QUERY_STORE
);
440 if (!$result ||
!PMA_DBI_num_rows($result)) {
441 $eps->dieSchema($pageNumber,"EPS",sprintf(__('Please configure the coordinates for table %s'), $tableName));
443 list($this->x
, $this->y
) = PMA_DBI_fetch_row($result);
444 $this->x
= (double) $this->x
;
445 $this->y
= (double) $this->y
;
447 $this->displayfield
= PMA_getDisplayField($db, $tableName);
449 $result = PMA_DBI_query('SHOW INDEX FROM ' . PMA_backquote($tableName) . ';', null, PMA_DBI_QUERY_STORE
);
450 if (PMA_DBI_num_rows($result) > 0) {
451 while ($row = PMA_DBI_fetch_assoc($result)) {
452 if ($row['Key_name'] == 'PRIMARY') {
453 $this->primary
[] = $row['Column_name'];
460 * Returns title of the current table,
461 * title can have the dimensions/co-ordinates of the table
463 * @return string The relation/table name
466 private function _getTitle()
468 return ($this->_showInfo ?
sprintf('%.0f', $this->width
) . 'x' . sprintf('%.0f', $this->heightCell
) : '') . ' ' . $this->_tableName
;
472 * Sets the width of the table
474 * @param string font The font name
475 * @param integer fontSize The font size
476 * @global object The current eps document
481 private function _setWidthTable($font,$fontSize)
485 foreach ($this->fields
as $field) {
486 $this->width
= max($this->width
, $eps->getStringWidth($field,$font,$fontSize));
488 $this->width +
= $eps->getStringWidth(' ',$font,$fontSize);
490 * it is unknown what value must be added, because
491 * table title is affected by the tabe width value
493 while ($this->width
< $eps->getStringWidth($this->_getTitle(),$font,$fontSize)) {
499 * Sets the height of the table
501 * @param integer fontSize The font size
505 private function _setHeightTable($fontSize)
507 $this->heightCell
= $fontSize +
4;
508 $this->height
= (count($this->fields
) +
1) * $this->heightCell
;
514 * @param boolean showColor Whether to display color
515 * @global object The current eps document
518 * @see PMA_EPS,PMA_EPS::line,PMA_EPS::rect
520 public function tableDraw($showColor)
523 //echo $this->_tableName.'<br />';
524 $eps->rect($this->x
,$this->y +
12,
525 $this->width
,$this->heightCell
,
528 $eps->showXY($this->_getTitle(),$this->x +
5,$this->y +
14);
529 foreach ($this->fields
as $field) {
530 $this->currentCell +
= $this->heightCell
;
533 if (in_array($field, $this->primary
)) {
536 if ($field == $this->displayfield
) {
540 $eps->rect($this->x
,$this->y +
12 +
$this->currentCell
,
541 $this->width
, $this->heightCell
,1);
542 $eps->showXY($field, $this->x +
5, $this->y +
14 +
$this->currentCell
);
548 * Relation preferences/statistics
550 * This class fetches the table master and foreign fields positions
551 * and helps in generating the Table references and then connects
552 * master table's master field to foreign table's foreign key
555 * @name Relation_Stats
568 public $xDest, $yDest;
572 * The "Relation_Stats" constructor
574 * @param string master_table The master table name
575 * @param string master_field The relation field in the master table
576 * @param string foreign_table The foreign table name
577 * @param string foreigh_field The relation field in the foreign table
578 * @see Relation_Stats::_getXy
580 function __construct($master_table, $master_field, $foreign_table, $foreign_field)
582 $src_pos = $this->_getXy($master_table, $master_field);
583 $dest_pos = $this->_getXy($foreign_table, $foreign_field);
589 $src_left = $src_pos[0] - $this->wTick
;
590 $src_right = $src_pos[1] +
$this->wTick
;
591 $dest_left = $dest_pos[0] - $this->wTick
;
592 $dest_right = $dest_pos[1] +
$this->wTick
;
594 $d1 = abs($src_left - $dest_left);
595 $d2 = abs($src_right - $dest_left);
596 $d3 = abs($src_left - $dest_right);
597 $d4 = abs($src_right - $dest_right);
598 $d = min($d1, $d2, $d3, $d4);
601 $this->xSrc
= $src_pos[0];
603 $this->xDest
= $dest_pos[0];
605 } elseif ($d == $d2) {
606 $this->xSrc
= $src_pos[1];
608 $this->xDest
= $dest_pos[0];
610 } elseif ($d == $d3) {
611 $this->xSrc
= $src_pos[0];
613 $this->xDest
= $dest_pos[1];
616 $this->xSrc
= $src_pos[1];
618 $this->xDest
= $dest_pos[1];
621 $this->ySrc
= $src_pos[2] +
10;
622 $this->yDest
= $dest_pos[2] +
10;
626 * Gets arrows coordinates
628 * @param string table The current table name
629 * @param string column The relation column name
630 * @return array Arrows coordinates
633 private function _getXy($table, $column)
635 $pos = array_search($column, $table->fields
);
636 // x_left, x_right, y
637 return array($table->x
, $table->x +
$table->width
, $table->y +
($pos +
1.5) * $table->heightCell
);
641 * draws relation links and arrows
642 * shows foreign key relations
644 * @param boolean changeColor Whether to use one color per relation or not
645 * @global object The current EPS document
649 public function relationDraw($changeColor)
654 $listOfColors = array(
663 shuffle($listOfColors);
664 $color = $listOfColors[0];
668 // draw a line like -- to foreign field
669 $eps->line($this->xSrc
,$this->ySrc
,
670 $this->xSrc +
$this->srcDir
* $this->wTick
,$this->ySrc
,
673 // draw a line like -- to master field
674 $eps->line($this->xDest +
$this->destDir
* $this->wTick
, $this->yDest
,
675 $this->xDest
, $this->yDest
,
678 // draw a line that connects to master field line and foreign field line
679 $eps->line($this->xSrc +
$this->srcDir
* $this->wTick
,$this->ySrc
,
680 $this->xDest +
$this->destDir
* $this->wTick
, $this->yDest
,
683 $root2 = 2 * sqrt(2);
684 $eps->line($this->xSrc +
$this->srcDir
* $this->wTick
* 0.75, $this->ySrc
,
685 $this->xSrc +
$this->srcDir
* (0.75 - 1 / $root2) * $this->wTick
,
686 $this->ySrc +
$this->wTick
/ $root2 ,
689 $eps->line($this->xSrc +
$this->srcDir
* $this->wTick
* 0.75, $this->ySrc
,
690 $this->xSrc +
$this->srcDir
* (0.75 - 1 / $root2) * $this->wTick
,
691 $this->ySrc
- $this->wTick
/ $root2 ,
694 $eps->line($this->xDest +
$this->destDir
* $this->wTick
/ 2 , $this->yDest
,
695 $this->xDest +
$this->destDir
* (0.5 +
1 / $root2) * $this->wTick
,
696 $this->yDest +
$this->wTick
/ $root2 ,
698 $eps->line($this->xDest +
$this->destDir
* $this->wTick
/ 2 ,
699 $this->yDest
, $this->xDest +
$this->destDir
* (0.5 +
1 / $root2) * $this->wTick
,
700 $this->yDest
- $this->wTick
/ $root2 ,
706 * end of the "Relation_Stats" class
710 * EPS Relation Schema Class
712 * Purpose of this class is to generate the EPS Document
713 * which is used for representing the database diagrams.
714 * This class uses post script commands and with
715 * the combination of these commands actually helps in preparing EPS Document.
717 * This class inherits Export_Relation_Schema class has common functionality added
720 * @name Eps_Relation_Schema
724 class PMA_Eps_Relation_Schema
extends PMA_Export_Relation_Schema
726 private $tables = array();
727 private $_relations = array();
730 * The "PMA_EPS_Relation_Schema" constructor
732 * Upon instantiation This starts writing the EPS document
733 * user will be prompted for download as .eps extension
738 function __construct()
742 $this->setPageNumber($_POST['pdf_page_number']);
743 $this->setShowColor(isset($_POST['show_color']));
744 $this->setShowKeys(isset($_POST['show_keys']));
745 $this->setTableDimension(isset($_POST['show_table_dimension']));
746 $this->setAllTableSameWidth(isset($_POST['all_table_same_wide']));
747 $this->setOrientation($_POST['orientation']);
748 $this->setExportType($_POST['export_type']);
750 $eps = new PMA_EPS();
751 $eps->setTitle(sprintf(__('Schema of the %s database - Page %s'), $db, $this->pageNumber
));
752 $eps->setAuthor('phpMyAdmin ' . PMA_VERSION
);
753 $eps->setDate(date("j F Y, g:i a"));
754 $eps->setOrientation($this->orientation
);
755 $eps->setFont('Verdana','10');
759 $alltables = $this->getAllTables($db,$this->pageNumber
);
761 foreach ($alltables AS $table) {
762 if (!isset($this->tables
[$table])) {
763 $this->tables
[$table] = new Table_Stats($table,$eps->getFont(),$eps->getFontSize(), $this->pageNumber
, $this->_tablewidth
, $this->showKeys
, $this->tableDimension
);
766 if ($this->sameWide
) {
767 $this->tables
[$table]->width
= $this->_tablewidth
;
771 $seen_a_relation = false;
772 foreach ($alltables as $one_table) {
773 $exist_rel = PMA_getForeigners($db, $one_table, '', 'both');
775 $seen_a_relation = true;
776 foreach ($exist_rel as $master_field => $rel) {
777 /* put the foreign table on the schema only if selected
779 * (do not use array_search() because we would have to
780 * to do a === FALSE and this is not PHP3 compatible)
782 if (in_array($rel['foreign_table'], $alltables)) {
783 $this->_addRelation($one_table,$eps->getFont(),$eps->getFontSize(), $master_field, $rel['foreign_table'], $rel['foreign_field'], $this->tableDimension
);
788 if ($seen_a_relation) {
789 $this->_drawRelations($this->showColor
);
792 $this->_drawTables($this->showColor
);
794 $eps->showOutput($db.'-'.$this->pageNumber
);
799 * Defines relation objects
801 * @param string masterTable The master table name
802 * @param string masterField The relation field in the master table
803 * @param string foreignTable The foreign table name
804 * @param string foreignField The relation field in the foreign table
805 * @param boolean showInfo Whether to display table position or not
808 * @see _setMinMax,Table_Stats::__construct(),Relation_Stats::__construct()
810 private function _addRelation($masterTable,$font,$fontSize, $masterField, $foreignTable, $foreignField, $showInfo)
812 if (!isset($this->tables
[$masterTable])) {
813 $this->tables
[$masterTable] = new Table_Stats($masterTable, $font, $fontSize, $this->pageNumber
, $this->_tablewidth
, false, $showInfo);
815 if (!isset($this->tables
[$foreignTable])) {
816 $this->tables
[$foreignTable] = new Table_Stats($foreignTable,$font,$fontSize,$this->pageNumber
, $this->_tablewidth
, false, $showInfo);
818 $this->_relations
[] = new Relation_Stats($this->tables
[$masterTable], $masterField, $this->tables
[$foreignTable], $foreignField);
822 * Draws relation arrows and lines
823 * connects master table's master field to
824 * foreign table's forein field
826 * @param boolean changeColor Whether to use one color per relation or not
829 * @see Relation_Stats::relationDraw()
831 private function _drawRelations($changeColor)
833 foreach ($this->_relations
as $relation) {
834 $relation->relationDraw($changeColor);
841 * @param boolean changeColor Whether to show color for primary fields or not
844 * @see Table_Stats::Table_Stats_tableDraw()
846 private function _drawTables($changeColor)
848 foreach ($this->tables
as $table) {
849 $table->tableDraw($changeColor);