From 04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 9 Jan 2020 10:55:03 +0100 Subject: phpmyadmin working --- .../libraries/classes/Plugins/Schema/Dia/Dia.php | 190 +++++ .../Plugins/Schema/Dia/DiaRelationSchema.php | 238 ++++++ .../Plugins/Schema/Dia/RelationStatsDia.php | 228 ++++++ .../classes/Plugins/Schema/Dia/TableStatsDia.php | 231 ++++++ .../libraries/classes/Plugins/Schema/Eps/Eps.php | 280 ++++++++ .../Plugins/Schema/Eps/EpsRelationSchema.php | 254 +++++++ .../Plugins/Schema/Eps/RelationStatsEps.php | 120 ++++ .../classes/Plugins/Schema/Eps/TableStatsEps.php | 183 +++++ .../Plugins/Schema/ExportRelationSchema.php | 310 ++++++++ .../libraries/classes/Plugins/Schema/Pdf/Pdf.php | 422 +++++++++++ .../Plugins/Schema/Pdf/PdfRelationSchema.php | 798 +++++++++++++++++++++ .../Plugins/Schema/Pdf/RelationStatsPdf.php | 163 +++++ .../classes/Plugins/Schema/Pdf/TableStatsPdf.php | 233 ++++++ .../classes/Plugins/Schema/RelationStats.php | 120 ++++ .../libraries/classes/Plugins/Schema/SchemaDia.php | 100 +++ .../libraries/classes/Plugins/Schema/SchemaEps.php | 101 +++ .../libraries/classes/Plugins/Schema/SchemaPdf.php | 133 ++++ .../libraries/classes/Plugins/Schema/SchemaSvg.php | 88 +++ .../Plugins/Schema/Svg/RelationStatsSvg.php | 140 ++++ .../libraries/classes/Plugins/Schema/Svg/Svg.php | 281 ++++++++ .../Plugins/Schema/Svg/SvgRelationSchema.php | 284 ++++++++ .../classes/Plugins/Schema/Svg/TableStatsSvg.php | 204 ++++++ .../classes/Plugins/Schema/TableStats.php | 208 ++++++ 23 files changed, 5309 insertions(+) create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/Dia.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/DiaRelationSchema.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/RelationStatsDia.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/TableStatsDia.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/Eps.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/EpsRelationSchema.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/RelationStatsEps.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/TableStatsEps.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/ExportRelationSchema.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/Pdf.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/RelationStatsPdf.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/TableStatsPdf.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/RelationStats.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaDia.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaEps.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaPdf.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaSvg.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/RelationStatsSvg.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/Svg.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/SvgRelationSchema.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/TableStatsSvg.php create mode 100644 srcs/phpmyadmin/libraries/classes/Plugins/Schema/TableStats.php (limited to 'srcs/phpmyadmin/libraries/classes/Plugins/Schema') diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/Dia.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/Dia.php new file mode 100644 index 0000000..b9941a5 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/Dia.php @@ -0,0 +1,190 @@ +openMemory(); + /* + * Set indenting using three spaces, + * so output is formatted + */ + $this->setIndent(true); + $this->setIndentString(' '); + /* + * Create the XML document + */ + $this->startDocument('1.0', 'UTF-8'); + } + + /** + * Starts Dia Document + * + * dia document starts by first initializing dia:diagram tag + * then dia:diagramdata contains all the attributes that needed + * to define the document, then finally a Layer starts which + * holds all the objects. + * + * @param string $paper the size of the paper/document + * @param float $topMargin top margin of the paper/document in cm + * @param float $bottomMargin bottom margin of the paper/document in cm + * @param float $leftMargin left margin of the paper/document in cm + * @param float $rightMargin right margin of the paper/document in cm + * @param string $orientation orientation of the document, portrait or landscape + * + * @return void + * + * @access public + * @see XMLWriter::startElement(),XMLWriter::writeAttribute(), + * XMLWriter::writeRaw() + */ + public function startDiaDoc( + $paper, + $topMargin, + $bottomMargin, + $leftMargin, + $rightMargin, + $orientation + ) { + if ($orientation == 'P') { + $isPortrait = 'true'; + } else { + $isPortrait = 'false'; + } + $this->startElement('dia:diagram'); + $this->writeAttribute('xmlns:dia', 'http://www.lysator.liu.se/~alla/dia/'); + $this->startElement('dia:diagramdata'); + $this->writeRaw( + ' + + + + + + + + + #' . $paper . '# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' + ); + $this->endElement(); + $this->startElement('dia:layer'); + $this->writeAttribute('name', 'Background'); + $this->writeAttribute('visible', 'true'); + $this->writeAttribute('active', 'true'); + } + + /** + * Ends Dia Document + * + * @return void + * @access public + * @see XMLWriter::endElement(),XMLWriter::endDocument() + */ + public function endDiaDoc() + { + $this->endElement(); + $this->endDocument(); + } + + /** + * Output Dia Document for download + * + * @param string $fileName name of the dia document + * + * @return void + * @access public + * @see XMLWriter::flush() + */ + public function showOutput($fileName) + { + if (ob_get_clean()) { + ob_end_clean(); + } + $output = $this->flush(); + Response::getInstance()->disable(); + Core::downloadHeader( + $fileName, + 'application/x-dia-diagram', + strlen($output) + ); + print $output; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/DiaRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/DiaRelationSchema.php new file mode 100644 index 0000000..ee04f0d --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/DiaRelationSchema.php @@ -0,0 +1,238 @@ +setShowColor(isset($_REQUEST['dia_show_color'])); + $this->setShowKeys(isset($_REQUEST['dia_show_keys'])); + $this->setOrientation($_REQUEST['dia_orientation']); + $this->setPaper($_REQUEST['dia_paper']); + + $this->diagram->startDiaDoc( + $this->paper, + $this->_topMargin, + $this->_bottomMargin, + $this->_leftMargin, + $this->_rightMargin, + $this->orientation + ); + + $alltables = $this->getTablesFromRequest(); + + foreach ($alltables as $table) { + if (! isset($this->_tables[$table])) { + $this->_tables[$table] = new TableStatsDia( + $this->diagram, + $this->db, + $table, + $this->pageNumber, + $this->showKeys, + $this->offline + ); + } + } + + $seen_a_relation = false; + foreach ($alltables as $one_table) { + $exist_rel = $this->relation->getForeigners($this->db, $one_table, '', 'both'); + if (! $exist_rel) { + continue; + } + + $seen_a_relation = true; + foreach ($exist_rel as $master_field => $rel) { + /* put the foreign table on the schema only if selected + * by the user + * (do not use array_search() because we would have to + * to do a === false and this is not PHP3 compatible) + */ + if ($master_field != 'foreign_keys_data') { + if (in_array($rel['foreign_table'], $alltables)) { + $this->_addRelation( + $one_table, + $master_field, + $rel['foreign_table'], + $rel['foreign_field'], + $this->showKeys + ); + } + continue; + } + + foreach ($rel as $one_key) { + if (! in_array($one_key['ref_table_name'], $alltables)) { + continue; + } + + foreach ($one_key['index_list'] as $index => $one_field) { + $this->_addRelation( + $one_table, + $one_field, + $one_key['ref_table_name'], + $one_key['ref_index_list'][$index], + $this->showKeys + ); + } + } + } + } + $this->_drawTables(); + + if ($seen_a_relation) { + $this->_drawRelations(); + } + $this->diagram->endDiaDoc(); + } + + /** + * Output Dia Document for download + * + * @return void + * @access public + */ + public function showOutput() + { + $this->diagram->showOutput($this->getFileName('.dia')); + } + + /** + * Defines relation objects + * + * @param string $masterTable The master table name + * @param string $masterField The relation field in the master table + * @param string $foreignTable The foreign table name + * @param string $foreignField The relation field in the foreign table + * @param bool $showKeys Whether to display ONLY keys or not + * + * @return void + * + * @access private + * @see TableStatsDia::__construct(),RelationStatsDia::__construct() + */ + private function _addRelation( + $masterTable, + $masterField, + $foreignTable, + $foreignField, + $showKeys + ) { + if (! isset($this->_tables[$masterTable])) { + $this->_tables[$masterTable] = new TableStatsDia( + $this->diagram, + $this->db, + $masterTable, + $this->pageNumber, + $showKeys + ); + } + if (! isset($this->_tables[$foreignTable])) { + $this->_tables[$foreignTable] = new TableStatsDia( + $this->diagram, + $this->db, + $foreignTable, + $this->pageNumber, + $showKeys + ); + } + $this->_relations[] = new RelationStatsDia( + $this->diagram, + $this->_tables[$masterTable], + $masterField, + $this->_tables[$foreignTable], + $foreignField + ); + } + + /** + * Draws relation references + * + * connects master table's master field to + * foreign table's foreign field using Dia object + * type Database - Reference + * + * @return void + * + * @access private + * @see RelationStatsDia::relationDraw() + */ + private function _drawRelations() + { + foreach ($this->_relations as $relation) { + $relation->relationDraw($this->showColor); + } + } + + /** + * Draws tables + * + * Tables are generated using Dia object type Database - Table + * primary fields are underlined and bold in tables + * + * @return void + * + * @access private + * @see TableStatsDia::tableDraw() + */ + private function _drawTables() + { + foreach ($this->_tables as $table) { + $table->tableDraw($this->showColor); + } + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/RelationStatsDia.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/RelationStatsDia.php new file mode 100644 index 0000000..bd44532 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/RelationStatsDia.php @@ -0,0 +1,228 @@ +diagram = $diagram; + $src_pos = $this->_getXy($master_table, $master_field); + $dest_pos = $this->_getXy($foreign_table, $foreign_field); + $this->srcConnPointsLeft = $src_pos[0]; + $this->srcConnPointsRight = $src_pos[1]; + $this->destConnPointsLeft = $dest_pos[0]; + $this->destConnPointsRight = $dest_pos[1]; + $this->masterTablePos = $src_pos[2]; + $this->foreignTablePos = $dest_pos[2]; + $this->masterTableId = $master_table->tableId; + $this->foreignTableId = $foreign_table->tableId; + } + + /** + * Each Table object have connection points + * which is used to connect to other objects in Dia + * we detect the position of key in fields and + * then determines its left and right connection + * points. + * + * @param TableStatsDia $table The current table name + * @param string $column The relation column name + * + * @return array Table right,left connection points and key position + * + * @access private + */ + private function _getXy($table, $column) + { + $pos = array_search($column, $table->fields); + // left, right, position + $value = 12; + if ($pos != 0) { + return [ + $pos + $value + $pos, + $pos + $value + $pos + 1, + $pos, + ]; + } + return [ + $pos + $value, + $pos + $value + 1, + $pos, + ]; + } + + /** + * Draws relation references + * + * connects master table's master field to foreign table's + * foreign field using Dia object type Database - Reference + * Dia object is used to generate the XML of Dia Document. + * Database reference Object and their attributes are involved + * in the combination of displaying Database - reference on Dia Document. + * + * @param boolean $showColor Whether to use one color per relation or not + * if showColor is true then an array of $listOfColors + * will be used to choose the random colors for + * references lines. we can change/add more colors to + * this + * + * @return boolean|void + * + * @access public + * @see PDF + */ + public function relationDraw($showColor) + { + ++DiaRelationSchema::$objectId; + /* + * if source connection points and destination connection + * points are same then return it false and don't draw that + * relation + */ + if ($this->srcConnPointsRight == $this->destConnPointsRight) { + if ($this->srcConnPointsLeft == $this->destConnPointsLeft) { + return false; + } + } + + if ($showColor) { + $listOfColors = [ + 'FF0000', + '000099', + '00FF00', + ]; + shuffle($listOfColors); + $this->referenceColor = '#' . $listOfColors[0] . ''; + } else { + $this->referenceColor = '#000000'; + } + + $this->diagram->writeRaw( + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #1# + + + #n# + + + + + + + + + + + + ' + ); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/TableStatsDia.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/TableStatsDia.php new file mode 100644 index 0000000..b3ae5a0 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Dia/TableStatsDia.php @@ -0,0 +1,231 @@ +tableId = ++DiaRelationSchema::$objectId; + } + + /** + * Displays an error when the table cannot be found. + * + * @return void + */ + protected function showMissingTableError() + { + ExportRelationSchema::dieSchema( + $this->pageNumber, + "DIA", + sprintf(__('The %s table doesn\'t exist!'), $this->tableName) + ); + } + + /** + * Do draw the table + * + * Tables are generated using object type Database - Table + * primary fields are underlined in tables. Dia object + * is used to generate the XML of Dia Document. Database Table + * Object and their attributes are involved in the combination + * of displaying Database - Table on Dia Document. + * + * @param boolean $showColor Whether to show color for tables text or not + * if showColor is true then an array of $listOfColors + * will be used to choose the random colors for tables + * text we can change/add more colors to this array + * + * @return void + * + * @access public + * @see Dia + */ + public function tableDraw($showColor) + { + if ($showColor) { + $listOfColors = [ + 'FF0000', + '000099', + '00FF00', + ]; + shuffle($listOfColors); + $this->tableColor = '#' . $listOfColors[0] . ''; + } else { + $this->tableColor = '#000000'; + } + + $factor = 0.1; + + $this->diagram->startElement('dia:object'); + $this->diagram->writeAttribute('type', 'Database - Table'); + $this->diagram->writeAttribute('version', '0'); + $this->diagram->writeAttribute('id', '' . $this->tableId . ''); + $this->diagram->writeRaw( + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #' . $this->tableName . '# + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' + ); + + $this->diagram->startElement('dia:attribute'); + $this->diagram->writeAttribute('name', 'attributes'); + + foreach ($this->fields as $field) { + $this->diagram->writeRaw( + ' + + #' . $field . '# + + + ## + + + ## + ' + ); + unset($pm); + $pm = 'false'; + if (in_array($field, $this->primary)) { + $pm = 'true'; + } + if ($field == $this->displayfield) { + $pm = 'false'; + } + $this->diagram->writeRaw( + ' + + + + + + + + + ' + ); + } + $this->diagram->endElement(); + $this->diagram->endElement(); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/Eps.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/Eps.php new file mode 100644 index 0000000..0679709 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/Eps.php @@ -0,0 +1,280 @@ +stringCommands = ""; + $this->stringCommands .= "%!PS-Adobe-3.0 EPSF-3.0 \n"; + } + + /** + * Set document title + * + * @param string $value sets the title text + * + * @return void + */ + public function setTitle($value) + { + $this->stringCommands .= '%%Title: ' . $value . "\n"; + } + + /** + * Set document author + * + * @param string $value sets the author + * + * @return void + */ + public function setAuthor($value) + { + $this->stringCommands .= '%%Creator: ' . $value . "\n"; + } + + /** + * Set document creation date + * + * @param string $value sets the date + * + * @return void + */ + public function setDate($value) + { + $this->stringCommands .= '%%CreationDate: ' . $value . "\n"; + } + + /** + * Set document orientation + * + * @param string $orientation sets the orientation + * + * @return void + */ + public function setOrientation($orientation) + { + $this->stringCommands .= "%%PageOrder: Ascend \n"; + if ($orientation == "L") { + $orientation = "Landscape"; + $this->stringCommands .= '%%Orientation: ' . $orientation . "\n"; + } else { + $orientation = "Portrait"; + $this->stringCommands .= '%%Orientation: ' . $orientation . "\n"; + } + $this->stringCommands .= "%%EndComments \n"; + $this->stringCommands .= "%%Pages 1 \n"; + $this->stringCommands .= "%%BoundingBox: 72 150 144 170 \n"; + } + + /** + * Set the font and size + * + * font can be set whenever needed in EPS + * + * @param string $value sets the font name e.g Arial + * @param integer $size sets the size of the font e.g 10 + * + * @return void + */ + public function setFont($value, $size) + { + $this->font = $value; + $this->fontSize = $size; + $this->stringCommands .= "/" . $value . " findfont % Get the basic font\n"; + $this->stringCommands .= "" + . $size . " scalefont % Scale the font to $size points\n"; + $this->stringCommands + .= "setfont % Make it the current font\n"; + } + + /** + * Get the font + * + * @return string return the font name e.g Arial + */ + public function getFont() + { + return $this->font; + } + + /** + * Get the font Size + * + * @return string return the size of the font e.g 10 + */ + public function getFontSize() + { + return $this->fontSize; + } + + /** + * Draw the line + * + * drawing the lines from x,y source to x,y destination and set the + * width of the line. lines helps in showing relationships of tables + * + * @param integer $x_from The x_from attribute defines the start + * left position of the element + * @param integer $y_from The y_from attribute defines the start + * right position of the element + * @param integer $x_to The x_to attribute defines the end + * left position of the element + * @param integer $y_to The y_to attribute defines the end + * right position of the element + * @param integer $lineWidth Sets the width of the line e.g 2 + * + * @return void + */ + public function line( + $x_from = 0, + $y_from = 0, + $x_to = 0, + $y_to = 0, + $lineWidth = 0 + ) { + $this->stringCommands .= $lineWidth . " setlinewidth \n"; + $this->stringCommands .= $x_from . ' ' . $y_from . " moveto \n"; + $this->stringCommands .= $x_to . ' ' . $y_to . " lineto \n"; + $this->stringCommands .= "stroke \n"; + } + + /** + * Draw the rectangle + * + * drawing the rectangle from x,y source to x,y destination and set the + * width of the line. rectangles drawn around the text shown of fields + * + * @param integer $x_from The x_from attribute defines the start + * left position of the element + * @param integer $y_from The y_from attribute defines the start + * right position of the element + * @param integer $x_to The x_to attribute defines the end + * left position of the element + * @param integer $y_to The y_to attribute defines the end + * right position of the element + * @param integer $lineWidth Sets the width of the line e.g 2 + * + * @return void + */ + public function rect($x_from, $y_from, $x_to, $y_to, $lineWidth) + { + $this->stringCommands .= $lineWidth . " setlinewidth \n"; + $this->stringCommands .= "newpath \n"; + $this->stringCommands .= $x_from . " " . $y_from . " moveto \n"; + $this->stringCommands .= "0 " . $y_to . " rlineto \n"; + $this->stringCommands .= $x_to . " 0 rlineto \n"; + $this->stringCommands .= "0 -" . $y_to . " rlineto \n"; + $this->stringCommands .= "closepath \n"; + $this->stringCommands .= "stroke \n"; + } + + /** + * Set the current point + * + * The moveto operator takes two numbers off the stack and treats + * them as x and y coordinates to which to move. The coordinates + * specified become the current point. + * + * @param integer $x The x attribute defines the left position of the element + * @param integer $y The y attribute defines the right position of the element + * + * @return void + */ + public function moveTo($x, $y) + { + $this->stringCommands .= $x . ' ' . $y . " moveto \n"; + } + + /** + * Output/Display the text + * + * @param string $text The string to be displayed + * + * @return void + */ + public function show($text) + { + $this->stringCommands .= '(' . $text . ") show \n"; + } + + /** + * Output the text at specified co-ordinates + * + * @param string $text String to be displayed + * @param integer $x X attribute defines the left position of the element + * @param integer $y Y attribute defines the right position of the element + * + * @return void + */ + public function showXY($text, $x, $y) + { + $this->moveTo($x, $y); + $this->show($text); + } + + /** + * Ends EPS Document + * + * @return void + */ + public function endEpsDoc() + { + $this->stringCommands .= "showpage \n"; + } + + /** + * Output EPS Document for download + * + * @param string $fileName name of the eps document + * + * @return void + */ + public function showOutput($fileName) + { + // if(ob_get_clean()){ + //ob_end_clean(); + //} + $output = $this->stringCommands; + Response::getInstance() + ->disable(); + Core::downloadHeader( + $fileName, + 'image/x-eps', + strlen($output) + ); + print $output; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/EpsRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/EpsRelationSchema.php new file mode 100644 index 0000000..238af1b --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/EpsRelationSchema.php @@ -0,0 +1,254 @@ +setShowColor(isset($_REQUEST['eps_show_color'])); + $this->setShowKeys(isset($_REQUEST['eps_show_keys'])); + $this->setTableDimension(isset($_REQUEST['eps_show_table_dimension'])); + $this->setAllTablesSameWidth(isset($_REQUEST['eps_all_tables_same_width'])); + $this->setOrientation($_REQUEST['eps_orientation']); + + $this->diagram->setTitle( + sprintf( + __('Schema of the %s database - Page %s'), + $this->db, + $this->pageNumber + ) + ); + $this->diagram->setAuthor('phpMyAdmin ' . PMA_VERSION); + $this->diagram->setDate(date("j F Y, g:i a")); + $this->diagram->setOrientation($this->orientation); + $this->diagram->setFont('Verdana', '10'); + + $alltables = $this->getTablesFromRequest(); + + foreach ($alltables as $table) { + if (! isset($this->_tables[$table])) { + $this->_tables[$table] = new TableStatsEps( + $this->diagram, + $this->db, + $table, + $this->diagram->getFont(), + $this->diagram->getFontSize(), + $this->pageNumber, + $this->_tablewidth, + $this->showKeys, + $this->tableDimension, + $this->offline + ); + } + + if ($this->sameWide) { + $this->_tables[$table]->width = $this->_tablewidth; + } + } + + $seen_a_relation = false; + foreach ($alltables as $one_table) { + $exist_rel = $this->relation->getForeigners($this->db, $one_table, '', 'both'); + if (! $exist_rel) { + continue; + } + + $seen_a_relation = true; + foreach ($exist_rel as $master_field => $rel) { + /* put the foreign table on the schema only if selected + * by the user + * (do not use array_search() because we would have to + * to do a === false and this is not PHP3 compatible) + */ + if ($master_field != 'foreign_keys_data') { + if (in_array($rel['foreign_table'], $alltables)) { + $this->_addRelation( + $one_table, + $this->diagram->getFont(), + $this->diagram->getFontSize(), + $master_field, + $rel['foreign_table'], + $rel['foreign_field'], + $this->tableDimension + ); + } + continue; + } + + foreach ($rel as $one_key) { + if (! in_array($one_key['ref_table_name'], $alltables)) { + continue; + } + + foreach ($one_key['index_list'] as $index => $one_field) { + $this->_addRelation( + $one_table, + $this->diagram->getFont(), + $this->diagram->getFontSize(), + $one_field, + $one_key['ref_table_name'], + $one_key['ref_index_list'][$index], + $this->tableDimension + ); + } + } + } + } + if ($seen_a_relation) { + $this->_drawRelations(); + } + + $this->_drawTables(); + $this->diagram->endEpsDoc(); + } + + /** + * Output Eps Document for download + * + * @return void + */ + public function showOutput() + { + $this->diagram->showOutput($this->getFileName('.eps')); + } + + /** + * Defines relation objects + * + * @param string $masterTable The master table name + * @param string $font The font + * @param int $fontSize The font size + * @param string $masterField The relation field in the master table + * @param string $foreignTable The foreign table name + * @param string $foreignField The relation field in the foreign table + * @param boolean $tableDimension Whether to display table position or not + * + * @return void + * + * @see _setMinMax,Table_Stats_Eps::__construct(), + * PhpMyAdmin\Plugins\Schema\Eps\RelationStatsEps::__construct() + */ + private function _addRelation( + $masterTable, + $font, + $fontSize, + $masterField, + $foreignTable, + $foreignField, + $tableDimension + ) { + if (! isset($this->_tables[$masterTable])) { + $this->_tables[$masterTable] = new TableStatsEps( + $this->diagram, + $this->db, + $masterTable, + $font, + $fontSize, + $this->pageNumber, + $this->_tablewidth, + false, + $tableDimension + ); + } + if (! isset($this->_tables[$foreignTable])) { + $this->_tables[$foreignTable] = new TableStatsEps( + $this->diagram, + $this->db, + $foreignTable, + $font, + $fontSize, + $this->pageNumber, + $this->_tablewidth, + false, + $tableDimension + ); + } + $this->_relations[] = new RelationStatsEps( + $this->diagram, + $this->_tables[$masterTable], + $masterField, + $this->_tables[$foreignTable], + $foreignField + ); + } + + /** + * Draws relation arrows and lines connects master table's master field to + * foreign table's foreign field + * + * @return void + * + * @see Relation_Stats_Eps::relationDraw() + */ + private function _drawRelations() + { + foreach ($this->_relations as $relation) { + $relation->relationDraw(); + } + } + + /** + * Draws tables + * + * @return void + * + * @see Table_Stats_Eps::Table_Stats_tableDraw() + */ + private function _drawTables() + { + foreach ($this->_tables as $table) { + $table->tableDraw($this->showColor); + } + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/RelationStatsEps.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/RelationStatsEps.php new file mode 100644 index 0000000..4c50131 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/RelationStatsEps.php @@ -0,0 +1,120 @@ +wTick = 10; + parent::__construct( + $diagram, + $master_table, + $master_field, + $foreign_table, + $foreign_field + ); + $this->ySrc += 10; + $this->yDest += 10; + } + + /** + * draws relation links and arrows + * shows foreign key relations + * + * @see PMA_EPS + * + * @return void + */ + public function relationDraw() + { + // draw a line like -- to foreign field + $this->diagram->line( + $this->xSrc, + $this->ySrc, + $this->xSrc + $this->srcDir * $this->wTick, + $this->ySrc, + 1 + ); + // draw a line like -- to master field + $this->diagram->line( + $this->xDest + $this->destDir * $this->wTick, + $this->yDest, + $this->xDest, + $this->yDest, + 1 + ); + // draw a line that connects to master field line and foreign field line + $this->diagram->line( + $this->xSrc + $this->srcDir * $this->wTick, + $this->ySrc, + $this->xDest + $this->destDir * $this->wTick, + $this->yDest, + 1 + ); + $root2 = 2 * sqrt(2); + $this->diagram->line( + $this->xSrc + $this->srcDir * $this->wTick * 0.75, + $this->ySrc, + $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, + $this->ySrc + $this->wTick / $root2, + 1 + ); + $this->diagram->line( + $this->xSrc + $this->srcDir * $this->wTick * 0.75, + $this->ySrc, + $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, + $this->ySrc - $this->wTick / $root2, + 1 + ); + $this->diagram->line( + $this->xDest + $this->destDir * $this->wTick / 2, + $this->yDest, + $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, + $this->yDest + $this->wTick / $root2, + 1 + ); + $this->diagram->line( + $this->xDest + $this->destDir * $this->wTick / 2, + $this->yDest, + $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, + $this->yDest - $this->wTick / $root2, + 1 + ); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/TableStatsEps.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/TableStatsEps.php new file mode 100644 index 0000000..904d96a --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Eps/TableStatsEps.php @@ -0,0 +1,183 @@ +_setHeightTable($fontSize); + // setWidth must me after setHeight, because title + // can include table height which changes table width + $this->_setWidthTable($font, $fontSize); + if ($same_wide_width < $this->width) { + $same_wide_width = $this->width; + } + } + + /** + * Displays an error when the table cannot be found. + * + * @return void + */ + protected function showMissingTableError() + { + ExportRelationSchema::dieSchema( + $this->pageNumber, + "EPS", + sprintf(__('The %s table doesn\'t exist!'), $this->tableName) + ); + } + + /** + * Sets the width of the table + * + * @param string $font The font name + * @param integer $fontSize The font size + * + * @return void + * + * @see PMA_EPS + */ + private function _setWidthTable($font, $fontSize) + { + foreach ($this->fields as $field) { + $this->width = max( + $this->width, + $this->font->getStringWidth($field, $font, (int) $fontSize) + ); + } + $this->width += $this->font->getStringWidth( + ' ', + $font, + (int) $fontSize + ); + /* + * it is unknown what value must be added, because + * table title is affected by the table width value + */ + while ($this->width + < $this->font->getStringWidth( + $this->getTitle(), + $font, + (int) $fontSize + )) { + $this->width += 7; + } + } + + /** + * Sets the height of the table + * + * @param integer $fontSize The font size + * + * @return void + */ + private function _setHeightTable($fontSize) + { + $this->heightCell = $fontSize + 4; + $this->height = (count($this->fields) + 1) * $this->heightCell; + } + + /** + * Draw the table + * + * @param boolean $showColor Whether to display color + * + * @return void + * + * @see PMA_EPS,PMA_EPS::line,PMA_EPS::rect + */ + public function tableDraw($showColor) + { + $this->diagram->rect( + $this->x, + $this->y + 12, + $this->width, + $this->heightCell, + 1 + ); + $this->diagram->showXY($this->getTitle(), $this->x + 5, $this->y + 14); + foreach ($this->fields as $field) { + $this->currentCell += $this->heightCell; + $this->diagram->rect( + $this->x, + $this->y + 12 + $this->currentCell, + $this->width, + $this->heightCell, + 1 + ); + $this->diagram->showXY( + $field, + $this->x + 5, + $this->y + 14 + $this->currentCell + ); + } + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/ExportRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/ExportRelationSchema.php new file mode 100644 index 0000000..c5209c4 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/ExportRelationSchema.php @@ -0,0 +1,310 @@ +db = $db; + $this->diagram = $diagram; + $this->setPageNumber($_REQUEST['page_number']); + $this->setOffline(isset($_REQUEST['offline_export'])); + $this->relation = new Relation($GLOBALS['dbi']); + } + + /** + * Set Page Number + * + * @param integer $value Page Number of the document to be created + * + * @return void + */ + public function setPageNumber($value) + { + $this->pageNumber = intval($value); + } + + /** + * Returns the schema page number + * + * @return integer schema page number + */ + public function getPageNumber() + { + return $this->pageNumber; + } + + /** + * Sets showColor + * + * @param boolean $value whether to show colors + * + * @return void + */ + public function setShowColor($value) + { + $this->showColor = $value; + } + + /** + * Returns whether to show colors + * + * @return boolean whether to show colors + */ + public function isShowColor() + { + return $this->showColor; + } + + /** + * Set Table Dimension + * + * @param boolean $value show table co-ordinates or not + * + * @return void + */ + public function setTableDimension($value) + { + $this->tableDimension = $value; + } + + /** + * Returns whether to show table dimensions + * + * @return boolean whether to show table dimensions + */ + public function isTableDimension() + { + return $this->tableDimension; + } + + /** + * Set same width of All Tables + * + * @param boolean $value set same width of all tables or not + * + * @return void + */ + public function setAllTablesSameWidth($value) + { + $this->sameWide = $value; + } + + /** + * Returns whether to use same width for all tables or not + * + * @return boolean whether to use same width for all tables or not + */ + public function isAllTableSameWidth() + { + return $this->sameWide; + } + + /** + * Set Show only keys + * + * @param boolean $value show only keys or not + * + * @return void + * + * @access public + */ + public function setShowKeys($value) + { + $this->showKeys = $value; + } + + /** + * Returns whether to show keys + * + * @return boolean whether to show keys + */ + public function isShowKeys() + { + return $this->showKeys; + } + + /** + * Set Orientation + * + * @param string $value Orientation will be portrait or landscape + * + * @return void + * + * @access public + */ + public function setOrientation($value) + { + $this->orientation = $value == 'P' ? 'P' : 'L'; + } + + /** + * Returns orientation + * + * @return string orientation + */ + public function getOrientation() + { + return $this->orientation; + } + + /** + * Set type of paper + * + * @param string $value paper type can be A4 etc + * + * @return void + * + * @access public + */ + public function setPaper($value) + { + $this->paper = $value; + } + + /** + * Returns the paper size + * + * @return string paper size + */ + public function getPaper() + { + return $this->paper; + } + + /** + * Set whether the document is generated from client side DB + * + * @param boolean $value offline or not + * + * @return void + * + * @access public + */ + public function setOffline($value) + { + $this->offline = $value; + } + + /** + * Returns whether the client side database is used + * + * @return boolean + * + * @access public + */ + public function isOffline() + { + return $this->offline; + } + + /** + * Get the table names from the request + * + * @return array an array of table names + */ + protected function getTablesFromRequest() + { + $tables = []; + if (isset($_POST['t_tbl'])) { + foreach ($_POST['t_tbl'] as $table) { + $tables[] = rawurldecode($table); + } + } + return $tables; + } + + /** + * Returns the file name + * + * @param String $extension file extension + * + * @return string file name + */ + protected function getFileName($extension) + { + $filename = $this->db . $extension; + // Get the name of this page to use as filename + if ($this->pageNumber != -1 && ! $this->offline) { + $_name_sql = 'SELECT page_descr FROM ' + . Util::backquote($GLOBALS['cfgRelation']['db']) . '.' + . Util::backquote($GLOBALS['cfgRelation']['pdf_pages']) + . ' WHERE page_nr = ' . $this->pageNumber; + $_name_rs = $this->relation->queryAsControlUser($_name_sql); + $_name_row = $GLOBALS['dbi']->fetchRow($_name_rs); + $filename = $_name_row[0] . $extension; + } + + return $filename; + } + + /** + * Displays an error message + * + * @param integer $pageNumber ID of the chosen page + * @param string $type Schema Type + * @param string $error_message The error message + * + * @access public + * + * @return void + */ + public static function dieSchema($pageNumber, $type = '', $error_message = '') + { + echo "

" , __("SCHEMA ERROR: ") , $type , "

" , "\n"; + if (! empty($error_message)) { + $error_message = htmlspecialchars($error_message); + } + echo '

' , "\n"; + echo ' ' , $error_message , "\n"; + echo '

' , "\n"; + echo '' , __('Back') , ''; + echo "\n"; + exit; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/Pdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/Pdf.php new file mode 100644 index 0000000..e02a953 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/Pdf.php @@ -0,0 +1,422 @@ +_pageNumber = $pageNumber; + $this->_withDoc = $withDoc; + $this->_db = $db; + $this->relation = new Relation($GLOBALS['dbi']); + } + + /** + * Sets the value for margins + * + * @param float $c_margin margin + * + * @return void + */ + public function setCMargin($c_margin) + { + $this->cMargin = $c_margin; + } + + /** + * Sets the scaling factor, defines minimum coordinates and margins + * + * @param float|int $scale The scaling factor + * @param float|int $xMin The minimum X coordinate + * @param float|int $yMin The minimum Y coordinate + * @param float|int $leftMargin The left margin + * @param float|int $topMargin The top margin + * + * @return void + */ + public function setScale( + $scale = 1, + $xMin = 0, + $yMin = 0, + $leftMargin = -1, + $topMargin = -1 + ) { + $this->scale = $scale; + $this->_xMin = $xMin; + $this->_yMin = $yMin; + if ($this->leftMargin != -1) { + $this->leftMargin = $leftMargin; + } + if ($this->topMargin != -1) { + $this->topMargin = $topMargin; + } + } + + /** + * Outputs a scaled cell + * + * @param float|int $w The cell width + * @param float|int $h The cell height + * @param string $txt The text to output + * @param mixed $border Whether to add borders or not + * @param integer $ln Where to put the cursor once the output is done + * @param string $align Align mode + * @param integer $fill Whether to fill the cell with a color or not + * @param string $link Link + * + * @return void + * + * @see TCPDF::Cell() + */ + public function cellScale( + $w, + $h = 0, + $txt = '', + $border = 0, + $ln = 0, + $align = '', + $fill = 0, + $link = '' + ) { + $h /= $this->scale; + $w /= $this->scale; + $this->Cell($w, $h, $txt, $border, $ln, $align, $fill, $link); + } + + /** + * Draws a scaled line + * + * @param float $x1 The horizontal position of the starting point + * @param float $y1 The vertical position of the starting point + * @param float $x2 The horizontal position of the ending point + * @param float $y2 The vertical position of the ending point + * + * @return void + * + * @see TCPDF::Line() + */ + public function lineScale($x1, $y1, $x2, $y2) + { + $x1 = ($x1 - $this->_xMin) / $this->scale + $this->leftMargin; + $y1 = ($y1 - $this->_yMin) / $this->scale + $this->topMargin; + $x2 = ($x2 - $this->_xMin) / $this->scale + $this->leftMargin; + $y2 = ($y2 - $this->_yMin) / $this->scale + $this->topMargin; + $this->Line($x1, $y1, $x2, $y2); + } + + /** + * Sets x and y scaled positions + * + * @param float $x The x position + * @param float $y The y position + * + * @return void + * + * @see TCPDF::SetXY() + */ + public function setXyScale($x, $y) + { + $x = ($x - $this->_xMin) / $this->scale + $this->leftMargin; + $y = ($y - $this->_yMin) / $this->scale + $this->topMargin; + $this->SetXY($x, $y); + } + + /** + * Sets the X scaled positions + * + * @param float $x The x position + * + * @return void + * + * @see TCPDF::SetX() + */ + public function setXScale($x) + { + $x = ($x - $this->_xMin) / $this->scale + $this->leftMargin; + $this->SetX($x); + } + + /** + * Sets the scaled font size + * + * @param float $size The font size (in points) + * + * @return void + * + * @see TCPDF::SetFontSize() + */ + public function setFontSizeScale($size) + { + // Set font size in points + $size /= $this->scale; + $this->SetFontSize($size); + } + + /** + * Sets the scaled line width + * + * @param float $width The line width + * + * @return void + * + * @see TCPDF::SetLineWidth() + */ + public function setLineWidthScale($width) + { + $width /= $this->scale; + $this->SetLineWidth($width); + } + + /** + * This method is used to render the page header. + * + * @return void + * + * @see TCPDF::Header() + */ + // @codingStandardsIgnoreLine + public function Header() + { + // We only show this if we find something in the new pdf_pages table + + // This function must be named "Header" to work with the TCPDF library + if ($this->_withDoc) { + if ($this->_offline || $this->_pageNumber == -1) { + $pg_name = __("PDF export page"); + } else { + $test_query = 'SELECT * FROM ' + . Util::backquote($GLOBALS['cfgRelation']['db']) . '.' + . Util::backquote($GLOBALS['cfgRelation']['pdf_pages']) + . ' WHERE db_name = \'' . $GLOBALS['dbi']->escapeString($this->_db) + . '\' AND page_nr = \'' . $this->_pageNumber . '\''; + $test_rs = $this->relation->queryAsControlUser($test_query); + $pages = @$GLOBALS['dbi']->fetchAssoc($test_rs); + $pg_name = ucfirst($pages['page_descr']); + } + + $this->SetFont($this->_ff, 'B', 14); + $this->Cell(0, 6, $pg_name, 'B', 1, 'C'); + $this->SetFont($this->_ff, ''); + $this->Ln(); + } + } + + /** + * This function must be named "Footer" to work with the TCPDF library + * + * @return void + * + * @see PDF::Footer() + */ + // @codingStandardsIgnoreLine + public function Footer() + { + if ($this->_withDoc) { + parent::Footer(); + } + } + + /** + * Sets widths + * + * @param array $w array of widths + * + * @return void + */ + public function setWidths(array $w) + { + // column widths + $this->widths = $w; + } + + /** + * Generates table row. + * + * @param array $data Data for table + * @param array $links Links for table cells + * + * @return void + */ + public function row(array $data, array $links) + { + // line height + $nb = 0; + $data_cnt = count($data); + for ($i = 0; $i < $data_cnt; $i++) { + $nb = max($nb, $this->numLines($this->widths[$i], $data[$i])); + } + $il = $this->FontSize; + $h = ($il + 1) * $nb; + // page break if necessary + $this->checkPageBreak($h); + // draw the cells + $data_cnt = count($data); + for ($i = 0; $i < $data_cnt; $i++) { + $w = $this->widths[$i]; + // save current position + $x = $this->GetX(); + $y = $this->GetY(); + // draw the border + $this->Rect($x, $y, $w, $h); + if (isset($links[$i])) { + $this->Link($x, $y, $w, $h, $links[$i]); + } + // print text + $this->MultiCell($w, $il + 1, $data[$i], 0, 'L'); + // go to right side + $this->SetXY($x + $w, $y); + } + // go to line + $this->Ln($h); + } + + /** + * Compute number of lines used by a multicell of width w + * + * @param int $w width + * @param string $txt text + * + * @return int + */ + public function numLines($w, $txt) + { + $cw = &$this->CurrentFont['cw']; + if ($w == 0) { + $w = $this->w - $this->rMargin - $this->x; + } + $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; + $s = str_replace("\r", '', $txt); + $nb = strlen($s); + if ($nb > 0 && $s[$nb - 1] == "\n") { + $nb--; + } + $sep = -1; + $i = 0; + $j = 0; + $l = 0; + $nl = 1; + while ($i < $nb) { + $c = $s[$i]; + if ($c == "\n") { + $i++; + $sep = -1; + $j = $i; + $l = 0; + $nl++; + continue; + } + if ($c == ' ') { + $sep = $i; + } + $l += isset($cw[mb_ord($c)]) ? $cw[mb_ord($c)] : 0 ; + if ($l > $wmax) { + if ($sep == -1) { + if ($i == $j) { + $i++; + } + } else { + $i = $sep + 1; + } + $sep = -1; + $j = $i; + $l = 0; + $nl++; + } else { + $i++; + } + } + return $nl; + } + + /** + * Set whether the document is generated from client side DB + * + * @param string $value whether offline + * + * @return void + * + * @access private + */ + public function setOffline($value) + { + $this->_offline = $value; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php new file mode 100644 index 0000000..fa67885 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php @@ -0,0 +1,798 @@ +transformations = new Transformations(); + + $this->setShowGrid(isset($_REQUEST['pdf_show_grid'])); + $this->setShowColor(isset($_REQUEST['pdf_show_color'])); + $this->setShowKeys(isset($_REQUEST['pdf_show_keys'])); + $this->setTableDimension(isset($_REQUEST['pdf_show_table_dimension'])); + $this->setAllTablesSameWidth(isset($_REQUEST['pdf_all_tables_same_width'])); + $this->setWithDataDictionary(isset($_REQUEST['pdf_with_doc'])); + $this->setTableOrder($_REQUEST['pdf_table_order']); + $this->setOrientation($_REQUEST['pdf_orientation']); + $this->setPaper($_REQUEST['pdf_paper']); + + // Initializes a new document + parent::__construct( + $db, + new Pdf( + $this->orientation, + 'mm', + $this->paper, + $this->pageNumber, + $this->_withDoc, + $db + ) + ); + $this->diagram->SetTitle( + sprintf( + __('Schema of the %s database'), + $this->db + ) + ); + $this->diagram->setCMargin(0); + $this->diagram->Open(); + $this->diagram->SetAutoPageBreak('auto'); + $this->diagram->setOffline($this->offline); + + $alltables = $this->getTablesFromRequest(); + if ($this->getTableOrder() == 'name_asc') { + sort($alltables); + } elseif ($this->getTableOrder() == 'name_desc') { + rsort($alltables); + } + + if ($this->_withDoc) { + $this->diagram->SetAutoPageBreak('auto', 15); + $this->diagram->setCMargin(1); + $this->dataDictionaryDoc($alltables); + $this->diagram->SetAutoPageBreak('auto'); + $this->diagram->setCMargin(0); + } + + $this->diagram->AddPage(); + + if ($this->_withDoc) { + $this->diagram->SetLink($this->diagram->PMA_links['RT']['-'], -1); + $this->diagram->Bookmark(__('Relational schema')); + $this->diagram->setAlias('{00}', $this->diagram->PageNo()); + $this->_topMargin = 28; + $this->_bottomMargin = 28; + } + + /* snip */ + foreach ($alltables as $table) { + if (! isset($this->_tables[$table])) { + $this->_tables[$table] = new TableStatsPdf( + $this->diagram, + $this->db, + $table, + null, + $this->pageNumber, + $this->_tablewidth, + $this->showKeys, + $this->tableDimension, + $this->offline + ); + } + if ($this->sameWide) { + $this->_tables[$table]->width = $this->_tablewidth; + } + $this->_setMinMax($this->_tables[$table]); + } + + // Defines the scale factor + $innerWidth = $this->diagram->getPageWidth() - $this->_rightMargin + - $this->_leftMargin; + $innerHeight = $this->diagram->getPageHeight() - $this->_topMargin + - $this->_bottomMargin; + $this->_scale = ceil( + max( + ($this->_xMax - $this->_xMin) / $innerWidth, + ($this->_yMax - $this->_yMin) / $innerHeight + ) * 100 + ) / 100; + + $this->diagram->setScale( + $this->_scale, + $this->_xMin, + $this->_yMin, + $this->_leftMargin, + $this->_topMargin + ); + // Builds and save the PDF document + $this->diagram->setLineWidthScale(0.1); + + if ($this->_showGrid) { + $this->diagram->SetFontSize(10); + $this->_strokeGrid(); + } + $this->diagram->setFontSizeScale(14); + // previous logic was checking master tables and foreign tables + // but I think that looping on every table of the pdf page as a master + // and finding its foreigns is OK (then we can support innodb) + $seen_a_relation = false; + foreach ($alltables as $one_table) { + $exist_rel = $this->relation->getForeigners($this->db, $one_table, '', 'both'); + if (! $exist_rel) { + continue; + } + + $seen_a_relation = true; + foreach ($exist_rel as $master_field => $rel) { + // put the foreign table on the schema only if selected + // by the user + // (do not use array_search() because we would have to + // to do a === false and this is not PHP3 compatible) + if ($master_field != 'foreign_keys_data') { + if (in_array($rel['foreign_table'], $alltables)) { + $this->_addRelation( + $one_table, + $master_field, + $rel['foreign_table'], + $rel['foreign_field'] + ); + } + continue; + } + + foreach ($rel as $one_key) { + if (! in_array($one_key['ref_table_name'], $alltables)) { + continue; + } + + foreach ($one_key['index_list'] as $index => $one_field) { + $this->_addRelation( + $one_table, + $one_field, + $one_key['ref_table_name'], + $one_key['ref_index_list'][$index] + ); + } + } + } // end while + } // end while + + if ($seen_a_relation) { + $this->_drawRelations(); + } + $this->_drawTables(); + } + + /** + * Set Show Grid + * + * @param boolean $value show grid of the document or not + * + * @return void + */ + public function setShowGrid($value) + { + $this->_showGrid = $value; + } + + /** + * Returns whether to show grid + * + * @return boolean whether to show grid + */ + public function isShowGrid() + { + return $this->_showGrid; + } + + /** + * Set Data Dictionary + * + * @param boolean $value show selected database data dictionary or not + * + * @return void + */ + public function setWithDataDictionary($value) + { + $this->_withDoc = $value; + } + + /** + * Return whether to show selected database data dictionary or not + * + * @return boolean whether to show selected database data dictionary or not + */ + public function isWithDataDictionary() + { + return $this->_withDoc; + } + + /** + * Sets the order of the table in data dictionary + * + * @param string $value table order + * + * @return void + */ + public function setTableOrder($value) + { + $this->_tableOrder = $value; + } + + /** + * Returns the order of the table in data dictionary + * + * @return string table order + */ + public function getTableOrder() + { + return $this->_tableOrder; + } + + /** + * Output Pdf Document for download + * + * @return void + */ + public function showOutput() + { + $this->diagram->download($this->getFileName('.pdf')); + } + + /** + * Sets X and Y minimum and maximum for a table cell + * + * @param TableStatsPdf $table The table name of which sets XY co-ordinates + * + * @return void + */ + private function _setMinMax($table) + { + $this->_xMax = max($this->_xMax, $table->x + $table->width); + $this->_yMax = max($this->_yMax, $table->y + $table->height); + $this->_xMin = min($this->_xMin, $table->x); + $this->_yMin = min($this->_yMin, $table->y); + } + + /** + * Defines relation objects + * + * @param string $masterTable The master table name + * @param string $masterField The relation field in the master table + * @param string $foreignTable The foreign table name + * @param string $foreignField The relation field in the foreign table + * + * @return void + * + * @see _setMinMax + */ + private function _addRelation( + $masterTable, + $masterField, + $foreignTable, + $foreignField + ) { + if (! isset($this->_tables[$masterTable])) { + $this->_tables[$masterTable] = new TableStatsPdf( + $this->diagram, + $this->db, + $masterTable, + null, + $this->pageNumber, + $this->_tablewidth, + $this->showKeys, + $this->tableDimension + ); + $this->_setMinMax($this->_tables[$masterTable]); + } + if (! isset($this->_tables[$foreignTable])) { + $this->_tables[$foreignTable] = new TableStatsPdf( + $this->diagram, + $this->db, + $foreignTable, + null, + $this->pageNumber, + $this->_tablewidth, + $this->showKeys, + $this->tableDimension + ); + $this->_setMinMax($this->_tables[$foreignTable]); + } + $this->relations[] = new RelationStatsPdf( + $this->diagram, + $this->_tables[$masterTable], + $masterField, + $this->_tables[$foreignTable], + $foreignField + ); + } + + /** + * Draws the grid + * + * @return void + * + * @see PMA_Schema_PDF + */ + private function _strokeGrid() + { + $gridSize = 10; + $labelHeight = 4; + $labelWidth = 5; + if ($this->_withDoc) { + $topSpace = 6; + $bottomSpace = 15; + } else { + $topSpace = 0; + $bottomSpace = 0; + } + + $this->diagram->SetMargins(0, 0); + $this->diagram->SetDrawColor(200, 200, 200); + // Draws horizontal lines + $innerHeight = $this->diagram->getPageHeight() - $topSpace - $bottomSpace; + for ($l = 0, $size = intval($innerHeight / $gridSize); $l <= $size; $l++) { + $this->diagram->line( + 0, + $l * $gridSize + $topSpace, + $this->diagram->getPageWidth(), + $l * $gridSize + $topSpace + ); + // Avoid duplicates + if ($l > 0 + && $l <= intval(($innerHeight - $labelHeight) / $gridSize) + ) { + $this->diagram->SetXY(0, $l * $gridSize + $topSpace); + $label = (string) sprintf( + '%.0f', + ($l * $gridSize + $topSpace - $this->_topMargin) + * $this->_scale + $this->_yMin + ); + $this->diagram->Cell($labelWidth, $labelHeight, ' ' . $label); + } // end if + } // end for + // Draws vertical lines + for ($j = 0, $size = intval($this->diagram->getPageWidth() / $gridSize); $j <= $size; $j++) { + $this->diagram->line( + $j * $gridSize, + $topSpace, + $j * $gridSize, + $this->diagram->getPageHeight() - $bottomSpace + ); + $this->diagram->SetXY($j * $gridSize, $topSpace); + $label = (string) sprintf( + '%.0f', + ($j * $gridSize - $this->_leftMargin) * $this->_scale + $this->_xMin + ); + $this->diagram->Cell($labelWidth, $labelHeight, $label); + } + } + + /** + * Draws relation arrows + * + * @return void + * + * @see Relation_Stats_Pdf::relationdraw() + */ + private function _drawRelations() + { + $i = 0; + foreach ($this->relations as $relation) { + $relation->relationDraw($this->showColor, $i); + $i++; + } + } + + /** + * Draws tables + * + * @return void + * + * @see Table_Stats_Pdf::tableDraw() + */ + private function _drawTables() + { + foreach ($this->_tables as $table) { + $table->tableDraw(null, $this->_withDoc, $this->showColor); + } + } + + /** + * Generates data dictionary pages. + * + * @param array $alltables Tables to document. + * + * @return void + */ + public function dataDictionaryDoc(array $alltables) + { + // TOC + $this->diagram->AddPage($this->orientation); + $this->diagram->Cell(0, 9, __('Table of contents'), 1, 0, 'C'); + $this->diagram->Ln(15); + $i = 1; + foreach ($alltables as $table) { + $this->diagram->PMA_links['doc'][$table]['-'] + = $this->diagram->AddLink(); + $this->diagram->SetX(10); + // $this->diagram->Ln(1); + $this->diagram->Cell( + 0, + 6, + __('Page number:') . ' {' . sprintf("%02d", $i) . '}', + 0, + 0, + 'R', + 0, + $this->diagram->PMA_links['doc'][$table]['-'] + ); + $this->diagram->SetX(10); + $this->diagram->Cell( + 0, + 6, + $i . ' ' . $table, + 0, + 1, + 'L', + 0, + $this->diagram->PMA_links['doc'][$table]['-'] + ); + // $this->diagram->Ln(1); + $fields = $GLOBALS['dbi']->getColumns($this->db, $table); + foreach ($fields as $row) { + $this->diagram->SetX(20); + $field_name = $row['Field']; + $this->diagram->PMA_links['doc'][$table][$field_name] + = $this->diagram->AddLink(); + //$this->diagram->Cell( + // 0, 6, $field_name, 0, 1, + // 'L', 0, $this->diagram->PMA_links['doc'][$table][$field_name] + //); + } + $i++; + } + $this->diagram->PMA_links['RT']['-'] = $this->diagram->AddLink(); + $this->diagram->SetX(10); + $this->diagram->Cell( + 0, + 6, + __('Page number:') . ' {00}', + 0, + 0, + 'R', + 0, + $this->diagram->PMA_links['RT']['-'] + ); + $this->diagram->SetX(10); + $this->diagram->Cell( + 0, + 6, + $i . ' ' . __('Relational schema'), + 0, + 1, + 'L', + 0, + $this->diagram->PMA_links['RT']['-'] + ); + $z = 0; + foreach ($alltables as $table) { + $z++; + $this->diagram->SetAutoPageBreak(true, 15); + $this->diagram->AddPage($this->orientation); + $this->diagram->Bookmark($table); + $this->diagram->setAlias( + '{' . sprintf("%02d", $z) . '}', + $this->diagram->PageNo() + ); + $this->diagram->PMA_links['RT'][$table]['-'] + = $this->diagram->AddLink(); + $this->diagram->SetLink( + $this->diagram->PMA_links['doc'][$table]['-'], + -1 + ); + $this->diagram->SetFont($this->_ff, 'B', 18); + $this->diagram->Cell( + 0, + 8, + $z . ' ' . $table, + 1, + 1, + 'C', + 0, + $this->diagram->PMA_links['RT'][$table]['-'] + ); + $this->diagram->SetFont($this->_ff, '', 8); + $this->diagram->Ln(); + + $cfgRelation = $this->relation->getRelationsParam(); + $comments = $this->relation->getComments($this->db, $table); + if ($cfgRelation['mimework']) { + $mime_map = $this->transformations->getMime($this->db, $table, true); + } + + /** + * Gets table information + */ + $showtable = $GLOBALS['dbi']->getTable($this->db, $table) + ->getStatusInfo(); + $show_comment = isset($showtable['Comment']) + ? $showtable['Comment'] + : ''; + $create_time = isset($showtable['Create_time']) + ? Util::localisedDate( + strtotime($showtable['Create_time']) + ) + : ''; + $update_time = isset($showtable['Update_time']) + ? Util::localisedDate( + strtotime($showtable['Update_time']) + ) + : ''; + $check_time = isset($showtable['Check_time']) + ? Util::localisedDate( + strtotime($showtable['Check_time']) + ) + : ''; + + /** + * Gets fields properties + */ + $columns = $GLOBALS['dbi']->getColumns($this->db, $table); + + // Find which tables are related with the current one and write it in + // an array + $res_rel = $this->relation->getForeigners($this->db, $table); + + /** + * Displays the comments of the table if MySQL >= 3.23 + */ + + $break = false; + if (! empty($show_comment)) { + $this->diagram->Cell( + 0, + 3, + __('Table comments:') . ' ' . $show_comment, + 0, + 1 + ); + $break = true; + } + + if (! empty($create_time)) { + $this->diagram->Cell( + 0, + 3, + __('Creation:') . ' ' . $create_time, + 0, + 1 + ); + $break = true; + } + + if (! empty($update_time)) { + $this->diagram->Cell( + 0, + 3, + __('Last update:') . ' ' . $update_time, + 0, + 1 + ); + $break = true; + } + + if (! empty($check_time)) { + $this->diagram->Cell( + 0, + 3, + __('Last check:') . ' ' . $check_time, + 0, + 1 + ); + $break = true; + } + + if ($break == true) { + $this->diagram->Cell(0, 3, '', 0, 1); + $this->diagram->Ln(); + } + + $this->diagram->SetFont($this->_ff, 'B'); + if (isset($this->orientation) && $this->orientation == 'L') { + $this->diagram->Cell(25, 8, __('Column'), 1, 0, 'C'); + $this->diagram->Cell(20, 8, __('Type'), 1, 0, 'C'); + $this->diagram->Cell(20, 8, __('Attributes'), 1, 0, 'C'); + $this->diagram->Cell(10, 8, __('Null'), 1, 0, 'C'); + $this->diagram->Cell(20, 8, __('Default'), 1, 0, 'C'); + $this->diagram->Cell(25, 8, __('Extra'), 1, 0, 'C'); + $this->diagram->Cell(45, 8, __('Links to'), 1, 0, 'C'); + + if ($this->paper == 'A4') { + $comments_width = 67; + } else { + // this is really intended for 'letter' + /** + * @todo find optimal width for all formats + */ + $comments_width = 50; + } + $this->diagram->Cell($comments_width, 8, __('Comments'), 1, 0, 'C'); + $this->diagram->Cell(45, 8, 'MIME', 1, 1, 'C'); + $this->diagram->setWidths( + [ + 25, + 20, + 20, + 10, + 20, + 25, + 45, + $comments_width, + 45, + ] + ); + } else { + $this->diagram->Cell(20, 8, __('Column'), 1, 0, 'C'); + $this->diagram->Cell(20, 8, __('Type'), 1, 0, 'C'); + $this->diagram->Cell(20, 8, __('Attributes'), 1, 0, 'C'); + $this->diagram->Cell(10, 8, __('Null'), 1, 0, 'C'); + $this->diagram->Cell(15, 8, __('Default'), 1, 0, 'C'); + $this->diagram->Cell(15, 8, __('Extra'), 1, 0, 'C'); + $this->diagram->Cell(30, 8, __('Links to'), 1, 0, 'C'); + $this->diagram->Cell(30, 8, __('Comments'), 1, 0, 'C'); + $this->diagram->Cell(30, 8, 'MIME', 1, 1, 'C'); + $this->diagram->setWidths([20, 20, 20, 10, 15, 15, 30, 30, 30]); + } + $this->diagram->SetFont($this->_ff, ''); + + foreach ($columns as $row) { + $extracted_columnspec + = Util::extractColumnSpec($row['Type']); + $type = $extracted_columnspec['print_type']; + $attribute = $extracted_columnspec['attribute']; + if (! isset($row['Default'])) { + if ($row['Null'] != '' && $row['Null'] != 'NO') { + $row['Default'] = 'NULL'; + } + } + $field_name = $row['Field']; + // $this->diagram->Ln(); + $this->diagram->PMA_links['RT'][$table][$field_name] + = $this->diagram->AddLink(); + $this->diagram->Bookmark($field_name, 1, -1); + $this->diagram->SetLink( + $this->diagram->PMA_links['doc'][$table][$field_name], + -1 + ); + $foreigner = $this->relation->searchColumnInForeigners($res_rel, $field_name); + + $linksTo = ''; + if ($foreigner) { + $linksTo = '-> '; + if ($foreigner['foreign_db'] != $this->db) { + $linksTo .= $foreigner['foreign_db'] . '.'; + } + $linksTo .= $foreigner['foreign_table'] + . '.' . $foreigner['foreign_field']; + + if (isset($foreigner['on_update'])) { // not set for internal + $linksTo .= "\n" . 'ON UPDATE ' . $foreigner['on_update']; + $linksTo .= "\n" . 'ON DELETE ' . $foreigner['on_delete']; + } + } + + $diagram_row = [ + $field_name, + $type, + $attribute, + ($row['Null'] == '' || $row['Null'] == 'NO') + ? __('No') + : __('Yes'), + isset($row['Default']) ? $row['Default'] : '', + $row['Extra'], + $linksTo, + isset($comments[$field_name]) + ? $comments[$field_name] + : '', + isset($mime_map) && isset($mime_map[$field_name]) + ? str_replace('_', '/', $mime_map[$field_name]['mimetype']) + : '', + ]; + $links = []; + $links[0] = $this->diagram->PMA_links['RT'][$table][$field_name]; + if ($foreigner + && isset($this->diagram->PMA_links['doc'][$foreigner['foreign_table']][$foreigner['foreign_field']]) + ) { + $links[6] = $this->diagram->PMA_links['doc'][$foreigner['foreign_table']][$foreigner['foreign_field']]; + } else { + unset($links[6]); + } + $this->diagram->row($diagram_row, $links); + } // end foreach + $this->diagram->SetFont($this->_ff, '', 14); + } //end each + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/RelationStatsPdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/RelationStatsPdf.php new file mode 100644 index 0000000..b422ce5 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/RelationStatsPdf.php @@ -0,0 +1,163 @@ +wTick = 5; + parent::__construct( + $diagram, + $master_table, + $master_field, + $foreign_table, + $foreign_field + ); + } + + /** + * draws relation links and arrows shows foreign key relations + * + * @param boolean $showColor Whether to use one color per relation or not + * @param integer $i The id of the link to draw + * + * @access public + * + * @return void + * + * @see Pdf + */ + public function relationDraw($showColor, $i) + { + if ($showColor) { + $d = $i % 6; + $j = ($i - $d) / 6; + $j %= 4; + $j++; + $case = [ + [ + 1, + 0, + 0, + ], + [ + 0, + 1, + 0, + ], + [ + 0, + 0, + 1, + ], + [ + 1, + 1, + 0, + ], + [ + 1, + 0, + 1, + ], + [ + 0, + 1, + 1, + ], + ]; + list ($a, $b, $c) = $case[$d]; + $e = (1 - ($j - 1) / 6); + $this->diagram->SetDrawColor($a * 255 * $e, $b * 255 * $e, $c * 255 * $e); + } else { + $this->diagram->SetDrawColor(0); + } + $this->diagram->setLineWidthScale(0.2); + $this->diagram->lineScale( + $this->xSrc, + $this->ySrc, + $this->xSrc + $this->srcDir * $this->wTick, + $this->ySrc + ); + $this->diagram->lineScale( + $this->xDest + $this->destDir * $this->wTick, + $this->yDest, + $this->xDest, + $this->yDest + ); + $this->diagram->setLineWidthScale(0.1); + $this->diagram->lineScale( + $this->xSrc + $this->srcDir * $this->wTick, + $this->ySrc, + $this->xDest + $this->destDir * $this->wTick, + $this->yDest + ); + /* + * Draws arrows -> + */ + $root2 = 2 * sqrt(2); + $this->diagram->lineScale( + $this->xSrc + $this->srcDir * $this->wTick * 0.75, + $this->ySrc, + $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, + $this->ySrc + $this->wTick / $root2 + ); + $this->diagram->lineScale( + $this->xSrc + $this->srcDir * $this->wTick * 0.75, + $this->ySrc, + $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, + $this->ySrc - $this->wTick / $root2 + ); + + $this->diagram->lineScale( + $this->xDest + $this->destDir * $this->wTick / 2, + $this->yDest, + $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, + $this->yDest + $this->wTick / $root2 + ); + $this->diagram->lineScale( + $this->xDest + $this->destDir * $this->wTick / 2, + $this->yDest, + $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, + $this->yDest - $this->wTick / $root2 + ); + $this->diagram->SetDrawColor(0); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/TableStatsPdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/TableStatsPdf.php new file mode 100644 index 0000000..999894c --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Pdf/TableStatsPdf.php @@ -0,0 +1,233 @@ +heightCell = 6; + $this->_setHeight(); + /* + * setWidth must me after setHeight, because title + * can include table height which changes table width + */ + $this->_setWidth($fontSize); + if ($sameWideWidth < $this->width) { + $sameWideWidth = $this->width; + } + } + + /** + * Displays an error when the table cannot be found. + * + * @return void + */ + protected function showMissingTableError() + { + ExportRelationSchema::dieSchema( + $this->pageNumber, + "PDF", + sprintf(__('The %s table doesn\'t exist!'), $this->tableName) + ); + } + + /** + * Returns title of the current table, + * title can have the dimensions of the table + * + * @return string + */ + protected function getTitle() + { + $ret = ''; + if ($this->tableDimension) { + $ret = sprintf('%.0fx%0.f', $this->width, $this->height); + } + + return $ret . ' ' . $this->tableName; + } + + /** + * Sets the width of the table + * + * @param integer $fontSize The font size + * + * @access private + * + * @return void + * + * @see PMA_Schema_PDF + */ + private function _setWidth($fontSize) + { + foreach ($this->fields as $field) { + $this->width = max($this->width, $this->diagram->GetStringWidth($field)); + } + $this->width += $this->diagram->GetStringWidth(' '); + $this->diagram->SetFont($this->_ff, 'B', $fontSize); + /* + * it is unknown what value must be added, because + * table title is affected by the table width value + */ + while ($this->width < $this->diagram->GetStringWidth($this->getTitle())) { + $this->width += 5; + } + $this->diagram->SetFont($this->_ff, '', $fontSize); + } + + /** + * Sets the height of the table + * + * @return void + * + * @access private + */ + private function _setHeight() + { + $this->height = (count($this->fields) + 1) * $this->heightCell; + } + + /** + * Do draw the table + * + * @param integer $fontSize The font size + * @param boolean $withDoc Whether to include links to documentation + * @param boolean|integer $setColor Whether to display color + * + * @access public + * + * @return void + * + * @see PMA_Schema_PDF + */ + public function tableDraw($fontSize, $withDoc, $setColor = 0) + { + $this->diagram->setXyScale($this->x, $this->y); + $this->diagram->SetFont($this->_ff, 'B', $fontSize); + if ($setColor) { + $this->diagram->SetTextColor(200); + $this->diagram->SetFillColor(0, 0, 128); + } + if ($withDoc) { + $this->diagram->SetLink( + $this->diagram->PMA_links['RT'][$this->tableName]['-'], + -1 + ); + } else { + $this->diagram->PMA_links['doc'][$this->tableName]['-'] = ''; + } + + $this->diagram->cellScale( + $this->width, + $this->heightCell, + $this->getTitle(), + 1, + 1, + 'C', + $setColor, + $this->diagram->PMA_links['doc'][$this->tableName]['-'] + ); + $this->diagram->setXScale($this->x); + $this->diagram->SetFont($this->_ff, '', $fontSize); + $this->diagram->SetTextColor(0); + $this->diagram->SetFillColor(255); + + foreach ($this->fields as $field) { + if ($setColor) { + if (in_array($field, $this->primary)) { + $this->diagram->SetFillColor(215, 121, 123); + } + if ($field == $this->displayfield) { + $this->diagram->SetFillColor(142, 159, 224); + } + } + if ($withDoc) { + $this->diagram->SetLink( + $this->diagram->PMA_links['RT'][$this->tableName][$field], + -1 + ); + } else { + $this->diagram->PMA_links['doc'][$this->tableName][$field] = ''; + } + + $this->diagram->cellScale( + $this->width, + $this->heightCell, + ' ' . $field, + 1, + 1, + 'L', + $setColor, + $this->diagram->PMA_links['doc'][$this->tableName][$field] + ); + $this->diagram->setXScale($this->x); + $this->diagram->SetFillColor(255); + } + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/RelationStats.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/RelationStats.php new file mode 100644 index 0000000..848fbf4 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/RelationStats.php @@ -0,0 +1,120 @@ +diagram = $diagram; + + $src_pos = $this->_getXy($master_table, $master_field); + $dest_pos = $this->_getXy($foreign_table, $foreign_field); + /* + * [0] is x-left + * [1] is x-right + * [2] is y + */ + $src_left = $src_pos[0] - $this->wTick; + $src_right = $src_pos[1] + $this->wTick; + $dest_left = $dest_pos[0] - $this->wTick; + $dest_right = $dest_pos[1] + $this->wTick; + + $d1 = abs($src_left - $dest_left); + $d2 = abs($src_right - $dest_left); + $d3 = abs($src_left - $dest_right); + $d4 = abs($src_right - $dest_right); + $d = min($d1, $d2, $d3, $d4); + + if ($d == $d1) { + $this->xSrc = $src_pos[0]; + $this->srcDir = -1; + $this->xDest = $dest_pos[0]; + $this->destDir = -1; + } elseif ($d == $d2) { + $this->xSrc = $src_pos[1]; + $this->srcDir = 1; + $this->xDest = $dest_pos[0]; + $this->destDir = -1; + } elseif ($d == $d3) { + $this->xSrc = $src_pos[0]; + $this->srcDir = -1; + $this->xDest = $dest_pos[1]; + $this->destDir = 1; + } else { + $this->xSrc = $src_pos[1]; + $this->srcDir = 1; + $this->xDest = $dest_pos[1]; + $this->destDir = 1; + } + $this->ySrc = $src_pos[2]; + $this->yDest = $dest_pos[2]; + } + + /** + * Gets arrows coordinates + * + * @param TableStats $table The table + * @param string $column The relation column name + * + * @return array Arrows coordinates + * + * @access private + */ + private function _getXy($table, $column) + { + $pos = array_search($column, $table->fields); + + // x_left, x_right, y + return [ + $table->x, + $table->x + $table->width, + $table->y + ($pos + 1.5) * $table->heightCell, + ]; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaDia.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaDia.php new file mode 100644 index 0000000..8c328d5 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaDia.php @@ -0,0 +1,100 @@ +setProperties(); + } + + /** + * Sets the schema export Dia properties + * + * @return void + */ + protected function setProperties() + { + $schemaPluginProperties = new SchemaPluginProperties(); + $schemaPluginProperties->setText('Dia'); + $schemaPluginProperties->setExtension('dia'); + $schemaPluginProperties->setMimeType('application/dia'); + + // create the root group that will be the options field for + // $schemaPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup( + "Format Specific Options" + ); + + // specific options main group + $specificOptions = new OptionsPropertyMainGroup("general_opts"); + // add options common to all plugins + $this->addCommonOptions($specificOptions); + + $leaf = new SelectPropertyItem( + "orientation", + __('Orientation') + ); + $leaf->setValues( + [ + 'L' => __('Landscape'), + 'P' => __('Portrait'), + ] + ); + $specificOptions->addProperty($leaf); + + $leaf = new SelectPropertyItem( + "paper", + __('Paper size') + ); + $leaf->setValues($this->getPaperSizeArray()); + $specificOptions->addProperty($leaf); + + // add the main group to the root group + $exportSpecificOptions->addProperty($specificOptions); + + // set the options for the schema export plugin property item + $schemaPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $schemaPluginProperties; + } + + /** + * Exports the schema into DIA format. + * + * @param string $db database name + * + * @return bool Whether it succeeded + */ + public function exportSchema($db) + { + $export = new DiaRelationSchema($db); + $export->showOutput(); + return true; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaEps.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaEps.php new file mode 100644 index 0000000..4218376 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaEps.php @@ -0,0 +1,101 @@ +setProperties(); + } + + /** + * Sets the schema export EPS properties + * + * @return void + */ + protected function setProperties() + { + $schemaPluginProperties = new SchemaPluginProperties(); + $schemaPluginProperties->setText('EPS'); + $schemaPluginProperties->setExtension('eps'); + $schemaPluginProperties->setMimeType('application/eps'); + + // create the root group that will be the options field for + // $schemaPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup( + "Format Specific Options" + ); + + // specific options main group + $specificOptions = new OptionsPropertyMainGroup("general_opts"); + // add options common to all plugins + $this->addCommonOptions($specificOptions); + + // create leaf items and add them to the group + $leaf = new BoolPropertyItem( + 'all_tables_same_width', + __('Same width for all tables') + ); + $specificOptions->addProperty($leaf); + + $leaf = new SelectPropertyItem( + "orientation", + __('Orientation') + ); + $leaf->setValues( + [ + 'L' => __('Landscape'), + 'P' => __('Portrait'), + ] + ); + $specificOptions->addProperty($leaf); + + // add the main group to the root group + $exportSpecificOptions->addProperty($specificOptions); + + // set the options for the schema export plugin property item + $schemaPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $schemaPluginProperties; + } + + /** + * Exports the schema into EPS format. + * + * @param string $db database name + * + * @return bool Whether it succeeded + */ + public function exportSchema($db) + { + $export = new EpsRelationSchema($db); + $export->showOutput(); + return true; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaPdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaPdf.php new file mode 100644 index 0000000..c57fcee --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaPdf.php @@ -0,0 +1,133 @@ +setProperties(); + } + + /** + * Sets the schema export PDF properties + * + * @return void + */ + protected function setProperties() + { + $schemaPluginProperties = new SchemaPluginProperties(); + $schemaPluginProperties->setText('PDF'); + $schemaPluginProperties->setExtension('pdf'); + $schemaPluginProperties->setMimeType('application/pdf'); + + // create the root group that will be the options field for + // $schemaPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup( + "Format Specific Options" + ); + + // specific options main group + $specificOptions = new OptionsPropertyMainGroup("general_opts"); + // add options common to all plugins + $this->addCommonOptions($specificOptions); + + // create leaf items and add them to the group + $leaf = new BoolPropertyItem( + 'all_tables_same_width', + __('Same width for all tables') + ); + $specificOptions->addProperty($leaf); + + $leaf = new SelectPropertyItem( + "orientation", + __('Orientation') + ); + $leaf->setValues( + [ + 'L' => __('Landscape'), + 'P' => __('Portrait'), + ] + ); + $specificOptions->addProperty($leaf); + + $leaf = new SelectPropertyItem( + "paper", + __('Paper size') + ); + $leaf->setValues($this->getPaperSizeArray()); + $specificOptions->addProperty($leaf); + + $leaf = new BoolPropertyItem( + 'show_grid', + __('Show grid') + ); + $specificOptions->addProperty($leaf); + + $leaf = new BoolPropertyItem( + 'with_doc', + __('Data dictionary') + ); + $specificOptions->addProperty($leaf); + + $leaf = new SelectPropertyItem( + "table_order", + __('Order of the tables') + ); + $leaf->setValues( + [ + '' => __('None'), + 'name_asc' => __('Name (Ascending)'), + 'name_desc' => __('Name (Descending)'), + ] + ); + $specificOptions->addProperty($leaf); + + // add the main group to the root group + $exportSpecificOptions->addProperty($specificOptions); + + // set the options for the schema export plugin property item + $schemaPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $schemaPluginProperties; + } + + /** + * Exports the schema into PDF format. + * + * @param string $db database name + * + * @return bool Whether it succeeded + */ + public function exportSchema($db) + { + $export = new PdfRelationSchema($db); + $export->showOutput(); + return true; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaSvg.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaSvg.php new file mode 100644 index 0000000..9466f64 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/SchemaSvg.php @@ -0,0 +1,88 @@ +setProperties(); + } + + /** + * Sets the schema export SVG properties + * + * @return void + */ + protected function setProperties() + { + $schemaPluginProperties = new SchemaPluginProperties(); + $schemaPluginProperties->setText('SVG'); + $schemaPluginProperties->setExtension('svg'); + $schemaPluginProperties->setMimeType('application/svg'); + + // create the root group that will be the options field for + // $schemaPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup( + "Format Specific Options" + ); + + // specific options main group + $specificOptions = new OptionsPropertyMainGroup("general_opts"); + // add options common to all plugins + $this->addCommonOptions($specificOptions); + + // create leaf items and add them to the group + $leaf = new BoolPropertyItem( + 'all_tables_same_width', + __('Same width for all tables') + ); + $specificOptions->addProperty($leaf); + + // add the main group to the root group + $exportSpecificOptions->addProperty($specificOptions); + + // set the options for the schema export plugin property item + $schemaPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $schemaPluginProperties; + } + + /** + * Exports the schema into SVG format. + * + * @param string $db database name + * + * @return bool Whether it succeeded + */ + public function exportSchema($db) + { + $export = new SvgRelationSchema($db); + $export->showOutput(); + return true; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/RelationStatsSvg.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/RelationStatsSvg.php new file mode 100644 index 0000000..2e323fc --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/RelationStatsSvg.php @@ -0,0 +1,140 @@ +wTick = 10; + parent::__construct( + $diagram, + $master_table, + $master_field, + $foreign_table, + $foreign_field + ); + } + + /** + * draws relation links and arrows shows foreign key relations + * + * @param boolean $showColor Whether to use one color per relation or not + * + * @return void + * @access public + * + * @see PMA_SVG + */ + public function relationDraw($showColor) + { + if ($showColor) { + $listOfColors = [ + '#c00', + '#bbb', + '#333', + '#cb0', + '#0b0', + '#0bf', + '#b0b', + ]; + shuffle($listOfColors); + $color = $listOfColors[0]; + } else { + $color = '#333'; + } + + $this->diagram->printElementLine( + 'line', + $this->xSrc, + $this->ySrc, + $this->xSrc + $this->srcDir * $this->wTick, + $this->ySrc, + 'stroke:' . $color . ';stroke-width:1;' + ); + $this->diagram->printElementLine( + 'line', + $this->xDest + $this->destDir * $this->wTick, + $this->yDest, + $this->xDest, + $this->yDest, + 'stroke:' . $color . ';stroke-width:1;' + ); + $this->diagram->printElementLine( + 'line', + $this->xSrc + $this->srcDir * $this->wTick, + $this->ySrc, + $this->xDest + $this->destDir * $this->wTick, + $this->yDest, + 'stroke:' . $color . ';stroke-width:1;' + ); + $root2 = 2 * sqrt(2); + $this->diagram->printElementLine( + 'line', + $this->xSrc + $this->srcDir * $this->wTick * 0.75, + $this->ySrc, + $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, + $this->ySrc + $this->wTick / $root2, + 'stroke:' . $color . ';stroke-width:2;' + ); + $this->diagram->printElementLine( + 'line', + $this->xSrc + $this->srcDir * $this->wTick * 0.75, + $this->ySrc, + $this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick, + $this->ySrc - $this->wTick / $root2, + 'stroke:' . $color . ';stroke-width:2;' + ); + $this->diagram->printElementLine( + 'line', + $this->xDest + $this->destDir * $this->wTick / 2, + $this->yDest, + $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, + $this->yDest + $this->wTick / $root2, + 'stroke:' . $color . ';stroke-width:2;' + ); + $this->diagram->printElementLine( + 'line', + $this->xDest + $this->destDir * $this->wTick / 2, + $this->yDest, + $this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick, + $this->yDest - $this->wTick / $root2, + 'stroke:' . $color . ';stroke-width:2;' + ); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/Svg.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/Svg.php new file mode 100644 index 0000000..4404574 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/Svg.php @@ -0,0 +1,281 @@ +openMemory(); + /* + * Set indenting using three spaces, + * so output is formatted + */ + + $this->setIndent(true); + $this->setIndentString(' '); + /* + * Create the XML document + */ + + $this->startDocument('1.0', 'UTF-8'); + $this->startDtd( + 'svg', + '-//W3C//DTD SVG 1.1//EN', + 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' + ); + $this->endDtd(); + } + + /** + * Set document title + * + * @param string $value sets the title text + * + * @return void + */ + public function setTitle($value) + { + $this->title = $value; + } + + /** + * Set document author + * + * @param string $value sets the author + * + * @return void + */ + public function setAuthor($value) + { + $this->author = $value; + } + + /** + * Set document font + * + * @param string $value sets the font e.g Arial, Sans-serif etc + * + * @return void + */ + public function setFont($value) + { + $this->font = $value; + } + + /** + * Get document font + * + * @return string returns the font name + */ + public function getFont() + { + return $this->font; + } + + /** + * Set document font size + * + * @param integer $value sets the font size in pixels + * + * @return void + */ + public function setFontSize($value) + { + $this->fontSize = $value; + } + + /** + * Get document font size + * + * @return integer returns the font size + */ + public function getFontSize() + { + return $this->fontSize; + } + + /** + * Starts RelationStatsSvg Document + * + * svg document starts by first initializing svg tag + * which contains all the attributes and namespace that needed + * to define the svg document + * + * @param integer $width total width of the RelationStatsSvg document + * @param integer $height total height of the RelationStatsSvg document + * @param integer $x min-x of the view box + * @param integer $y min-y of the view box + * + * @return void + * + * @see XMLWriter::startElement(),XMLWriter::writeAttribute() + */ + public function startSvgDoc($width, $height, $x = 0, $y = 0) + { + $this->startElement('svg'); + + if (! is_int($width)) { + $width = intval($width); + } + + if (! is_int($height)) { + $height = intval($height); + } + + if ($x != 0 || $y != 0) { + $this->writeAttribute('viewBox', "$x $y $width $height"); + } + $this->writeAttribute('width', ($width - $x) . 'px'); + $this->writeAttribute('height', ($height - $y) . 'px'); + $this->writeAttribute('xmlns', 'http://www.w3.org/2000/svg'); + $this->writeAttribute('version', '1.1'); + } + + /** + * Ends RelationStatsSvg Document + * + * @return void + * @see XMLWriter::endElement(),XMLWriter::endDocument() + */ + public function endSvgDoc() + { + $this->endElement(); + $this->endDocument(); + } + + /** + * output RelationStatsSvg Document + * + * svg document prompted to the user for download + * RelationStatsSvg document saved in .svg extension and can be + * easily changeable by using any svg IDE + * + * @param string $fileName file name + * + * @return void + * @see XMLWriter::startElement(),XMLWriter::writeAttribute() + */ + public function showOutput($fileName) + { + //ob_get_clean(); + $output = $this->flush(); + Response::getInstance()->disable(); + Core::downloadHeader( + $fileName, + 'image/svg+xml', + strlen($output) + ); + print $output; + } + + /** + * Draws RelationStatsSvg elements + * + * SVG has some predefined shape elements like rectangle & text + * and other elements who have x,y co-ordinates are drawn. + * specify their width and height and can give styles too. + * + * @param string $name RelationStatsSvg element name + * @param int $x The x attr defines the left position of the element + * (e.g. x="0" places the element 0 pixels from the + * left of the browser window) + * @param integer $y The y attribute defines the top position of the + * element (e.g. y="0" places the element 0 pixels + * from the top of the browser window) + * @param int|string $width The width attribute defines the width the element + * @param int|string $height The height attribute defines the height the element + * @param string|null $text The text attribute defines the text the element + * @param string $styles The style attribute defines the style the element + * styles can be defined like CSS styles + * + * @return void + * + * @see XMLWriter::startElement(), XMLWriter::writeAttribute(), + * XMLWriter::text(), XMLWriter::endElement() + */ + public function printElement( + $name, + $x, + $y, + $width = '', + $height = '', + ?string $text = '', + $styles = '' + ) { + $this->startElement($name); + $this->writeAttribute('width', (string) $width); + $this->writeAttribute('height', (string) $height); + $this->writeAttribute('x', (string) $x); + $this->writeAttribute('y', (string) $y); + $this->writeAttribute('style', (string) $styles); + if (isset($text)) { + $this->writeAttribute('font-family', (string) $this->font); + $this->writeAttribute('font-size', $this->fontSize . 'px'); + $this->text($text); + } + $this->endElement(); + } + + /** + * Draws RelationStatsSvg Line element + * + * RelationStatsSvg line element is drawn for connecting the tables. + * arrows are also drawn by specify its start and ending + * co-ordinates + * + * @param string $name RelationStatsSvg element name i.e line + * @param integer $x1 Defines the start of the line on the x-axis + * @param integer $y1 Defines the start of the line on the y-axis + * @param integer $x2 Defines the end of the line on the x-axis + * @param integer $y2 Defines the end of the line on the y-axis + * @param string $styles The style attribute defines the style the element + * styles can be defined like CSS styles + * + * @return void + * + * @see XMLWriter::startElement(), XMLWriter::writeAttribute(), + * XMLWriter::endElement() + */ + public function printElementLine($name, $x1, $y1, $x2, $y2, $styles) + { + $this->startElement($name); + $this->writeAttribute('x1', $x1); + $this->writeAttribute('y1', $y1); + $this->writeAttribute('x2', $x2); + $this->writeAttribute('y2', $y2); + $this->writeAttribute('style', $styles); + $this->endElement(); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/SvgRelationSchema.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/SvgRelationSchema.php new file mode 100644 index 0000000..9a18b6e --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/SvgRelationSchema.php @@ -0,0 +1,284 @@ +setShowColor(isset($_REQUEST['svg_show_color'])); + $this->setShowKeys(isset($_REQUEST['svg_show_keys'])); + $this->setTableDimension(isset($_REQUEST['svg_show_table_dimension'])); + $this->setAllTablesSameWidth(isset($_REQUEST['svg_all_tables_same_width'])); + + $this->diagram->setTitle( + sprintf( + __('Schema of the %s database - Page %s'), + $this->db, + $this->pageNumber + ) + ); + $this->diagram->SetAuthor('phpMyAdmin ' . PMA_VERSION); + $this->diagram->setFont('Arial'); + $this->diagram->setFontSize(16); + + $alltables = $this->getTablesFromRequest(); + + foreach ($alltables as $table) { + if (! isset($this->_tables[$table])) { + $this->_tables[$table] = new TableStatsSvg( + $this->diagram, + $this->db, + $table, + $this->diagram->getFont(), + $this->diagram->getFontSize(), + $this->pageNumber, + $this->_tablewidth, + $this->showKeys, + $this->tableDimension, + $this->offline + ); + } + + if ($this->sameWide) { + $this->_tables[$table]->width = &$this->_tablewidth; + } + $this->_setMinMax($this->_tables[$table]); + } + + $border = 15; + $this->diagram->startSvgDoc( + $this->_xMax + $border, + $this->_yMax + $border, + $this->_xMin - $border, + $this->_yMin - $border + ); + + $seen_a_relation = false; + foreach ($alltables as $one_table) { + $exist_rel = $this->relation->getForeigners($this->db, $one_table, '', 'both'); + if (! $exist_rel) { + continue; + } + + $seen_a_relation = true; + foreach ($exist_rel as $master_field => $rel) { + /* put the foreign table on the schema only if selected + * by the user + * (do not use array_search() because we would have to + * to do a === false and this is not PHP3 compatible) + */ + if ($master_field != 'foreign_keys_data') { + if (in_array($rel['foreign_table'], $alltables)) { + $this->_addRelation( + $one_table, + $this->diagram->getFont(), + $this->diagram->getFontSize(), + $master_field, + $rel['foreign_table'], + $rel['foreign_field'], + $this->tableDimension + ); + } + continue; + } + + foreach ($rel as $one_key) { + if (! in_array($one_key['ref_table_name'], $alltables)) { + continue; + } + + foreach ($one_key['index_list'] as $index => $one_field) { + $this->_addRelation( + $one_table, + $this->diagram->getFont(), + $this->diagram->getFontSize(), + $one_field, + $one_key['ref_table_name'], + $one_key['ref_index_list'][$index], + $this->tableDimension + ); + } + } + } + } + if ($seen_a_relation) { + $this->_drawRelations(); + } + + $this->_drawTables(); + $this->diagram->endSvgDoc(); + } + + /** + * Output RelationStatsSvg Document for download + * + * @return void + */ + public function showOutput() + { + $this->diagram->showOutput($this->getFileName('.svg')); + } + + /** + * Sets X and Y minimum and maximum for a table cell + * + * @param TableStatsSvg $table The table + * + * @return void + */ + private function _setMinMax($table) + { + $this->_xMax = max($this->_xMax, $table->x + $table->width); + $this->_yMax = max($this->_yMax, $table->y + $table->height); + $this->_xMin = min($this->_xMin, $table->x); + $this->_yMin = min($this->_yMin, $table->y); + } + + /** + * Defines relation objects + * + * @param string $masterTable The master table name + * @param string $font The font face + * @param int $fontSize Font size + * @param string $masterField The relation field in the master table + * @param string $foreignTable The foreign table name + * @param string $foreignField The relation field in the foreign table + * @param boolean $tableDimension Whether to display table position or not + * + * @return void + * + * @see _setMinMax,Table_Stats_Svg::__construct(), + * PhpMyAdmin\Plugins\Schema\Svg\RelationStatsSvg::__construct() + */ + private function _addRelation( + $masterTable, + $font, + $fontSize, + $masterField, + $foreignTable, + $foreignField, + $tableDimension + ) { + if (! isset($this->_tables[$masterTable])) { + $this->_tables[$masterTable] = new TableStatsSvg( + $this->diagram, + $this->db, + $masterTable, + $font, + $fontSize, + $this->pageNumber, + $this->_tablewidth, + false, + $tableDimension + ); + $this->_setMinMax($this->_tables[$masterTable]); + } + if (! isset($this->_tables[$foreignTable])) { + $this->_tables[$foreignTable] = new TableStatsSvg( + $this->diagram, + $this->db, + $foreignTable, + $font, + $fontSize, + $this->pageNumber, + $this->_tablewidth, + false, + $tableDimension + ); + $this->_setMinMax($this->_tables[$foreignTable]); + } + $this->_relations[] = new RelationStatsSvg( + $this->diagram, + $this->_tables[$masterTable], + $masterField, + $this->_tables[$foreignTable], + $foreignField + ); + } + + /** + * Draws relation arrows and lines + * connects master table's master field to + * foreign table's foreign field + * + * @return void + * + * @see Relation_Stats_Svg::relationDraw() + */ + private function _drawRelations() + { + foreach ($this->_relations as $relation) { + $relation->relationDraw($this->showColor); + } + } + + /** + * Draws tables + * + * @return void + * + * @see Table_Stats_Svg::Table_Stats_tableDraw() + */ + private function _drawTables() + { + foreach ($this->_tables as $table) { + $table->tableDraw($this->showColor); + } + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/TableStatsSvg.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/TableStatsSvg.php new file mode 100644 index 0000000..13b1a82 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/Svg/TableStatsSvg.php @@ -0,0 +1,204 @@ +_setHeightTable($fontSize); + // setWidth must me after setHeight, because title + // can include table height which changes table width + $this->_setWidthTable($font, $fontSize); + if ($same_wide_width < $this->width) { + $same_wide_width = $this->width; + } + } + + /** + * Displays an error when the table cannot be found. + * + * @return void + */ + protected function showMissingTableError() + { + ExportRelationSchema::dieSchema( + $this->pageNumber, + "SVG", + sprintf(__('The %s table doesn\'t exist!'), $this->tableName) + ); + } + + /** + * Sets the width of the table + * + * @param string $font The font size + * @param integer $fontSize The font size + * + * @return void + * @access private + * + * @see PMA_SVG + */ + private function _setWidthTable($font, $fontSize) + { + foreach ($this->fields as $field) { + $this->width = max( + $this->width, + $this->font->getStringWidth($field, $font, $fontSize) + ); + } + $this->width += $this->font->getStringWidth(' ', $font, $fontSize); + + /* + * it is unknown what value must be added, because + * table title is affected by the table width value + */ + while ($this->width + < $this->font->getStringWidth($this->getTitle(), $font, $fontSize) + ) { + $this->width += 7; + } + } + + /** + * Sets the height of the table + * + * @param integer $fontSize font size + * + * @return void + */ + private function _setHeightTable($fontSize) + { + $this->heightCell = $fontSize + 4; + $this->height = (count($this->fields) + 1) * $this->heightCell; + } + + /** + * draw the table + * + * @param boolean $showColor Whether to display color + * + * @access public + * @return void + * + * @see PMA_SVG,PMA_SVG::printElement + */ + public function tableDraw($showColor) + { + $this->diagram->printElement( + 'rect', + $this->x, + $this->y, + $this->width, + $this->heightCell, + null, + 'fill:#007;stroke:black;' + ); + $this->diagram->printElement( + 'text', + $this->x + 5, + $this->y + 14, + $this->width, + $this->heightCell, + $this->getTitle(), + 'fill:#fff;' + ); + foreach ($this->fields as $field) { + $this->currentCell += $this->heightCell; + $fillColor = 'none'; + if ($showColor) { + if (in_array($field, $this->primary)) { + $fillColor = '#aea'; + } + if ($field == $this->displayfield) { + $fillColor = 'none'; + } + } + $this->diagram->printElement( + 'rect', + $this->x, + $this->y + $this->currentCell, + $this->width, + $this->heightCell, + null, + 'fill:' . $fillColor . ';stroke:black;' + ); + $this->diagram->printElement( + 'text', + $this->x + 5, + $this->y + 14 + $this->currentCell, + $this->width, + $this->heightCell, + $field, + 'fill:black;' + ); + } + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Schema/TableStats.php b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/TableStats.php new file mode 100644 index 0000000..a3d3b5c --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Plugins/Schema/TableStats.php @@ -0,0 +1,208 @@ +diagram = $diagram; + $this->db = $db; + $this->pageNumber = $pageNumber; + $this->tableName = $tableName; + + $this->showKeys = $showKeys; + $this->tableDimension = $tableDimension; + + $this->offline = $offline; + + $this->relation = new Relation($GLOBALS['dbi']); + $this->font = new Font(); + + // checks whether the table exists + // and loads fields + $this->validateTableAndLoadFields(); + // load table coordinates + $this->loadCoordinates(); + // loads display field + $this->loadDisplayField(); + // loads primary keys + $this->loadPrimaryKey(); + } + + /** + * Validate whether the table exists. + * + * @return void + */ + protected function validateTableAndLoadFields() + { + $sql = 'DESCRIBE ' . Util::backquote($this->tableName); + $result = $GLOBALS['dbi']->tryQuery( + $sql, + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_STORE + ); + if (! $result || ! $GLOBALS['dbi']->numRows($result)) { + $this->showMissingTableError(); + } + + if ($this->showKeys) { + $indexes = Index::getFromTable($this->tableName, $this->db); + $all_columns = []; + foreach ($indexes as $index) { + $all_columns = array_merge( + $all_columns, + array_flip(array_keys($index->getColumns())) + ); + } + $this->fields = array_keys($all_columns); + } else { + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + $this->fields[] = $row[0]; + } + } + } + + /** + * Displays an error when the table cannot be found. + * + * @return void + * @abstract + */ + abstract protected function showMissingTableError(); + + /** + * Loads coordinates of a table + * + * @return void + */ + protected function loadCoordinates() + { + if (isset($_POST['t_h'])) { + foreach ($_POST['t_h'] as $key => $value) { + $db = rawurldecode($_POST['t_db'][$key]); + $tbl = rawurldecode($_POST['t_tbl'][$key]); + if ($this->db . '.' . $this->tableName === $db . '.' . $tbl) { + $this->x = (double) $_POST['t_x'][$key]; + $this->y = (double) $_POST['t_y'][$key]; + break; + } + } + } + } + + /** + * Loads the table's display field + * + * @return void + */ + protected function loadDisplayField() + { + $this->displayfield = $this->relation->getDisplayField($this->db, $this->tableName); + } + + /** + * Loads the PRIMARY key. + * + * @return void + */ + protected function loadPrimaryKey() + { + $result = $GLOBALS['dbi']->query( + 'SHOW INDEX FROM ' . Util::backquote($this->tableName) . ';', + DatabaseInterface::CONNECT_USER, + DatabaseInterface::QUERY_STORE + ); + if ($GLOBALS['dbi']->numRows($result) > 0) { + while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { + if ($row['Key_name'] == 'PRIMARY') { + $this->primary[] = $row['Column_name']; + } + } + } + } + + /** + * Returns title of the current table, + * title can have the dimensions/co-ordinates of the table + * + * @return string title of the current table + */ + protected function getTitle() + { + return ($this->tableDimension + ? sprintf('%.0fx%0.f', $this->width, $this->heightCell) + : '' + ) + . ' ' . $this->tableName; + } +} -- cgit