Pelzini

This is the code documentation for the Pelzini project

source of /viewer/controllers/class.php

  1. <?php
  2. /*
  3. Copyright 2008 Josh Heidenreich
  4.  
  5. This file is part of Pelzini.
  6.  
  7. Pelzini is free software: you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation, either version 3 of the License, or
  10. (at your option) any later version.
  11.  
  12. Pelzini is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Pelzini. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20.  
  21. /**
  22.  * Shows information about a specific class
  23.  *
  24.  * @package Viewer
  25.  * @author Josh Heidenreich
  26.  * @since 0.1
  27.  * @see ParserClass
  28.  * @tag i18n-done
  29.  **/
  30.  
  31. require_once 'functions.php';
  32.  
  33.  
  34. define('PAGE_CLASS_GENERAL', 0);
  35. define('PAGE_CLASS_USED_BY', 1);
  36. define('PAGE_CLASS_EXTENDS', 2);
  37. define('PAGE_CLASS_SOURCE', 3);
  38.  
  39.  
  40. $_GET['page'] = (int) @$_GET['page'];
  41.  
  42.  
  43. $sql_name = db_quote($_GET['name']);
  44. $q = new SelectQuery();
  45. $q->addFields('classes.id, classes.name, namespaces.name AS namespace, classes.description, classes.extends, files.name as filename,
  46. classes.final, classes.abstract, classes.sinceid, classes.projectid, classes.deprecated');
  47. $q->setFrom('classes');
  48. $q->addInnerJoin('files ON classes.fileid = files.id');
  49. $q->addLeftJoin('namespaces ON classes.namespaceid = namespaces.id');
  50. $q->addWhere("classes.name = {$sql_name}");
  51. $q->addProjectWhere();
  52.  
  53. if (isset($_GET['file'])) {
  54. $sql_name = db_quote($_GET['file']);
  55. $q->addWhere("files.name = {$sql_name}");
  56. }
  57.  
  58. $q = $q->buildQuery();
  59. $res = db_query($q);
  60.  
  61. if (db_num_rows($res) == 0) {
  62. require_once 'head.php';
  63. echo '<h2>', str(STR_ERROR_TITLE), '</h2>';
  64. echo '<p>', str(STR_CLASS_INVALID), '</p>';
  65. require_once 'foot.php';
  66.  
  67. } else if (db_num_rows($res) > 1) {
  68. require_once 'head.php';
  69. echo '<h2>', str(STR_MULTIPLE_TITLE, 'NUM', db_num_rows($res), 'TYPE', strtolower(str(STR_CLASSES))), '</h2>';
  70.  
  71. echo '<div class="list">';
  72. while ($row = db_fetch_assoc($res)) {
  73. $name_parts = array();
  74. $name_parts[] = str(STR_IN_FILE, 'VAL', $row['filename']);
  75.  
  76. $url = 'class?name=' . htmlspecialchars($_GET['name']) . '&file=' . urlencode($row['filename']);
  77.  
  78. echo '<div class="item">';
  79. echo '<p><strong><a href="', htmlspecialchars($url), '">', htmlspecialchars($row['name']), '</a></strong></p>';
  80. echo '<pre>', ucfirst(implode(', ', $name_parts)), '</pre>';
  81. echo '</div>';
  82. }
  83. echo '</div>';
  84.  
  85. require_once 'foot.php';
  86.  
  87. } else {
  88. $class = db_fetch_assoc($res);
  89. }
  90.  
  91.  
  92. $skin['page_name'] = str(STR_CLASS_BROWSER_TITLE, 'name', $class['name']);
  93. require_once 'head.php';
  94.  
  95.  
  96. // Pages
  97. $pages = array(
  98. str(STR_CLASS_PAGE_GENERAL),
  99. str(STR_CLASS_PAGE_USED_BY),
  100. str(STR_CLASS_PAGE_EXTENDS),
  101. str(STR_CLASS_PAGE_SOURCE)
  102. );
  103.  
  104. $url_name = urlencode($class['name']);
  105. echo "<div class=\"viewer_options\">";
  106. echo '<p><b>', str(STR_CLASS_PAGE), '</b></p>';
  107. foreach ($pages as $num => $page) {
  108. if ($_GET['page'] == $num) {
  109. echo "<p class=\"on\"><a href=\"class?name={$url_name}&page={$num}\">{$page}</a></p>";
  110. } else {
  111. echo "<p><a href=\"class?name={$url_name}&page={$num}\">{$page}</a></p>";
  112. }
  113. }
  114. echo "</div>";
  115.  
  116. // Page options
  117. if ($_GET['page'] == 0) {
  118. echo "<div class=\"viewer_options\">";
  119. echo '<p><b>', str(STR_CLASS_OPTIONS), '</b></p>';
  120. if (@$_GET['complete'] == 1) {
  121. echo "<p class=\"on\"><a href=\"class?name={$url_name}\">", str(STR_CLASS_INHERITED), "</a></p>";
  122. } else {
  123. echo "<p><a href=\"class?name={$url_name}&complete=1\">", str(STR_CLASS_INHERITED), "</a></p>";
  124. }
  125. echo "</div>";
  126. }
  127.  
  128.  
  129.  
  130.  
  131. echo '<h2>', str(STR_CLASS_PAGE_TITLE, 'name', $class['name']), '</h2>';
  132.  
  133. if ($class['deprecated'] !== null) {
  134. echo '<p><span class="deprecated">', str(STR_CLASS_DEPRECATED), '</span></p>';
  135. if ($class['deprecated']) echo '<br>', process_inline($class['deprecated']);
  136. echo '</p>';
  137. }
  138.  
  139. echo '<div class="main-description">';
  140. echo process_inline($class['description']);
  141. echo '</div>';
  142.  
  143.  
  144. // Basic class details
  145. echo "<ul>";
  146. echo '<li>', str(STR_FILE, 'filename', $class['filename']), '</li>';
  147.  
  148. if ($class['namespace'] != null) {
  149. echo '<li>', str(STR_NAMESPACE, 'name', get_namespace_link($class['namespace'])), '</li>';
  150. }
  151.  
  152. if ($class['extends'] != null) {
  153. echo '<li>', str(STR_CLASS_EXTENDS, 'link', get_object_link($class['extends'])), '</li>';
  154. }
  155.  
  156. // Show implements
  157. $q = "SELECT name FROM class_implements WHERE classid = {$class['id']}";
  158. $res = db_query ($q);
  159.  
  160. if (db_num_rows ($res) > 0) {
  161. echo '<li>', str(STR_CLASS_IMPLEMENTS);
  162.  
  163. $j = 0;
  164. while ($row = db_fetch_assoc ($res)) {
  165. if ($j++ > 0) echo ', ';
  166. echo get_object_link ($row['name']);
  167. }
  168. echo '</li>';
  169. }
  170.  
  171. if ($class['abstract'] == 1) echo '<li>', str(STR_CLASS_ABSTRACT), '</li>';
  172. if ($class['final'] == 1) echo '<li>', str(STR_CLASS_FINAL), '</li>';
  173.  
  174. if ($class['sinceid']) {
  175. echo '<li>', str(STR_AVAIL_SINCE, 'version', get_since_version($class['sinceid'])), '</li>';
  176. }
  177. echo "</ul>";
  178.  
  179.  
  180. show_examples($class['id'], LINK_TYPE_CLASS);
  181.  
  182.  
  183. switch ($_GET['page']) {
  184. case PAGE_CLASS_GENERAL:
  185. // Determine a list of variables and functions
  186. $functions = array();
  187. $variables = array();
  188.  
  189. if (@$_GET['complete'] == 1) {
  190. $name = $class['name'];
  191. $filename = $class['filename'];
  192.  
  193. do {
  194. $result = load_class($project['id'], $name, $filename);
  195. if ($result == null) break;
  196.  
  197. list ($funcs, $vars, $parent) = $result;
  198.  
  199. $functions = array_merge($funcs, $functions);
  200. $variables = array_merge($vars, $variables);
  201.  
  202. $name = $parent;
  203. $filename = null;
  204. } while ($name != null);
  205.  
  206. } else {
  207. list($functions, $variables) = load_class($project['id'], $class['name'], $class['filename']);
  208. }
  209.  
  210. ksort($functions);
  211. ksort($variables);
  212.  
  213. show_authors ($class['id'], LINK_TYPE_CLASS);
  214. show_tables ($class['id'], LINK_TYPE_CLASS);
  215.  
  216.  
  217. // Show variables
  218. if (count($variables) > 0) {
  219. echo '<a name="variables"></a>';
  220. echo '<h3>', str(STR_VARIABLES), '</h3>';
  221. echo "<table class=\"function-list\">\n";
  222. echo '<tr><th>', str(STR_NAME), '</th><th>', str(STR_VISIBILITY), '</th><th>', str(STR_DESCRIPTION), "</th></tr>\n";
  223. foreach ($variables as $row) {
  224. if (!isset($row['visibility'])) $row['visibility'] = '';
  225.  
  226. // encode for output
  227. $row['name'] = htmlspecialchars($row['name']);
  228. if ($row['description'] == null) $row['description'] = '&nbsp;';
  229.  
  230. if ($row['static']) $row['visibility'] .= ' ' . str(STR_CLASS_VAR_STATIC);
  231.  
  232. // display
  233. echo "<tr>";
  234. echo "<td><code>{$row['name']}</code></td>";
  235. echo "<td>{$row['visibility']}</td>";
  236. echo "<td>{$row['description']}</td>";
  237. echo "</tr>\n";
  238. }
  239. echo "</table>\n";
  240. }
  241.  
  242. // Show functions
  243. if (count($functions) > 0) {
  244. $base_url = $_SERVER['REQUEST_URI'];
  245. echo '<h3>', str(STR_FUNCTIONS), '</h3>';
  246. echo "<table class=\"function-list\">\n";
  247. echo '<tr><th>', str(STR_NAME), '</th><th>', str(STR_VISIBILITY), "</th><th>", str(STR_DESCRIPTION), "</th></tr>\n";
  248. foreach ($functions as $row) {
  249. if (!isset($row['visibility'])) $row['visibility'] = '';
  250.  
  251. // encode for output
  252. $row['name'] = htmlspecialchars($row['name']);
  253.  
  254. if ($row['description'] == null) {
  255. $summary = '&nbsp;';
  256. } else {
  257. $lines = explode("\n", trim(strip_tags($row['description'])));
  258. $summary = delink_inline($lines[0]);
  259. }
  260.  
  261. if ($row['static']) $row['visibility'] .= ' ' . str(STR_CLASS_VAR_STATIC);
  262.  
  263. $url = get_function_link($row['classname'], $row['name']);
  264.  
  265. // display
  266. echo "<tr>";
  267. echo "<td>{$url}</td>";
  268. echo "<td>{$row['visibility']}</td>";
  269. echo "<td>{$summary}</td>";
  270. echo "</tr>\n";
  271. }
  272. echo "</table>\n";
  273. }
  274.  
  275.  
  276. // Show functions
  277. if (count($functions) > 0) {
  278. foreach ($functions as $row) {
  279. if ($row['description'] == null) {
  280. $row['description'] = '<em>This function does not have a description</em>';
  281. }
  282.  
  283. // display
  284. echo "<a name=\"func-", $row['name'], "\"></a>";
  285. echo "<h3>{$row['visibility']} ", get_function_link($row['classname'], $row['name']);
  286. if ($row['classname'] != $class['name']) {
  287. echo " <small>(from ", get_class_link($row['classname']), ")</small>";
  288. }
  289. echo "</h3>";
  290.  
  291. show_function_usage($row['id']);
  292. echo '<br>';
  293. echo process_inline($row['description']);
  294. }
  295. }
  296. break;
  297.  
  298.  
  299. case PAGE_CLASS_USED_BY:
  300. // Loads the classes tree
  301. // and finds this class within it
  302. $root = create_classes_tree();
  303. $matcher = new FieldTreeNodeMatcher('name', $class['name']);
  304. $node = $root->findNode($matcher);
  305.  
  306. // If our class was found - which it should be - find the top ancestor
  307. // and then draw unordered lists of the class structure
  308. if ($node != null) {
  309. echo '<h3>', str(STR_CLASS_STRUCTURE), '</h3>';
  310.  
  311. $ancestors = $node->findAncestors();
  312. $top = end($ancestors);
  313.  
  314. echo "<ul class=\"tree\">\n";
  315. draw_class_tree($top, array($node));
  316. echo "</ul>\n";
  317. }
  318.  
  319.  
  320. $sql_class_name = db_quote ($class['name']);
  321.  
  322. // Query to get functions which return this class
  323. $q = "SELECT functions.id, functions.name, functions.description, functions.classid,
  324. files.name as filename, functions.fileid, classes.name as class
  325. FROM functions
  326. INNER JOIN files ON functions.fileid = files.id
  327. INNER JOIN returns ON returns.functionid = functions.id
  328. LEFT JOIN classes ON functions.classid = classes.id
  329. WHERE returns.type = {$sql_class_name}
  330. AND functions.projectid = {$class['projectid']}
  331. ORDER BY functions.name";
  332. $res = db_query ($q);
  333.  
  334. // Display any functions which return this class
  335. if (db_num_rows ($res) > 0) {
  336. echo '<h3>', str(STR_CLASS_FUNC_RETURN), '</h3>';
  337.  
  338. echo '<div class="list">';
  339. while ($row = db_fetch_assoc ($res)) {
  340. $class = 'item';
  341. if ($alt) $class .= '-alt';
  342.  
  343. echo "<div class=\"{$class}\">";
  344. echo "<img src=\"assets/icon_remove.png\" alt=\"\" title=\"Hide this result\" onclick=\"hide_content(event)\" class=\"showhide\">";
  345. echo "<p><strong>", get_function_link($row['class'], $row['name']), "</strong>";
  346.  
  347. if ($row['class'] != null) {
  348. echo " <small>from class ", get_class_link($row['class']), "</small>";
  349. }
  350.  
  351. echo "<div class=\"content\">";
  352. echo delink_inline($row['description']);
  353. echo "<br><small>From ", get_file_link($row['filename']), "</small></div>";
  354. echo "</div>";
  355.  
  356. $alt = ! $alt;
  357. }
  358. echo '</div>';
  359. }
  360.  
  361.  
  362. // Query to get functions which use this class as an argument
  363. $q = "SELECT functions.id, functions.name, functions.description, functions.classid,
  364. files.name as filename, functions.fileid, classes.name as class, arguments.name as argname
  365. FROM functions
  366. INNER JOIN arguments ON arguments.functionid = functions.id
  367. INNER JOIN files ON functions.fileid = files.id
  368. LEFT JOIN classes ON functions.classid = classes.id
  369. WHERE arguments.type = {$sql_class_name}
  370. AND functions.projectid = {$class['projectid']}
  371. ORDER BY functions.name";
  372. $res = db_query ($q);
  373.  
  374. // Display any functions which use this class as an argument
  375. if (db_num_rows ($res) > 0) {
  376. echo '<h3>', str(STR_CLASS_FUNC_ARG), '</h3>';
  377.  
  378. echo '<div class="list">';
  379. while ($row = db_fetch_assoc ($res)) {
  380. $class = 'item';
  381. if ($alt) $class .= '-alt';
  382.  
  383. echo "<div class=\"{$class}\">";
  384. echo "<img src=\"assets/icon_remove.png\" alt=\"\" title=\"Hide this result\" onclick=\"hide_content(event)\" class=\"showhide\">";
  385. echo "<p><strong>", get_function_link($row['class'], $row['name']), "</strong>";
  386.  
  387. if ($row['class'] != null) {
  388. echo " <small>from class ", get_class_link($row['class']), "</small>";
  389. }
  390.  
  391. echo "<div class=\"content\">";
  392. echo delink_inline($row['description']);
  393. echo "<br><small>Argument name: {$row['argname']}</small>";
  394. echo "<br><small>From ", get_file_link($row['filename']), "</small>";
  395. echo "</div>";
  396. echo "</div>";
  397.  
  398. $alt = ! $alt;
  399. }
  400. echo '</div>';
  401. }
  402. break;
  403.  
  404.  
  405. case PAGE_CLASS_EXTENDS:
  406. echo '<h3>', str(STR_CLASS_EXTENDING), '</h3>';
  407.  
  408. require_once 'php_code_renderer.php';
  409. $renderer = new PHPCodeRenderer();
  410. $code = $renderer->drawClassExtends ($class['id']);
  411.  
  412. echo "<pre class=\"source\">";
  413. echo htmlspecialchars($code);
  414. echo "</pre>";
  415. break;
  416.  
  417.  
  418. case PAGE_CLASS_SOURCE:
  419. require_once 'search_functions.php';
  420. search_source ($class['name'], true);
  421. break;
  422.  
  423.  
  424. default:
  425. echo '<h3>', str(STR_ERROR_TITLE), '</h3>';
  426. echo '<p>', str(STR_CLASS_INVALID_INFO), '</p>';
  427. break;
  428. }
  429.  
  430. show_see_also ($class['id'], LINK_TYPE_CLASS);
  431. show_tags ($class['id'], LINK_TYPE_CLASS);
  432.  
  433.  
  434. require_once 'foot.php';
  435.  
  436.  
  437. /**
  438.  * @param int $project_id
  439.  * @param string $name
  440.  * @param string $filename
  441.  * @return array
  442.  * [0] => functions
  443.  * [1] => variables
  444.  * [2] => name of parent class
  445.  **/
  446. function load_class($project_id, $name, $filename = null)
  447. {
  448. $project_id = (int) $project_id;
  449.  
  450. // determine parent class
  451. $name_sql = db_escape($name);
  452. $q = "SELECT classes.id, classes.extends
  453. FROM classes
  454. INNER JOIN files ON classes.fileid = files.id
  455. WHERE classes.projectid = {$project_id}
  456. AND classes.name LIKE '{$name_sql}'";
  457.  
  458. if ($filename) {
  459. $name_sql = db_escape($filename);
  460. $q .= " AND files.name = '{$name_sql}'";
  461. }
  462.  
  463. $res = db_query($q);
  464. if (db_num_rows($res) != 1) {
  465. return null;
  466. }
  467.  
  468. $row = db_fetch_assoc($res);
  469. $id = $row['id'];
  470. $parent = $row['extends'];
  471.  
  472. // determine functions
  473. $functions = array();
  474. $q = "SELECT *, '{$name}' AS classname FROM functions WHERE classid = {$id}";
  475. $res = db_query($q);
  476. while ($row = db_fetch_assoc($res)) {
  477. $functions[$row['name']] = $row;
  478. }
  479.  
  480. // determine variables
  481. $variables = array();
  482. $q = "SELECT *, '{$name}' AS classname FROM variables WHERE classid = {$id}";
  483. $res = db_query($q);
  484. while ($row = db_fetch_assoc($res)) {
  485. $variables[$row['name']] = $row;
  486. }
  487.  
  488. return array($functions, $variables, $parent);
  489. }
  490.  
  491.  
  492. /**
  493.  * Draws the tree from this node and below as unordered lists within unordered lists
  494.  *
  495.  * @param array $higlight_nodes The nodes to put class="on" for the LI element.
  496.  **/
  497. function draw_class_tree($node, $higlight_nodes)
  498. {
  499. // Draw this item
  500. if (in_array($node, $higlight_nodes, true)) {
  501. echo '<li class="on">', get_object_link($node['name']);
  502. } else {
  503. echo '<li>', get_object_link($node['name']);
  504. }
  505.  
  506. // Draw its children if it has any
  507. $children = $node->getChildren();
  508. usort($children, 'nodenamesort');
  509.  
  510. if (count($children) > 0) {
  511. echo "<ul>\n";
  512. foreach ($children as $child) {
  513. draw_class_tree($child, $higlight_nodes);
  514. }
  515. echo "</ul>\n";
  516. }
  517.  
  518. echo "</li>\n";
  519. }
  520.  
  521.  
  522. function nodenamesort($a, $b)
  523. {
  524. return strcasecmp($a['name'], $b['name']);
  525. }
  526.  
  527.  
  528. ?>
  529.