Node.class.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Functionality for the navigation tree in the left frame
  5. *
  6. * @package PhpMyAdmin-Navigation
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. /**
  12. * The Node is the building block for the collapsible navigation tree
  13. *
  14. * @package PhpMyAdmin-Navigation
  15. */
  16. class Node
  17. {
  18. /**
  19. * @var int Defines a possible node type
  20. */
  21. const CONTAINER = 0;
  22. /**
  23. * @var int Defines a possible node type
  24. */
  25. const OBJECT = 1;
  26. /**
  27. * @var string A non-unique identifier for the node
  28. * This may be trimmed when grouping nodes
  29. */
  30. public $name = "";
  31. /**
  32. * @var string A non-unique identifier for the node
  33. * This will never change after being assigned
  34. */
  35. public $real_name = "";
  36. /**
  37. * @var int May be one of CONTAINER or OBJECT
  38. */
  39. public $type = Node::OBJECT;
  40. /**
  41. * @var bool Whether this object has been created while grouping nodes
  42. * Only relevant if the node is of type CONTAINER
  43. */
  44. public $is_group;
  45. /**
  46. * @var bool Whether to add a "display: none;" CSS
  47. * rule to the node when rendering it
  48. */
  49. public $visible = false;
  50. /**
  51. * @var Node A reference to the parent object of
  52. * this node, NULL for the root node.
  53. */
  54. public $parent;
  55. /**
  56. * @var array An array of Node objects that are
  57. * direct children of this node
  58. */
  59. public $children = array();
  60. /**
  61. * @var Mixed A string used to group nodes, or an array of strings
  62. * Only relevant if the node is of type CONTAINER
  63. */
  64. public $separator = '';
  65. /**
  66. * @var int How many time to recursively apply the grouping function
  67. * Only relevant if the node is of type CONTAINER
  68. */
  69. public $separator_depth = 1;
  70. /**
  71. * @var string An IMG tag, used when rendering the node
  72. */
  73. public $icon;
  74. /**
  75. * @var Array An array of A tags, used when rendering the node
  76. * The indexes in the array may be 'icon' and 'text'
  77. */
  78. public $links;
  79. /**
  80. * @var string Extra CSS classes for the node
  81. */
  82. public $classes = '';
  83. /**
  84. * @var string Whether this node is a link for creating new objects
  85. */
  86. public $isNew = false;
  87. /**
  88. * @var int The position for the pagination of
  89. * the branch at the second level of the tree
  90. */
  91. public $pos2 = 0;
  92. /**
  93. * @var int The position for the pagination of
  94. * the branch at the third level of the tree
  95. */
  96. public $pos3 = 0;
  97. /**
  98. * Initialises the class by setting the mandatory variables
  99. *
  100. * @param string $name An identifier for the new node
  101. * @param int $type Type of node, may be one of CONTAINER or OBJECT
  102. * @param bool $is_group Whether this object has been created
  103. * while grouping nodes
  104. *
  105. * @return Node
  106. */
  107. public function __construct($name, $type = Node::OBJECT, $is_group = false)
  108. {
  109. if (! empty($name)) {
  110. $this->name = $name;
  111. $this->real_name = $name;
  112. }
  113. if ($type === Node::CONTAINER) {
  114. $this->type = Node::CONTAINER;
  115. }
  116. $this->is_group = (bool)$is_group;
  117. }
  118. /**
  119. * Adds a child node to this node
  120. *
  121. * @param Node $child A child node
  122. *
  123. * @return void
  124. */
  125. public function addChild($child)
  126. {
  127. $this->children[] = $child;
  128. $child->parent = $this;
  129. }
  130. /**
  131. * Returns a child node given it's name
  132. *
  133. * @param string $name The name of requested child
  134. * @param bool $real_name Whether to use the "real_name"
  135. * instead of "name" in comparisons
  136. *
  137. * @return false|Node The requested child node or false,
  138. * if the requested node cannot be found
  139. */
  140. public function getChild($name, $real_name = false)
  141. {
  142. if ($real_name) {
  143. foreach ($this->children as $child) {
  144. if ($child->real_name == $name) {
  145. return $child;
  146. }
  147. }
  148. } else {
  149. foreach ($this->children as $child) {
  150. if ($child->name == $name) {
  151. return $child;
  152. }
  153. }
  154. }
  155. return false;
  156. }
  157. /**
  158. * Removes a child node from this node
  159. *
  160. * @param string $name The name of child to be removed
  161. *
  162. * @return void
  163. */
  164. public function removeChild($name)
  165. {
  166. foreach ($this->children as $key => $child) {
  167. if ($child->name == $name) {
  168. unset($this->children[$key]);
  169. break;
  170. }
  171. }
  172. }
  173. /**
  174. * Retreives the parents for a node
  175. *
  176. * @param bool $self Whether to include the Node itself in the results
  177. * @param bool $containers Whether to include nodes of type CONTAINER
  178. * @param bool $groups Whether to include nodes which have $group == true
  179. *
  180. * @return array An array of parent Nodes
  181. */
  182. public function parents($self = false, $containers = false, $groups = false)
  183. {
  184. $parents = array();
  185. if ($self
  186. && ($this->type != Node::CONTAINER || $containers)
  187. && ($this->is_group != true || $groups)
  188. ) {
  189. $parents[] = $this;
  190. $self = false;
  191. }
  192. $parent = $this->parent;
  193. while (isset($parent)) {
  194. if ( ($parent->type != Node::CONTAINER || $containers)
  195. && ($parent->is_group != true || $groups)
  196. ) {
  197. $parents[] = $parent;
  198. }
  199. $parent = $parent->parent;
  200. }
  201. return $parents;
  202. }
  203. /**
  204. * Returns the actual parent of a node. If used twice on an index or columns
  205. * node, it will return the table and database nodes. The names of the returned
  206. * nodes can be used in SQL queries, etc...
  207. *
  208. * @return Node
  209. */
  210. public function realParent()
  211. {
  212. $retval = $this->parents();
  213. if (count($retval) <= 0) {
  214. return false;
  215. }
  216. return $retval[0];
  217. }
  218. /**
  219. * This function checks if the node has children nodes associated with it
  220. *
  221. * @param bool $count_empty_containers Whether to count empty child
  222. * containers as valid children
  223. *
  224. * @return bool Whether the node has child nodes
  225. */
  226. public function hasChildren($count_empty_containers = true)
  227. {
  228. $retval = false;
  229. if ($count_empty_containers) {
  230. if (count($this->children)) {
  231. $retval = true;
  232. }
  233. } else {
  234. foreach ($this->children as $child) {
  235. if ($child->type == Node::OBJECT || $child->hasChildren(false)) {
  236. $retval = true;
  237. break;
  238. }
  239. }
  240. }
  241. return $retval;
  242. }
  243. /**
  244. * Returns true the node has some siblings (other nodes on the same tree level,
  245. * in the same branch), false otherwise. The only exception is for nodes on
  246. * the third level of the tree (columns and indexes), for which the function
  247. * always returns true. This is because we want to render the containers
  248. * for these nodes
  249. *
  250. * @return bool
  251. */
  252. public function hasSiblings()
  253. {
  254. $retval = false;
  255. $paths = $this->getPaths();
  256. if (count($paths['aPath_clean']) > 3) {
  257. $retval = true;
  258. return $retval;
  259. }
  260. foreach ($this->parent->children as $child) {
  261. if ($child !== $this
  262. && ($child->type == Node::OBJECT || $child->hasChildren(false))
  263. ) {
  264. $retval = true;
  265. break;
  266. }
  267. }
  268. return $retval;
  269. }
  270. /**
  271. * Returns the number of child nodes that a node has associated with it
  272. *
  273. * @return int The number of children nodes
  274. */
  275. public function numChildren()
  276. {
  277. $retval = 0;
  278. foreach ($this->children as $child) {
  279. if ($child->type == Node::OBJECT) {
  280. $retval++;
  281. } else {
  282. $retval += $child->numChildren();
  283. }
  284. }
  285. return $retval;
  286. }
  287. /**
  288. * Returns the actual path and the virtual paths for a node
  289. * both as clean arrays and base64 encoded strings
  290. *
  291. * @return array
  292. */
  293. public function getPaths()
  294. {
  295. $aPath = array();
  296. $aPath_clean = array();
  297. foreach ($this->parents(true, true, false) as $parent) {
  298. $aPath[] = base64_encode($parent->real_name);
  299. $aPath_clean[] = $parent->real_name;
  300. }
  301. $aPath = implode('.', array_reverse($aPath));
  302. $aPath_clean = array_reverse($aPath_clean);
  303. $vPath = array();
  304. $vPath_clean = array();
  305. foreach ($this->parents(true, true, true) as $parent) {
  306. $vPath[] = base64_encode($parent->name);
  307. $vPath_clean[] = $parent->name;
  308. }
  309. $vPath = implode('.', array_reverse($vPath));
  310. $vPath_clean = array_reverse($vPath_clean);
  311. return array(
  312. 'aPath' => $aPath,
  313. 'aPath_clean' => $aPath_clean,
  314. 'vPath' => $vPath,
  315. 'vPath_clean' => $vPath_clean
  316. );
  317. }
  318. /**
  319. * Returns the names of children of type $type present inside this container
  320. * This method is overridden by the Node_Database and Node_Table classes
  321. *
  322. * @param string $type The type of item we are looking for
  323. * ('tables', 'views', etc)
  324. * @param int $pos The offset of the list within the results
  325. * @param string $searchClause A string used to filter the results of the query
  326. *
  327. * @return array
  328. */
  329. public function getData($type, $pos, $searchClause = '')
  330. {
  331. $query = "SELECT `SCHEMA_NAME` ";
  332. $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA`, ";
  333. $query .= "(";
  334. $query .= "select DB_first_level ";
  335. $query .= "from ( ";
  336. $query .= "SELECT distinct SUBSTRING_INDEX(SCHEMA_NAME, ";
  337. $query .= "'{$GLOBALS['cfg']['NavigationTreeDbSeparator']}', 1) ";
  338. $query .= "DB_first_level ";
  339. $query .= "FROM INFORMATION_SCHEMA.SCHEMATA ";
  340. $query .= $this->_getWhereClause($searchClause);
  341. $query .= ") t ";
  342. $query .= "ORDER BY DB_first_level ASC ";
  343. $query .= "LIMIT $pos, {$GLOBALS['cfg']['FirstLevelNavigationItems']}";
  344. $query .= ") t2 ";
  345. $query .= "where 1 = locate(concat(DB_first_level, ";
  346. $query .= "'{$GLOBALS['cfg']['NavigationTreeDbSeparator']}'), ";
  347. $query .= "concat(SCHEMA_NAME, ";
  348. $query .= "'{$GLOBALS['cfg']['NavigationTreeDbSeparator']}')) ";
  349. $query .= "order by SCHEMA_NAME ASC";
  350. return $GLOBALS['dbi']->fetchResult($query);
  351. }
  352. /**
  353. * Returns the number of children of type $type present inside this container
  354. * This method is overridden by the Node_Database and Node_Table classes
  355. *
  356. * @param string $type The type of item we are looking for
  357. * ('tables', 'views', etc)
  358. * @param string $searchClause A string used to filter the results of the query
  359. *
  360. * @return int
  361. */
  362. public function getPresence($type = '', $searchClause = '')
  363. {
  364. $query = "select COUNT(*) ";
  365. $query .= "from ( ";
  366. $query .= "SELECT distinct SUBSTRING_INDEX(SCHEMA_NAME, ";
  367. $query .= "'{$GLOBALS['cfg']['NavigationTreeDbSeparator']}', 1) ";
  368. $query .= "DB_first_level ";
  369. $query .= "FROM INFORMATION_SCHEMA.SCHEMATA ";
  370. $query .= $this->_getWhereClause($searchClause);
  371. $query .= ") t ";
  372. $retval = (int)$GLOBALS['dbi']->fetchValue($query);
  373. return $retval;
  374. }
  375. /**
  376. * Returns the WHERE clause depending on the $searchClause parameter
  377. * and the hide_db directive
  378. *
  379. * @param string $searchClause A string used to filter the results of the query
  380. *
  381. * @return string
  382. */
  383. private function _getWhereClause($searchClause = '')
  384. {
  385. $whereClause = "WHERE TRUE ";
  386. if (! empty($searchClause)) {
  387. $whereClause .= "AND `SCHEMA_NAME` LIKE '%";
  388. $whereClause .= PMA_Util::sqlAddSlashes(
  389. $searchClause, true
  390. );
  391. $whereClause .= "%' ";
  392. }
  393. if (! empty($GLOBALS['cfg']['Server']['hide_db'])) {
  394. $whereClause .= "AND `SCHEMA_NAME` NOT REGEXP '"
  395. . $GLOBALS['cfg']['Server']['hide_db'] . "' ";
  396. }
  397. if (! empty($GLOBALS['cfg']['Server']['only_db'])) {
  398. if (is_string($GLOBALS['cfg']['Server']['only_db'])) {
  399. $GLOBALS['cfg']['Server']['only_db'] = array(
  400. $GLOBALS['cfg']['Server']['only_db']
  401. );
  402. }
  403. $whereClause .= "AND (";
  404. $subClauses = array();
  405. foreach ($GLOBALS['cfg']['Server']['only_db'] as $each_only_db) {
  406. $subClauses[] = " `SCHEMA_NAME` LIKE '"
  407. . $each_only_db . "' ";
  408. }
  409. $whereClause .= implode("OR", $subClauses) . ")";
  410. }
  411. return $whereClause;
  412. }
  413. /**
  414. * Returns HTML for control buttons displayed infront of a node
  415. *
  416. * @return String HTML for control buttons
  417. */
  418. public function getHtmlForControlButtons()
  419. {
  420. return '';
  421. }
  422. }
  423. ?>