PdfRelationSchema.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * PDF schema handling
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. declare(strict_types=1);
  9. namespace PhpMyAdmin\Plugins\Schema\Pdf;
  10. use PhpMyAdmin\Pdf as PdfLib;
  11. use PhpMyAdmin\Plugins\Schema\ExportRelationSchema;
  12. use PhpMyAdmin\Relation;
  13. use PhpMyAdmin\Transformations;
  14. use PhpMyAdmin\Util;
  15. /**
  16. * Skip the plugin if TCPDF is not available.
  17. */
  18. if (! class_exists('TCPDF')) {
  19. $GLOBALS['skip_import'] = true;
  20. return;
  21. }
  22. /**
  23. * block attempts to directly run this script
  24. */
  25. if (getcwd() == __DIR__) {
  26. die('Attack stopped');
  27. }
  28. /**
  29. * Pdf Relation Schema Class
  30. *
  31. * Purpose of this class is to generate the PDF Document. PDF is widely
  32. * used format for documenting text,fonts,images and 3d vector graphics.
  33. *
  34. * This class inherits ExportRelationSchema class has common functionality added
  35. * to this class
  36. *
  37. * @name Pdf_Relation_Schema
  38. * @package PhpMyAdmin
  39. */
  40. class PdfRelationSchema extends ExportRelationSchema
  41. {
  42. /**
  43. * Defines properties
  44. */
  45. private $_showGrid;
  46. private $_withDoc;
  47. private $_tableOrder;
  48. /**
  49. * @var TableStatsPdf[]
  50. */
  51. private $_tables = [];
  52. private $_ff = PdfLib::PMA_PDF_FONT;
  53. private $_xMax = 0;
  54. private $_yMax = 0;
  55. private $_scale;
  56. private $_xMin = 100000;
  57. private $_yMin = 100000;
  58. private $_topMargin = 10;
  59. private $_bottomMargin = 10;
  60. private $_leftMargin = 10;
  61. private $_rightMargin = 10;
  62. private $_tablewidth;
  63. /**
  64. * @var RelationStatsPdf[]
  65. */
  66. protected $relations = [];
  67. /**
  68. * @var Transformations
  69. */
  70. private $transformations;
  71. /**
  72. * The "PdfRelationSchema" constructor
  73. *
  74. * @param string $db database name
  75. *
  76. * @see PMA_Schema_PDF
  77. */
  78. public function __construct($db)
  79. {
  80. $this->transformations = new Transformations();
  81. $this->setShowGrid(isset($_REQUEST['pdf_show_grid']));
  82. $this->setShowColor(isset($_REQUEST['pdf_show_color']));
  83. $this->setShowKeys(isset($_REQUEST['pdf_show_keys']));
  84. $this->setTableDimension(isset($_REQUEST['pdf_show_table_dimension']));
  85. $this->setAllTablesSameWidth(isset($_REQUEST['pdf_all_tables_same_width']));
  86. $this->setWithDataDictionary(isset($_REQUEST['pdf_with_doc']));
  87. $this->setTableOrder($_REQUEST['pdf_table_order']);
  88. $this->setOrientation($_REQUEST['pdf_orientation']);
  89. $this->setPaper($_REQUEST['pdf_paper']);
  90. // Initializes a new document
  91. parent::__construct(
  92. $db,
  93. new Pdf(
  94. $this->orientation,
  95. 'mm',
  96. $this->paper,
  97. $this->pageNumber,
  98. $this->_withDoc,
  99. $db
  100. )
  101. );
  102. $this->diagram->SetTitle(
  103. sprintf(
  104. __('Schema of the %s database'),
  105. $this->db
  106. )
  107. );
  108. $this->diagram->setCMargin(0);
  109. $this->diagram->Open();
  110. $this->diagram->SetAutoPageBreak('auto');
  111. $this->diagram->setOffline($this->offline);
  112. $alltables = $this->getTablesFromRequest();
  113. if ($this->getTableOrder() == 'name_asc') {
  114. sort($alltables);
  115. } elseif ($this->getTableOrder() == 'name_desc') {
  116. rsort($alltables);
  117. }
  118. if ($this->_withDoc) {
  119. $this->diagram->SetAutoPageBreak('auto', 15);
  120. $this->diagram->setCMargin(1);
  121. $this->dataDictionaryDoc($alltables);
  122. $this->diagram->SetAutoPageBreak('auto');
  123. $this->diagram->setCMargin(0);
  124. }
  125. $this->diagram->AddPage();
  126. if ($this->_withDoc) {
  127. $this->diagram->SetLink($this->diagram->PMA_links['RT']['-'], -1);
  128. $this->diagram->Bookmark(__('Relational schema'));
  129. $this->diagram->setAlias('{00}', $this->diagram->PageNo());
  130. $this->_topMargin = 28;
  131. $this->_bottomMargin = 28;
  132. }
  133. /* snip */
  134. foreach ($alltables as $table) {
  135. if (! isset($this->_tables[$table])) {
  136. $this->_tables[$table] = new TableStatsPdf(
  137. $this->diagram,
  138. $this->db,
  139. $table,
  140. null,
  141. $this->pageNumber,
  142. $this->_tablewidth,
  143. $this->showKeys,
  144. $this->tableDimension,
  145. $this->offline
  146. );
  147. }
  148. if ($this->sameWide) {
  149. $this->_tables[$table]->width = $this->_tablewidth;
  150. }
  151. $this->_setMinMax($this->_tables[$table]);
  152. }
  153. // Defines the scale factor
  154. $innerWidth = $this->diagram->getPageWidth() - $this->_rightMargin
  155. - $this->_leftMargin;
  156. $innerHeight = $this->diagram->getPageHeight() - $this->_topMargin
  157. - $this->_bottomMargin;
  158. $this->_scale = ceil(
  159. max(
  160. ($this->_xMax - $this->_xMin) / $innerWidth,
  161. ($this->_yMax - $this->_yMin) / $innerHeight
  162. ) * 100
  163. ) / 100;
  164. $this->diagram->setScale(
  165. $this->_scale,
  166. $this->_xMin,
  167. $this->_yMin,
  168. $this->_leftMargin,
  169. $this->_topMargin
  170. );
  171. // Builds and save the PDF document
  172. $this->diagram->setLineWidthScale(0.1);
  173. if ($this->_showGrid) {
  174. $this->diagram->SetFontSize(10);
  175. $this->_strokeGrid();
  176. }
  177. $this->diagram->setFontSizeScale(14);
  178. // previous logic was checking master tables and foreign tables
  179. // but I think that looping on every table of the pdf page as a master
  180. // and finding its foreigns is OK (then we can support innodb)
  181. $seen_a_relation = false;
  182. foreach ($alltables as $one_table) {
  183. $exist_rel = $this->relation->getForeigners($this->db, $one_table, '', 'both');
  184. if (! $exist_rel) {
  185. continue;
  186. }
  187. $seen_a_relation = true;
  188. foreach ($exist_rel as $master_field => $rel) {
  189. // put the foreign table on the schema only if selected
  190. // by the user
  191. // (do not use array_search() because we would have to
  192. // to do a === false and this is not PHP3 compatible)
  193. if ($master_field != 'foreign_keys_data') {
  194. if (in_array($rel['foreign_table'], $alltables)) {
  195. $this->_addRelation(
  196. $one_table,
  197. $master_field,
  198. $rel['foreign_table'],
  199. $rel['foreign_field']
  200. );
  201. }
  202. continue;
  203. }
  204. foreach ($rel as $one_key) {
  205. if (! in_array($one_key['ref_table_name'], $alltables)) {
  206. continue;
  207. }
  208. foreach ($one_key['index_list'] as $index => $one_field) {
  209. $this->_addRelation(
  210. $one_table,
  211. $one_field,
  212. $one_key['ref_table_name'],
  213. $one_key['ref_index_list'][$index]
  214. );
  215. }
  216. }
  217. } // end while
  218. } // end while
  219. if ($seen_a_relation) {
  220. $this->_drawRelations();
  221. }
  222. $this->_drawTables();
  223. }
  224. /**
  225. * Set Show Grid
  226. *
  227. * @param boolean $value show grid of the document or not
  228. *
  229. * @return void
  230. */
  231. public function setShowGrid($value)
  232. {
  233. $this->_showGrid = $value;
  234. }
  235. /**
  236. * Returns whether to show grid
  237. *
  238. * @return boolean whether to show grid
  239. */
  240. public function isShowGrid()
  241. {
  242. return $this->_showGrid;
  243. }
  244. /**
  245. * Set Data Dictionary
  246. *
  247. * @param boolean $value show selected database data dictionary or not
  248. *
  249. * @return void
  250. */
  251. public function setWithDataDictionary($value)
  252. {
  253. $this->_withDoc = $value;
  254. }
  255. /**
  256. * Return whether to show selected database data dictionary or not
  257. *
  258. * @return boolean whether to show selected database data dictionary or not
  259. */
  260. public function isWithDataDictionary()
  261. {
  262. return $this->_withDoc;
  263. }
  264. /**
  265. * Sets the order of the table in data dictionary
  266. *
  267. * @param string $value table order
  268. *
  269. * @return void
  270. */
  271. public function setTableOrder($value)
  272. {
  273. $this->_tableOrder = $value;
  274. }
  275. /**
  276. * Returns the order of the table in data dictionary
  277. *
  278. * @return string table order
  279. */
  280. public function getTableOrder()
  281. {
  282. return $this->_tableOrder;
  283. }
  284. /**
  285. * Output Pdf Document for download
  286. *
  287. * @return void
  288. */
  289. public function showOutput()
  290. {
  291. $this->diagram->download($this->getFileName('.pdf'));
  292. }
  293. /**
  294. * Sets X and Y minimum and maximum for a table cell
  295. *
  296. * @param TableStatsPdf $table The table name of which sets XY co-ordinates
  297. *
  298. * @return void
  299. */
  300. private function _setMinMax($table)
  301. {
  302. $this->_xMax = max($this->_xMax, $table->x + $table->width);
  303. $this->_yMax = max($this->_yMax, $table->y + $table->height);
  304. $this->_xMin = min($this->_xMin, $table->x);
  305. $this->_yMin = min($this->_yMin, $table->y);
  306. }
  307. /**
  308. * Defines relation objects
  309. *
  310. * @param string $masterTable The master table name
  311. * @param string $masterField The relation field in the master table
  312. * @param string $foreignTable The foreign table name
  313. * @param string $foreignField The relation field in the foreign table
  314. *
  315. * @return void
  316. *
  317. * @see _setMinMax
  318. */
  319. private function _addRelation(
  320. $masterTable,
  321. $masterField,
  322. $foreignTable,
  323. $foreignField
  324. ) {
  325. if (! isset($this->_tables[$masterTable])) {
  326. $this->_tables[$masterTable] = new TableStatsPdf(
  327. $this->diagram,
  328. $this->db,
  329. $masterTable,
  330. null,
  331. $this->pageNumber,
  332. $this->_tablewidth,
  333. $this->showKeys,
  334. $this->tableDimension
  335. );
  336. $this->_setMinMax($this->_tables[$masterTable]);
  337. }
  338. if (! isset($this->_tables[$foreignTable])) {
  339. $this->_tables[$foreignTable] = new TableStatsPdf(
  340. $this->diagram,
  341. $this->db,
  342. $foreignTable,
  343. null,
  344. $this->pageNumber,
  345. $this->_tablewidth,
  346. $this->showKeys,
  347. $this->tableDimension
  348. );
  349. $this->_setMinMax($this->_tables[$foreignTable]);
  350. }
  351. $this->relations[] = new RelationStatsPdf(
  352. $this->diagram,
  353. $this->_tables[$masterTable],
  354. $masterField,
  355. $this->_tables[$foreignTable],
  356. $foreignField
  357. );
  358. }
  359. /**
  360. * Draws the grid
  361. *
  362. * @return void
  363. *
  364. * @see PMA_Schema_PDF
  365. */
  366. private function _strokeGrid()
  367. {
  368. $gridSize = 10;
  369. $labelHeight = 4;
  370. $labelWidth = 5;
  371. if ($this->_withDoc) {
  372. $topSpace = 6;
  373. $bottomSpace = 15;
  374. } else {
  375. $topSpace = 0;
  376. $bottomSpace = 0;
  377. }
  378. $this->diagram->SetMargins(0, 0);
  379. $this->diagram->SetDrawColor(200, 200, 200);
  380. // Draws horizontal lines
  381. $innerHeight = $this->diagram->getPageHeight() - $topSpace - $bottomSpace;
  382. for ($l = 0, $size = intval($innerHeight / $gridSize); $l <= $size; $l++) {
  383. $this->diagram->line(
  384. 0,
  385. $l * $gridSize + $topSpace,
  386. $this->diagram->getPageWidth(),
  387. $l * $gridSize + $topSpace
  388. );
  389. // Avoid duplicates
  390. if ($l > 0
  391. && $l <= intval(($innerHeight - $labelHeight) / $gridSize)
  392. ) {
  393. $this->diagram->SetXY(0, $l * $gridSize + $topSpace);
  394. $label = (string) sprintf(
  395. '%.0f',
  396. ($l * $gridSize + $topSpace - $this->_topMargin)
  397. * $this->_scale + $this->_yMin
  398. );
  399. $this->diagram->Cell($labelWidth, $labelHeight, ' ' . $label);
  400. } // end if
  401. } // end for
  402. // Draws vertical lines
  403. for ($j = 0, $size = intval($this->diagram->getPageWidth() / $gridSize); $j <= $size; $j++) {
  404. $this->diagram->line(
  405. $j * $gridSize,
  406. $topSpace,
  407. $j * $gridSize,
  408. $this->diagram->getPageHeight() - $bottomSpace
  409. );
  410. $this->diagram->SetXY($j * $gridSize, $topSpace);
  411. $label = (string) sprintf(
  412. '%.0f',
  413. ($j * $gridSize - $this->_leftMargin) * $this->_scale + $this->_xMin
  414. );
  415. $this->diagram->Cell($labelWidth, $labelHeight, $label);
  416. }
  417. }
  418. /**
  419. * Draws relation arrows
  420. *
  421. * @return void
  422. *
  423. * @see Relation_Stats_Pdf::relationdraw()
  424. */
  425. private function _drawRelations()
  426. {
  427. $i = 0;
  428. foreach ($this->relations as $relation) {
  429. $relation->relationDraw($this->showColor, $i);
  430. $i++;
  431. }
  432. }
  433. /**
  434. * Draws tables
  435. *
  436. * @return void
  437. *
  438. * @see Table_Stats_Pdf::tableDraw()
  439. */
  440. private function _drawTables()
  441. {
  442. foreach ($this->_tables as $table) {
  443. $table->tableDraw(null, $this->_withDoc, $this->showColor);
  444. }
  445. }
  446. /**
  447. * Generates data dictionary pages.
  448. *
  449. * @param array $alltables Tables to document.
  450. *
  451. * @return void
  452. */
  453. public function dataDictionaryDoc(array $alltables)
  454. {
  455. // TOC
  456. $this->diagram->AddPage($this->orientation);
  457. $this->diagram->Cell(0, 9, __('Table of contents'), 1, 0, 'C');
  458. $this->diagram->Ln(15);
  459. $i = 1;
  460. foreach ($alltables as $table) {
  461. $this->diagram->PMA_links['doc'][$table]['-']
  462. = $this->diagram->AddLink();
  463. $this->diagram->SetX(10);
  464. // $this->diagram->Ln(1);
  465. $this->diagram->Cell(
  466. 0,
  467. 6,
  468. __('Page number:') . ' {' . sprintf("%02d", $i) . '}',
  469. 0,
  470. 0,
  471. 'R',
  472. 0,
  473. $this->diagram->PMA_links['doc'][$table]['-']
  474. );
  475. $this->diagram->SetX(10);
  476. $this->diagram->Cell(
  477. 0,
  478. 6,
  479. $i . ' ' . $table,
  480. 0,
  481. 1,
  482. 'L',
  483. 0,
  484. $this->diagram->PMA_links['doc'][$table]['-']
  485. );
  486. // $this->diagram->Ln(1);
  487. $fields = $GLOBALS['dbi']->getColumns($this->db, $table);
  488. foreach ($fields as $row) {
  489. $this->diagram->SetX(20);
  490. $field_name = $row['Field'];
  491. $this->diagram->PMA_links['doc'][$table][$field_name]
  492. = $this->diagram->AddLink();
  493. //$this->diagram->Cell(
  494. // 0, 6, $field_name, 0, 1,
  495. // 'L', 0, $this->diagram->PMA_links['doc'][$table][$field_name]
  496. //);
  497. }
  498. $i++;
  499. }
  500. $this->diagram->PMA_links['RT']['-'] = $this->diagram->AddLink();
  501. $this->diagram->SetX(10);
  502. $this->diagram->Cell(
  503. 0,
  504. 6,
  505. __('Page number:') . ' {00}',
  506. 0,
  507. 0,
  508. 'R',
  509. 0,
  510. $this->diagram->PMA_links['RT']['-']
  511. );
  512. $this->diagram->SetX(10);
  513. $this->diagram->Cell(
  514. 0,
  515. 6,
  516. $i . ' ' . __('Relational schema'),
  517. 0,
  518. 1,
  519. 'L',
  520. 0,
  521. $this->diagram->PMA_links['RT']['-']
  522. );
  523. $z = 0;
  524. foreach ($alltables as $table) {
  525. $z++;
  526. $this->diagram->SetAutoPageBreak(true, 15);
  527. $this->diagram->AddPage($this->orientation);
  528. $this->diagram->Bookmark($table);
  529. $this->diagram->setAlias(
  530. '{' . sprintf("%02d", $z) . '}',
  531. $this->diagram->PageNo()
  532. );
  533. $this->diagram->PMA_links['RT'][$table]['-']
  534. = $this->diagram->AddLink();
  535. $this->diagram->SetLink(
  536. $this->diagram->PMA_links['doc'][$table]['-'],
  537. -1
  538. );
  539. $this->diagram->SetFont($this->_ff, 'B', 18);
  540. $this->diagram->Cell(
  541. 0,
  542. 8,
  543. $z . ' ' . $table,
  544. 1,
  545. 1,
  546. 'C',
  547. 0,
  548. $this->diagram->PMA_links['RT'][$table]['-']
  549. );
  550. $this->diagram->SetFont($this->_ff, '', 8);
  551. $this->diagram->Ln();
  552. $cfgRelation = $this->relation->getRelationsParam();
  553. $comments = $this->relation->getComments($this->db, $table);
  554. if ($cfgRelation['mimework']) {
  555. $mime_map = $this->transformations->getMime($this->db, $table, true);
  556. }
  557. /**
  558. * Gets table information
  559. */
  560. $showtable = $GLOBALS['dbi']->getTable($this->db, $table)
  561. ->getStatusInfo();
  562. $show_comment = isset($showtable['Comment'])
  563. ? $showtable['Comment']
  564. : '';
  565. $create_time = isset($showtable['Create_time'])
  566. ? Util::localisedDate(
  567. strtotime($showtable['Create_time'])
  568. )
  569. : '';
  570. $update_time = isset($showtable['Update_time'])
  571. ? Util::localisedDate(
  572. strtotime($showtable['Update_time'])
  573. )
  574. : '';
  575. $check_time = isset($showtable['Check_time'])
  576. ? Util::localisedDate(
  577. strtotime($showtable['Check_time'])
  578. )
  579. : '';
  580. /**
  581. * Gets fields properties
  582. */
  583. $columns = $GLOBALS['dbi']->getColumns($this->db, $table);
  584. // Find which tables are related with the current one and write it in
  585. // an array
  586. $res_rel = $this->relation->getForeigners($this->db, $table);
  587. /**
  588. * Displays the comments of the table if MySQL >= 3.23
  589. */
  590. $break = false;
  591. if (! empty($show_comment)) {
  592. $this->diagram->Cell(
  593. 0,
  594. 3,
  595. __('Table comments:') . ' ' . $show_comment,
  596. 0,
  597. 1
  598. );
  599. $break = true;
  600. }
  601. if (! empty($create_time)) {
  602. $this->diagram->Cell(
  603. 0,
  604. 3,
  605. __('Creation:') . ' ' . $create_time,
  606. 0,
  607. 1
  608. );
  609. $break = true;
  610. }
  611. if (! empty($update_time)) {
  612. $this->diagram->Cell(
  613. 0,
  614. 3,
  615. __('Last update:') . ' ' . $update_time,
  616. 0,
  617. 1
  618. );
  619. $break = true;
  620. }
  621. if (! empty($check_time)) {
  622. $this->diagram->Cell(
  623. 0,
  624. 3,
  625. __('Last check:') . ' ' . $check_time,
  626. 0,
  627. 1
  628. );
  629. $break = true;
  630. }
  631. if ($break == true) {
  632. $this->diagram->Cell(0, 3, '', 0, 1);
  633. $this->diagram->Ln();
  634. }
  635. $this->diagram->SetFont($this->_ff, 'B');
  636. if (isset($this->orientation) && $this->orientation == 'L') {
  637. $this->diagram->Cell(25, 8, __('Column'), 1, 0, 'C');
  638. $this->diagram->Cell(20, 8, __('Type'), 1, 0, 'C');
  639. $this->diagram->Cell(20, 8, __('Attributes'), 1, 0, 'C');
  640. $this->diagram->Cell(10, 8, __('Null'), 1, 0, 'C');
  641. $this->diagram->Cell(20, 8, __('Default'), 1, 0, 'C');
  642. $this->diagram->Cell(25, 8, __('Extra'), 1, 0, 'C');
  643. $this->diagram->Cell(45, 8, __('Links to'), 1, 0, 'C');
  644. if ($this->paper == 'A4') {
  645. $comments_width = 67;
  646. } else {
  647. // this is really intended for 'letter'
  648. /**
  649. * @todo find optimal width for all formats
  650. */
  651. $comments_width = 50;
  652. }
  653. $this->diagram->Cell($comments_width, 8, __('Comments'), 1, 0, 'C');
  654. $this->diagram->Cell(45, 8, 'MIME', 1, 1, 'C');
  655. $this->diagram->setWidths(
  656. [
  657. 25,
  658. 20,
  659. 20,
  660. 10,
  661. 20,
  662. 25,
  663. 45,
  664. $comments_width,
  665. 45,
  666. ]
  667. );
  668. } else {
  669. $this->diagram->Cell(20, 8, __('Column'), 1, 0, 'C');
  670. $this->diagram->Cell(20, 8, __('Type'), 1, 0, 'C');
  671. $this->diagram->Cell(20, 8, __('Attributes'), 1, 0, 'C');
  672. $this->diagram->Cell(10, 8, __('Null'), 1, 0, 'C');
  673. $this->diagram->Cell(15, 8, __('Default'), 1, 0, 'C');
  674. $this->diagram->Cell(15, 8, __('Extra'), 1, 0, 'C');
  675. $this->diagram->Cell(30, 8, __('Links to'), 1, 0, 'C');
  676. $this->diagram->Cell(30, 8, __('Comments'), 1, 0, 'C');
  677. $this->diagram->Cell(30, 8, 'MIME', 1, 1, 'C');
  678. $this->diagram->setWidths([20, 20, 20, 10, 15, 15, 30, 30, 30]);
  679. }
  680. $this->diagram->SetFont($this->_ff, '');
  681. foreach ($columns as $row) {
  682. $extracted_columnspec
  683. = Util::extractColumnSpec($row['Type']);
  684. $type = $extracted_columnspec['print_type'];
  685. $attribute = $extracted_columnspec['attribute'];
  686. if (! isset($row['Default'])) {
  687. if ($row['Null'] != '' && $row['Null'] != 'NO') {
  688. $row['Default'] = 'NULL';
  689. }
  690. }
  691. $field_name = $row['Field'];
  692. // $this->diagram->Ln();
  693. $this->diagram->PMA_links['RT'][$table][$field_name]
  694. = $this->diagram->AddLink();
  695. $this->diagram->Bookmark($field_name, 1, -1);
  696. $this->diagram->SetLink(
  697. $this->diagram->PMA_links['doc'][$table][$field_name],
  698. -1
  699. );
  700. $foreigner = $this->relation->searchColumnInForeigners($res_rel, $field_name);
  701. $linksTo = '';
  702. if ($foreigner) {
  703. $linksTo = '-> ';
  704. if ($foreigner['foreign_db'] != $this->db) {
  705. $linksTo .= $foreigner['foreign_db'] . '.';
  706. }
  707. $linksTo .= $foreigner['foreign_table']
  708. . '.' . $foreigner['foreign_field'];
  709. if (isset($foreigner['on_update'])) { // not set for internal
  710. $linksTo .= "\n" . 'ON UPDATE ' . $foreigner['on_update'];
  711. $linksTo .= "\n" . 'ON DELETE ' . $foreigner['on_delete'];
  712. }
  713. }
  714. $diagram_row = [
  715. $field_name,
  716. $type,
  717. $attribute,
  718. ($row['Null'] == '' || $row['Null'] == 'NO')
  719. ? __('No')
  720. : __('Yes'),
  721. isset($row['Default']) ? $row['Default'] : '',
  722. $row['Extra'],
  723. $linksTo,
  724. isset($comments[$field_name])
  725. ? $comments[$field_name]
  726. : '',
  727. isset($mime_map) && isset($mime_map[$field_name])
  728. ? str_replace('_', '/', $mime_map[$field_name]['mimetype'])
  729. : '',
  730. ];
  731. $links = [];
  732. $links[0] = $this->diagram->PMA_links['RT'][$table][$field_name];
  733. if ($foreigner
  734. && isset($this->diagram->PMA_links['doc'][$foreigner['foreign_table']][$foreigner['foreign_field']])
  735. ) {
  736. $links[6] = $this->diagram->PMA_links['doc'][$foreigner['foreign_table']][$foreigner['foreign_field']];
  737. } else {
  738. unset($links[6]);
  739. }
  740. $this->diagram->row($diagram_row, $links);
  741. } // end foreach
  742. $this->diagram->SetFont($this->_ff, '', 14);
  743. } //end each
  744. }
  745. }