PdfRelationSchema.php 25 KB

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