Source for file _basicnav.php

Documentation is available at _basicnav.php

  1. <?php
  2. /**
  3. * @package midcom
  4. * @author The Midgard Project, http://www.midgard-project.org
  5. * @version $Id: _basicnav.php,v 1.34.2.12 2005/11/21 14:52:30 bergius Exp $
  6. * @copyright The Midgard Project, http://www.midgard-project.org
  7. * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
  8. */
  9.  
  10. /**
  11. * This class is the basic building stone of the Navigation Access Point
  12. * System of MidCOM.
  13. *
  14. * It is responsible for collecting the available
  15. * Information and for building the navigational Tree out of it. This
  16. * class is only the internal interface to the NAP System and is used by
  17. * midcom_helper_nav as a node cache. The framework should ensure that
  18. * only one class of this type is active at one time.
  19. *
  20. * Basicnav will give you a very abstract view of the content tree, modified
  21. * by the NAP classes of the components. You can retrieve a node/leaf tree
  22. * of the content, and for each element you can retrieve an URL name and a
  23. * long name for Navigation display.
  24. *
  25. * Leaves and Nodes are both indexed by Integer constants which are assigned
  26. * by the framework. The framework defines two starting points in this tree:
  27. * The root node and the "current" node. The current node defined through
  28. * the topic of the component that declared to be able to handle the request.
  29. *
  30. * The class will load the neccessary information on demand to minimize
  31. * database traffic.
  32. *
  33. * The interface functions should enable you to build any navigation tree you
  34. * desire. The public nav class will give you some of those high-level
  35. * functions.
  36. *
  37. * <b>Node data interchange format</b>
  38. *
  39. * Node NAP data consists of a simple key => value array with the following
  40. * keys required by the component:
  41. *
  42. * - MIDCOM_NAV_NAME => The Real (= displayable) name of the element
  43. * - MIDCOM_NAV_TOOLBAR => Toolbar data (see below)
  44. * - MIDCOM_META_CREATOR => Creator of the element (MidgardPerson)
  45. * - MIDCOM_META_CREATED => Creation date (UNIX Timestamp)
  46. * - MIDCOM_META_EDITOR => Last modifier of the element (MidgardPerson)
  47. * - MIDCOM_META_EDITED => Last modification date (UNIX Timestamp)
  48. *
  49. * Other keys delivered to NAP users include:
  50. *
  51. * - MIDCOM_NAV_URL => The URL name of the element, which is automatically
  52. * defined by NAP.
  53. *
  54. * <b>Leaf data interchaneg format</b>
  55. *
  56. * Basically for each leaf the usual meta information is returned:
  57. *
  58. * - MIDCOM_META_CREATOR => Creator of the element (MidgardPerson)
  59. * - MIDCOM_META_CREATED => Creation date (UNIX Timestamp)
  60. * - MIDCOM_META_EDITOR => Last modifier of the element (MidgardPerson)
  61. * - MIDCOM_META_EDITED => Last modification date (UNIX Timestamp)
  62. * - MIDCOM_NAV_GUID => Optional argument denoting the GUID of the referred element
  63. * - MIDCOM_NAV_TOOLBAR => Toolbar data (see below)
  64. *
  65. * MidCOM NAP has reduced the separation of Admin Mode and Site Mode NAP
  66. * Data. Both Site- and Administrative Mode data is now delivered to NAP
  67. * (and from there to the NAP user) in a single call. This is done by
  68. * creating two sub-arrays retrievable under the keys MIDCOM_NAV_SITE and
  69. * MIDCOM_NAV_ADMIN. Both of those arrays contain MIDCOM_NAV_URL and
  70. * MIDCOM_NAV_NAME values. For compatibility and ease of use the top-level
  71. * entries of MIDCOM_NAV_NAME and MIDCOM_NAV_URL are still existent and
  72. * in use. Therefore, three possible constellation exist:
  73. *
  74. * 1) Both Values present
  75. *
  76. * <pre>
  77. * MIDCOM_NAV_SITE => Array (MIDCOM_NAV_URL, MIDCOM_NAV_NAME),
  78. * MIDCOM_NAV_ADMIN => Array (MIDCOM_NAV_URL, MIDCOM_NAV_NAME),
  79. * [... all other tags ...]
  80. * </pre>
  81. *
  82. * The top-level entries MIDCOM_NAV_NAME and _URL will be automatically
  83. * popluated according to Admin- or non-Admin mode, so that the displaying
  84. * code for all standard-situations won't have to consider this difference.
  85. *
  86. * 2) One element omitted
  87. *
  88. * If any Element does have only one of those pairs (like a "Create New
  89. * Category"-Link for example), set the unavailable Array Entry to null:
  90. *
  91. * <pre>
  92. * MIDCOM_NAV_SITE => null,
  93. * MIDCOM_NAV_ADMIN => Array (MIDCOM_NAV_URL, MIDCOM_NAV_NAME),
  94. * [... all other tags ...]
  95. * </pre>
  96. *
  97. * Note, that if one of the elements is missing like outlined above, the
  98. * list-methods of NAP will not show them in the corresponding mode. The
  99. * element of the above example would only be included in the listings if
  100. * the system was running in Admin-Mode. Copying of the primary values will
  101. * still happen like in (1).
  102. *
  103. * 3) Compatibility syntax
  104. *
  105. * For ease-of-use and for backwards compatibility, you can deliver an old
  106. * style data like this:
  107. *
  108. * <pre>
  109. * MIDCOM_NAV_URL => "blah",
  110. * MIDCOM_NAV_NAME => "blubb",
  111. * [... all other tags ...]
  112. * </pre>
  113. *
  114. * The Datamanger will automatically transform (3) to the syntax described in
  115. * (1) by copying the values.
  116. *
  117. * <b>Important note:</b> The difference outlined above is only valid for leaves (read
  118. * "articles"), because the topic structure is essentially the same in both AIS
  119. * and live Site.
  120. *
  121. * <b>Toolbar Syntax</b>
  122. *
  123. * You can add toolbars to your NAP information, that can be used for simple on-site
  124. * editing. They are indexed using integers and consist of an
  125. * midcom_helper_toolbar::add_item() compatible array with one exception:
  126. * The URL is always realtive to the AIS topic welcome page, but see the example
  127. * (it assumes that the referenced l10n libraries are available, of course):
  128. *
  129. * <code>
  130. * $toolbar[0] = Array (
  131. * MIDCOM_TOOLBAR_URL =&gt; '',
  132. * MIDCOM_TOOLBAR_LABEL =&gt; $this-&gt;_l10n-&gt;get('create article'),
  133. * MIDCOM_TOOLBAR_HELPTEXT =&gt; null,
  134. * MIDCOM_TOOLBAR_ICON =&gt; 'stock-icons/16x16/stock_new.png',
  135. * MIDCOM_TOOLBAR_ENABLED =&gt; true
  136. * );
  137. * $toolbar[100] = Array(
  138. * MIDCOM_TOOLBAR_URL =&gt; 'config.html',
  139. * MIDCOM_TOOLBAR_LABEL =&gt; $this-&gt;_l10n_midcom-&gt;get('component configuration'),
  140. * MIDCOM_TOOLBAR_HELPTEXT =&gt; $this-&gt;_l10n_midcom-&gt;get('component configuration helptext'),
  141. * MIDCOM_TOOLBAR_ICON =&gt; 'stock-icons/16x16/stock_folder-properties.png',
  142. * MIDCOM_TOOLBAR_ENABLED =&gt; true
  143. * );
  144. * </code>
  145. *
  146. * You can now use a similar in your leaf data and place further buttons between these two
  147. * using indexes like 50,51,52.
  148. *
  149. * <b>DEPRECATED INFORMATION</b>
  150. *
  151. * The key MIDCOM_NAV_VISIBLE is deprecated from MidCOM 2.4.0 on, visibility is taken into account
  152. * automatically. The key is set to true for all values now for backwards compatibility and will
  153. * be removed entirely in MidCOM 2.6.0
  154. *
  155. * @todo Bring the information from http://www.nathan-syntronics.de/midgard/midcom_fs-transition/nap-update.html somehow into this.
  156. * @package midcom
  157. */
  158. class midcom_helper__basicnav
  159. {
  160. /**#@+
  161. * NAP data variable.
  162. *
  163. * @access private
  164. */
  165. /**
  166. * The GUID of the MidCOM Root Content Topic
  167. *
  168. * @var int
  169. */
  170. var $_root;
  171. /**
  172. * The GUID of the currently active Navigation Node, determied by the active
  173. * MidCOM Topic or one of its uplinks, if the subtree in question is invisible.
  174. *
  175. * @var int
  176. */
  177. var $_current;
  178. /**
  179. * The GUID of the currently active leaf.
  180. *
  181. * @var int
  182. */
  183. var $_currentleaf;
  184. /**
  185. * This is the leaf cache. It is an array which contains elements indexed by
  186. * their leaf ID. The data is again stored in an accociative array:
  187. *
  188. * - MIDCOM_NAV_NODEID => ID of the parent node (int)
  189. * - MIDCOM_NAV_URL => URL name of the leaf (string)
  190. * - MIDCOM_NAV_NAME => Textual name of the leaf (string)
  191. * - MIDCOM_META_CREATOR => Creator of the element (MidgardPerson)
  192. * - MIDCOM_META_CREATED => Creation date (UNIX Timestamp)
  193. * - MIDCOM_META_EDITOR => Last modifier of the element (MidgardPerson)
  194. * - MIDCOM_META_EDITED => Last modification date (UNIX Timestamp)
  195. *
  196. * @todo Update the data structure documentation
  197. * @var Array
  198. */
  199. var $_leaves;
  200. /**
  201. * This is the node cache. It is an array which contains elements indexed by
  202. * their node ID. The data is again stored in an accociative array:
  203. *
  204. * - MIDCOM_NAV_NODEID => ID of the parent node (-1 for the root node) (int)
  205. * - MIDCOM_NAV_URL => URL name of the leaf (string)
  206. * - MIDCOM_NAV_NAME => Textual name of the leaf (string)
  207. * - MIDCOM_META_CREATOR => Creator of the element (MidgardPerson)
  208. * - MIDCOM_META_CREATED => Creation date (UNIX Timestamp)
  209. * - MIDCOM_META_EDITOR => Last modifier of the element (MidgardPerson)
  210. * - MIDCOM_META_EDITED => Last modification date (UNIX Timestamp)
  211. *
  212. * @todo Update the data structure documentation
  213. * @var Array
  214. */
  215. var $_nodes;
  216. /**
  217. * This map tracks all loaded GUIDs along with their NAP structures. This cache
  218. * is used by nav's resolve_guid function to short-circut already known GUIDs.
  219. *
  220. * @var Array
  221. */
  222. var $_guid_map = Array();
  223. /**
  224. * This array holds a list of all topics for which the leaves have been loaded.
  225. * If the id of the node is in this array, the leaves are available, otheriwise,
  226. * the leaves ahve to be loaded.
  227. *
  228. * @var Array
  229. */
  230. var $_loaded_leaves = Array();
  231. /**#@-*/
  232. /**#@+
  233. * Internal runtime state variable.
  234. *
  235. * @access private
  236. */
  237. /**
  238. * This is a reference to the systemwide component loader class.
  239. *
  240. * @var midcom_helper__componentloader
  241. */
  242. var $_loader;
  243. /**
  244. * This one is true, if the system is in content administration mode and therefore
  245. * working with a different topic. See Constructor Documentation for details.
  246. *
  247. * @var bool
  248. */
  249. var $_adminmode;
  250. /**
  251. * This is a temporary storage where _loadNode can return the last known good
  252. * node in case the current node not visible. It is evaluated by the
  253. * constructor.
  254. *
  255. * @var int
  256. */
  257. var $_lastgoodnode;
  258.  
  259. /**
  260. * A reference to the NAP cache store
  261. *
  262. * @var midcom_services_cache_backend
  263. */
  264. var $_nap_cache = null;
  265. /**#@-*/
  266. /**
  267. * This helper object will construct a complete node data structure for a given topic,
  268. * without any dependant objects like subtopics or leaves. It does not do any visibility
  269. * checks, it just prepares the object for later processing.
  270. *
  271. * This code is NAP cache aware, if the resulting information is already in the NAP
  272. * cache, it is retrieved from there.
  273. *
  274. * @param int $id The ID of the topic for which the NAP information is requested.
  275. * @return Array NAP node data structure or NULL in case no NAP information is available for this topic.
  276. * @access private
  277. */
  278. function _get_node($id)
  279. {
  280. debug_push_class(__CLASS__, __FUNCTION__);
  281. debug_add("Trying to load NAP data for topic {$id}...");
  282.  
  283. $this->_nap_cache->open();
  284. if ($this->_nap_cache->exists($id))
  285. {
  286. debug_add("Cache hit for the guid {$id}.");
  287. $nodedata = $this->_nap_cache->get($id);
  288. $this->_nap_cache->close();
  289. }
  290. else
  291. {
  292. debug_add("No cache hit for the guid {$id}.");
  293. $this->_nap_cache->close();
  294.  
  295. $nodedata = $this->_get_node_from_database($id);
  296. $this->_nap_cache->put($id, $nodedata);
  297. debug_add("Added the guid {$id} to the cache.");
  298. }
  299. if (is_null($nodedata))
  300. {
  301. debug_add('We got NULL for this node, so we do not have any NAP information, returning null directly.');
  302. debug_pop();
  303. return null;
  304. }
  305. // Rewrite all host dependant URLs based on the relative URL within our topic tree.
  306. $midgard = mgd_get_midgard();
  307. $nodedata[MIDCOM_NAV_FULLURL] = "{$GLOBALS['midcom_config']['midcom_site_url']}{$nodedata[MIDCOM_NAV_RELATIVEURL]}";
  308. $nodedata[MIDCOM_NAV_ABSOLUTEURL] = substr($GLOBALS['midcom_config']['midcom_site_url'], strlen($GLOBALS['midcom']->get_host_name()))
  309. . "{$nodedata[MIDCOM_NAV_RELATIVEURL]}";
  310. $nodedata[MIDCOM_NAV_PERMALINK] = "{$GLOBALS['midcom_config']['midcom_site_url']}midcom-permalink-{$nodedata[MIDCOM_NAV_GUID]}";
  311.  
  312. // In addition, kill the toolbar as this is cached information and thus not relevant for the current user.
  313. $nodedata[MIDCOM_NAV_TOOLBAR] = null;
  314. debug_print_r("Node structure to return:", $nodedata);
  315. debug_pop();
  316. return $nodedata;
  317. }
  318. /**
  319. * Reads a node data structure from the database, completes all defaults and
  320. * derived properties (like ViewerGroups).
  321. *
  322. * @param int $id The ID of the topic for which the NAP information is requested.
  323. * @return Array Node data structure or NULL in case no NAP information is available for this topic.
  324. * @access private
  325. */
  326. function _get_node_from_database($id)
  327. {
  328. debug_push_class(__CLASS__, __FUNCTION__);
  329.  
  330. // Load the topic first.
  331. $topic = mgd_get_topic($id);
  332. if (! $topic)
  333. {
  334. $GLOBALS['midcom']->generate_error(MIDCOM_ERRCRIT,
  335. "Cannot load NAP information, aborting: Could not load the topic {$id} from the database ("
  336. . mgd_errstr() . ').');
  337. // This will exit().
  338. }
  339. debug_add("Trying to load NAP data for topic {$topic->name} (#{$topic->id})");
  340. // Retrieve a NAP instance
  341. $path = $topic->parameter('midcom', 'component');
  342. if ($path === false)
  343. {
  344. debug_print_r('Topic object dump:', $topic);
  345. $GLOBALS['midcom']->generate_error(MIDCOM_ERRCRIT,
  346. "Cannot load NAP information, aborting: The topic {$topic->id} does not have a component assigned.");
  347. // This will exit().
  348. }
  349. $nap =& $this->_loader->get_nap_class($path);
  350. if (! $nap->set_object($topic))
  351. {
  352. debug_print_r('Topic object dump:', $topic);
  353. $GLOBALS['midcom']->generate_error(MIDCOM_ERRCRIT,
  354. "Cannot load NAP information, aborting: Could not set the nap instance of {$path} to the topic {$topic->id}.");
  355. // This will exit().
  356. }
  357. // Get the node data and verify this is a node that actually has any relevant NAP
  358. // information. Internal components like AIS or the L10n editor, which don't have
  359. // a NAP interface yet return null here, to be exempt from any NAP processing.
  360. $nodedata = $nap->get_node();
  361. if (is_null($nodedata))
  362. {
  363. debug_add("The component {$path} did return null for the topic {$topic->id}, indicating no NAP information is available.");
  364. debug_pop();
  365. return null;
  366. }
  367. // Now complete the node data structure, we need a metadata object for this:
  368. $metadata =& midcom_helper_metadata::retrieve($topic);
  369. $nodedata[MIDCOM_NAV_URL] = $topic->name . '/';
  370. $nodedata[MIDCOM_NAV_NAME] = trim($nodedata[MIDCOM_NAV_NAME]) == '' ? $topic->name : $nodedata[MIDCOM_NAV_NAME];
  371. $nodedata[MIDCOM_NAV_GUID] = $topic->guid();
  372. $nodedata[MIDCOM_NAV_ID] = $topic->id;
  373. $nodedata[MIDCOM_NAV_TYPE] = 'node';
  374. $nodedata[MIDCOM_NAV_SCORE] = $topic->score;
  375. $nodedata[MIDCOM_NAV_COMPONENT] = $path;
  376. $nodedata[MIDCOM_NAV_SUBNODES] = null;
  377. $nodedata[MIDCOM_NAV_LEAVES] = null;
  378. if (! array_key_exists(MIDCOM_NAV_TOOLBAR, $nodedata))
  379. {
  380. $nodedata[MIDCOM_NAV_TOOLBAR] = null;
  381. }
  382. if ( ! array_key_exists(MIDCOM_NAV_NOENTRY, $nodedata)
  383. || $nodedata[MIDCOM_NAV_NOENTRY] == false)
  384. {
  385. $nodedata[MIDCOM_NAV_NOENTRY] = (bool) $metadata->get('nav_noentry');
  386. }
  387. if ($topic->id == $this->_root)
  388. {
  389. $nodedata[MIDCOM_NAV_NODEID] = -1;
  390. $nodedata[MIDCOM_NAV_RELATIVEURL] = '';
  391. }
  392. else
  393. {
  394. $nodedata[MIDCOM_NAV_NODEID] = $topic->up;
  395. $nodedata[MIDCOM_NAV_RELATIVEURL] = $this->_nodes[$nodedata[MIDCOM_NAV_NODEID]][MIDCOM_NAV_RELATIVEURL] . $nodedata[MIDCOM_NAV_URL];
  396. }
  397. $nodedata[MIDCOM_NAV_OBJECT] = $topic;
  398. // Collect Viewergroups
  399. // A topic can be viewed by all groups by default
  400. $nodedata[MIDCOM_NAV_VIEWERGROUPS] = null;
  401. $topic_viewers = $topic->listparameters("ViewerGroups");
  402. if ($topic_viewers)
  403. {
  404. $groups = Array();
  405. while ($topic_viewers->fetch())
  406. {
  407. if ($topic_viewers->name == 'all')
  408. {
  409. // There is an "all" value, everybody can access this topic for sure.
  410. debug_add("Got a viewer Group 'all', breaking out of the loop and leaving the topic readable for everybody.");
  411. break;
  412. }
  413. $groups[] = $topic_viewers->name; }
  414. $nodedata[MIDCOM_NAV_VIEWERGROUPS] = $groups;
  415. }
  416. // Temporary compatiblity value
  417. $nodedata[MIDCOM_NAV_VISIBLE] = true;
  418. debug_pop();
  419. return $nodedata;
  420. }
  421. /**
  422. * Return the list of leaves for a given node. This helper will construct complete leaf
  423. * data structures for each leaf found. It will first check the cache for the leaf structures,
  424. * and query the database only if the corresponding objects have not been found there.
  425. *
  426. * No visibility checks are made at this point.
  427. *
  428. * @param Array $node The node data structure for which to retrieve the leaves.
  429. * @return Array All leaves found for that node, in complete post processed leave data structures.
  430. * @access private
  431. */
  432. function _get_leaves($node)
  433. {
  434. debug_push_class(__CLASS__, __FUNCTION__);
  435. debug_add("Trying to load NAP leaf data for topic {$node[MIDCOM_NAV_OBJECT]->name} (#{$node[MIDCOM_NAV_OBJECT]->id})");
  436.  
  437. $entry_name = "{$node[MIDCOM_NAV_ID]}-leaves";
  438. $this->_nap_cache->open();
  439. if ($this->_nap_cache->exists($entry_name))
  440. {
  441. $leaves = $this->_nap_cache->get($entry_name);
  442. }
  443. else
  444. {
  445. $leaves = null;
  446. }
  447. $this->_nap_cache->close();
  448. if (is_null($leaves))
  449. {
  450. // Appearantly, the leaves have not yet been loaded for this topic, so we have to do this now.
  451. // Afterwards we update the cache.
  452. debug_add('The leaves have not yet been loaded from the database, we do this now.');
  453. $leaves = $this->_get_leaves_from_database($node);
  454. $this->_write_leaves_to_cache($node, $leaves);
  455. }
  456. // Post process the leaves for URLs and the like. Don't forget NAV_ADMIN/NAV_SITE
  457. // Rewrite all host dependant URLs based on the relative URL within our topic tree.
  458. $this->_update_leaflist_urls($leaves);
  459. debug_print_r("We will return these leaves:", $leaves);
  460. debug_pop();
  461. return $leaves;
  462. }
  463. /**
  464. * This helper updates the URLs in the reference-passed leaf list.
  465. * FULLURL, ABSOLUTEURL and PERMALINK are built upon RELATIVEURL,
  466. * NAV_NAME and NAV_URL are populated based on the administration mode with either
  467. * NAV_ADMIN or NAV_SITE values.
  468. *
  469. * @param Array $leaves A reference to the list of leaves which has to be processed.
  470. * @access private
  471. */
  472. function _update_leaflist_urls(&$leaves)
  473. {
  474. debug_push_class(__CLASS__, __FUNCTION__);
  475. $fullprefix = "{$GLOBALS['midcom_config']['midcom_site_url']}";
  476. $absoluteprefix = substr($GLOBALS['midcom_config']['midcom_site_url'], strlen($GLOBALS['midcom']->get_host_name()));
  477. $permaprefix = "{$fullprefix}midcom-permalink-";
  478.  
  479. if (! is_array($leaves))
  480. {
  481. echo "<pre>"; print_r($leaves); echo "</pre>";
  482. die ("wrong type");
  483. }
  484. foreach ($leaves as $id => $copy)
  485. {
  486. $leaves[$id][MIDCOM_NAV_FULLURL] = $fullprefix . $leaves[$id][MIDCOM_NAV_RELATIVEURL];
  487. $leaves[$id][MIDCOM_NAV_ABSOLUTEURL] = $absoluteprefix . $leaves[$id][MIDCOM_NAV_RELATIVEURL];
  488. if (is_null($leaves[$id][MIDCOM_NAV_GUID]))
  489. {
  490. $leaves[$id][MIDCOM_NAV_PERMALINK] = $leaves[$id][MIDCOM_NAV_FULLURL];
  491. }
  492. else
  493. {
  494. $leaves[$id][MIDCOM_NAV_PERMALINK] = $permaprefix . $leaves[$id][MIDCOM_NAV_GUID];
  495. }
  496. if ($this->_adminmode)
  497. {
  498. $leaves[$id][MIDCOM_NAV_URL] = $leaves[$id][MIDCOM_NAV_ADMIN][MIDCOM_NAV_URL];
  499. $leaves[$id][MIDCOM_NAV_NAME] = $leaves[$id][MIDCOM_NAV_ADMIN][MIDCOM_NAV_NAME];
  500. }
  501. else
  502. {
  503. $leaves[$id][MIDCOM_NAV_URL] = $leaves[$id][MIDCOM_NAV_SITE][MIDCOM_NAV_URL];
  504. $leaves[$id][MIDCOM_NAV_NAME] = $leaves[$id][MIDCOM_NAV_SITE][MIDCOM_NAV_NAME];
  505. }
  506. // In addition, kill the toolbar as this is cached information and thus not relevant for the current user.
  507. $leaves[$id][MIDCOM_NAV_TOOLBAR] = null;
  508. }
  509. debug_pop();
  510. }
  511. /**
  512. * Writes the leaves passed to this function to the cache, assigning them to the
  513. * specified node.
  514. *
  515. * The function will bail out on any critical error. Data inconsistencies will be
  516. * logged and overwritten silently otherwise.
  517. *
  518. * @param Array $node The node datastructure to which the leaves should be assigned.
  519. * @param Array $leaves The leaves to store in the cache.
  520. * @access private
  521. */
  522. function _write_leaves_to_cache($node, $leaves)
  523. {
  524. debug_push_class(__CLASS__, __FUNCTION__);
  525. debug_add('Writing ' . count ($leaves) . ' leaves to the cache.');
  526. // We need to update the node too, as it contains the leaf list for rapid access.
  527. $node_leaflist = array_keys($leaves);
  528. $this->_nap_cache->open(true);
  529. if (! $this->_nap_cache->exists($node[MIDCOM_NAV_ID]))
  530. {
  531. $this->_nap_cache->close();
  532. debug_add("NAP Caching Engine: Tried to update the topic {$node[MIDCOM_NAV_OBJECT]->name} (#{$node[MIDCOM_NAV_OBJECT]->id}) "
  533. . 'which was supposed to be in the cache already, but failed to load the object from the database. '
  534. . 'Aborting write_to_cache, this is a critical cache inconsistency.', MIDCOM_LOG_WARN);
  535. debug_pop();
  536. return;
  537. }
  538. // We load it again to get the cached structure, not the completed one from the
  539. // in-memory cache.
  540. $cached_node = $this->_nap_cache->get($node[MIDCOM_NAV_ID]);
  541. $cached_node[MIDCOM_NAV_LEAVES] = $node_leaflist;
  542. debug_print_r('Updating the Node structure in the cache to this:', $cached_node);
  543. $this->_nap_cache->put($node[MIDCOM_NAV_ID], $cached_node);
  544. $this->_nap_cache->put("{$node[MIDCOM_NAV_ID]}-leaves", $leaves);
  545. $this->_nap_cache->close();
  546. debug_pop();
  547. }
  548. /**
  549. * This helper is responsible for loading the leaves for a given node out of the
  550. * database. It will complete all default fields to provide full blown nap structures.
  551. * It will also build the base relative URLs which will later be completed by the
  552. * _get_leaves() interface functions.
  553. *
  554. * Important notes:
  555. * - The ViewerGroups property is copied from the parent topic, to ensure the same level of visibility.
  556. * - The IDs constructed for the leaves are the concatenation of the ID delivered by the component
  557. * and the topics' GUID.
  558. *
  559. * @param Array $node The node data structure for which to retrieve the leaves.
  560. * @return Array All leaves found for that node, in complete post processed leave data structures.
  561. * @access private
  562. */
  563. function _get_leaves_from_database($node)
  564. {
  565. debug_push_class(__CLASS__, __FUNCTION__);
  566. $topic = $node[MIDCOM_NAV_OBJECT];
  567. // Retrieve a NAP instance
  568. $nap =& $this->_loader->get_nap_class($node[MIDCOM_NAV_COMPONENT]);
  569. if (! $nap->set_object($topic))
  570. {
  571. debug_print_r('Topic object dump:', $topic);
  572. $GLOBALS['midcom']->generate_error(MIDCOM_ERRCRIT,
  573. "Cannot load NAP information, aborting: Could not set the nap instance of {$path} to the topic {$topic->id}.");
  574. // This will exit().
  575. }
  576. $leafdata = $nap->get_leaves();
  577. $leaves = Array();
  578. foreach ($leafdata as $id => $leaf)
  579. {
  580. // First, try to somehow gain both a GUID and a Leaf.
  581. if ( ! array_key_exists(MIDCOM_NAV_GUID, $leaf)
  582. && ! array_key_exists(MIDCOM_NAV_OBJECT, $leaf))
  583. {
  584. debug_add("Warning: The leaf {$id} of topic {$topic->id} does set neither a GUID nor an object.", MIDCOM_LOG_WARN);
  585. $leaf[MIDCOM_NAV_GUID] = null;
  586. $leaf[MIDCOM_NAV_OBJECT] = null;
  587. }
  588. else if (! array_key_exists(MIDCOM_NAV_GUID, $leaf))
  589. {
  590. $leaf[MIDCOM_NAV_GUID] = $leaf[MIDCOM_NAV_OBJECT]->guid();
  591. }
  592. else if (! array_key_exists(MIDCOM_NAV_OBJECT, $leaf))
  593. {
  594. $leaf[MIDCOM_NAV_OBJECT] = mgd_get_object_by_guid($leaf[MIDCOM_NAV_GUID]);
  595. }
  596. $leaf[MIDCOM_NAV_VIEWERGROUPS] = $node[MIDCOM_NAV_VIEWERGROUPS];
  597.  
  598. // Now complete the actual leaf information
  599. // Score
  600. if (! array_key_exists(MIDCOM_NAV_SCORE, $leaf))
  601. {
  602. if ( ! is_null($leaf[MIDCOM_NAV_OBJECT])
  603. && array_key_exists('score', get_object_vars($leaf[MIDCOM_NAV_OBJECT])))
  604. {
  605. $leaf[MIDCOM_NAV_SCORE] = $leaf[MIDCOM_NAV_OBJECT]->score;
  606. }
  607. else
  608. {
  609. $leaf[MIDCOM_NAV_SCORE] = 0;
  610. }
  611. }
  612.  
  613. // NAV_NOENTRY Flag
  614. if (! array_key_exists(MIDCOM_NAV_NOENTRY, $leaf))
  615. {
  616. $leaf[MIDCOM_NAV_NOENTRY] = false;
  617. }
  618. if ($leaf[MIDCOM_NAV_NOENTRY] == false)
  619. {
  620. $metadata =& midcom_helper_metadata::retrieve($leaf);
  621. if ($metadata)
  622. {
  623. $leaf[MIDCOM_NAV_NOENTRY] = (bool) $metadata->get('nav_noentry');
  624. }
  625. }
  626. // Complete the NAV_SITE and NAV_ADMIN fields if the old-style
  627. // root level URL/NAME parameters are set. This automatically overrides
  628. // any NAV_SITE/ADMIN settings.
  629. if ( array_key_exists(MIDCOM_NAV_NAME, $leaf)
  630. && array_key_exists(MIDCOM_NAV_URL, $leaf))
  631. {
  632. $leaf[MIDCOM_NAV_SITE][MIDCOM_NAV_URL] = $leaf[MIDCOM_NAV_URL];
  633. $leaf[MIDCOM_NAV_SITE][MIDCOM_NAV_NAME] = $leaf[MIDCOM_NAV_NAME];
  634. $leaf[MIDCOM_NAV_ADMIN][MIDCOM_NAV_URL] = $leaf[MIDCOM_NAV_URL];
  635. $leaf[MIDCOM_NAV_ADMIN][MIDCOM_NAV_NAME] = $leaf[MIDCOM_NAV_NAME];
  636. }
  637. // complete NAV_NAMES where neccessary
  638. if ( ! is_null($leaf[MIDCOM_NAV_SITE])
  639. && trim($leaf[MIDCOM_NAV_SITE][MIDCOM_NAV_NAME]) == '')
  640. {
  641. $leaf[MIDCOM_NAV_SITE][MIDCOM_NAV_NAME] = $leaf[MIDCOM_NAV_ADMIN][MIDCOM_NAV_URL];
  642. }
  643. if ( ! is_null($leaf[MIDCOM_NAV_ADMIN])
  644. && trim($leaf[MIDCOM_NAV_ADMIN][MIDCOM_NAV_NAME]) == '')
  645. {
  646. $leaf[MIDCOM_NAV_ADMIN][MIDCOM_NAV_NAME] = $leaf[MIDCOM_NAV_ADMIN][MIDCOM_NAV_URL];
  647. }
  648. // Toolbar
  649. if (! array_key_exists(