Completed
Push — master ( abfdab...df31dd )
by Andreas
08:27
created

midcom_helper_nav::get_root_node()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package midcom.helper
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * Main Navigation interface class.
11
 *
12
 * Basically, this class proxies all requests to a midcom_helper_nav_backend
13
 * class. See the interface definition of it for further details.
14
 *
15
 * Additionally this class implements a couple of helper functions to make
16
 * common NAP tasks easier.
17
 *
18
 * <b>Important note:</b> Whenever you add new code to this class, or extend it through
19
 * inheritance, never call the proxy-functions of the backend directly, this is strictly
20
 * forbidden.
21
 *
22
 * @todo End-User documentation of node and leaf data, as the one in the backend is incomplete too.
23
 * @package midcom.helper
24
 * @see midcom_helper_nav_backend
25
 */
26
class midcom_helper_nav
1 ignored issue
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
27
{
28
    /**
29
     * A reference to the backend instance in use.
30
     *
31
     * @var midcom_helper_nav_backend
32
     */
33
    private $_backend;
34
35
    /**
36
     * The cache of instantiated NAP backends
37
     *
38
     * @var array
39
     */
40
    private static $_backends = array();
41
42
    /**
43
     * The context ID we're associated with.
44
     *
45
     * @var int
46
     */
47
    private $_contextid;
48
49
    /**
50
     * Create a NAP instance for the given context. If unspecified, it
51
     * uses the currently active context which should be sufficient
52
     * in most cases.
53
     *
54
     * @param int $contextid    The id of the context you want to navigate.
55
     */
56
    public function __construct($contextid = -1)
57
    {
58
        if ($contextid == -1)
59
        {
60
            $contextid = midcom_core_context::get()->id;
61
        }
62
        $this->_contextid = $contextid;
63
        $this->_backend = $this->_get_backend();
64
    }
65
66
    /**
67
     * This function maintains one NAP Class per context. Usually this is enough,
68
     * since you mostly will access it in context 0, the default. The problem is, that
69
     * this is not 100% efficient: If you instantiate two different NAP Classes in
70
     * different contexts both referring to the same root node, you will get two
71
     * different instances.
72
     *
73
     * @return midcom_helper_nav_backend&    A reference to the backend instance in the cache.
0 ignored issues
show
Documentation introduced by
The doc-type midcom_helper_nav_backend& could not be parsed: Unknown type name "midcom_helper_nav_backend&" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
74
     * @see midcom_helper_nav
75
     */
76
    private function & _get_backend()
77
    {
78
        if (!isset(self::$_backends[$this->_contextid]))
79
        {
80
            self::$_backends[$this->_contextid] = new midcom_helper_nav_backend($this->_contextid);
81
        }
82
83
        return self::$_backends[$this->_contextid];
84
    }
85
86
    /* The following methods are just interfaces to midcom_helper_nav_backend */
87
88
    /**
89
     * Retrieve the ID of the currently displayed node. Defined by the topic of
90
     * the component that declared able to handle the request.
91
     *
92
     * @return int    The ID of the node in question.
93
     * @see midcom_helper_nav_backend::get_current_node()
94
     */
95
    public function get_current_node()
96
    {
97
        return $this->_backend->get_current_node();
98
    }
99
100
    /**
101
     * Retrieve the ID of the currently displayed leaf. This is a leaf that is
102
     * displayed by the handling topic. If no leaf is active, this function
103
     * returns false. (Remember to make a type sensitive check, e.g.
104
     * nav::get_current_leaf() !== false to distinguish '0' and 'false'.)
105
     *
106
     * @return int    The ID of the leaf in question or false on failure.
107
     * @see midcom_helper_nav_backend::get_current_leaf()
108
     */
109
    public function get_current_leaf()
110
    {
111
        return $this->_backend->get_current_leaf();
112
    }
113
114
    /**
115
     * Retrieve the ID of the root node. Note that this ID is dependent from the
116
     * ID of the MidCOM Root topic and therefore will change as easily as the
117
     * root topic ID might. The MIDCOM_NAV_URL entry of the root node's data will
118
     * always be empty.
119
     *
120
     * @return int    The ID of the root node.
121
     * @see midcom_helper_nav_backend::get_root_node()
122
     */
123
    public function get_root_node()
124
    {
125
        return $this->_backend->get_root_node();
126
    }
127
128
    /**
129
     * Lists all Sub-nodes of $parent_node. If there are no subnodes you will get
130
     * an empty array, if there was an error (for instance an unknown parent node
131
     * ID) you will get false.
132
     *
133
     * @param int $parent_node    The id of the node of which the subnodes are searched.
134
     * @param boolean $show_noentry Show all objects on-site which have the noentry flag set.
135
     *     This defaults to false.
136
     * @return Array            An Array of Node IDs or false on failure.
137
     * @see midcom_helper_nav_backend::list_nodes()
138
     */
139
    public function list_nodes($parent_node, $show_noentry = false)
140
    {
141
        return $this->_backend->list_nodes($parent_node, $show_noentry);
142
    }
143
144
    /**
145
     * Lists all leaves of $parent_node. If there are no leaves you will get an
146
     * empty array, if there was an error (for instance an unknown parent node ID)
147
     * you will get false.
148
     *
149
     * @param int $parent_node    The ID of the node of which the leaves are searched.
150
     * @param boolean $show_noentry Show all objects on-site which have the noentry flag set.
151
     *     This defaults to false.
152
     * @return Array             A list of leaves found, or false on failure.
153
     * @see midcom_helper_nav_backend::list_leaves()
154
     */
155
    public function list_leaves($parent_node, $show_noentry = false)
156
    {
157
        return $this->_backend->list_leaves($parent_node, $show_noentry);
158
    }
159
160
    /**
161
     * This will give you a key-value pair describing the node with the ID
162
     * $node_id. The defined keys are described above in Node data interchange
163
     * format. You will get false if the node ID is invalid.
164
     *
165
     * @param int $node_id    The node ID to be retrieved.
166
     * @return Array        The node data as outlined in the class introduction, false on failure
167
     * @see midcom_helper_nav_backend::get_node()
168
     */
169
    public function get_node($node_id)
170
    {
171
        return $this->_backend->get_node($node_id);
172
    }
173
174
    /**
175
     * This will give you a key-value pair describing the leaf with the ID
176
     * $node_id. The defined keys are described above in leaf data interchange
177
     * format. You will get false if the leaf ID is invalid.
178
     *
179
     * @param string $leaf_id    The leaf-id to be retrieved.
180
     * @return Array        The leaf-data as outlined in the class introduction, false on failure
181
     * @see midcom_helper_nav_backend::get_leaf()
182
     */
183
    public function get_leaf($leaf_id)
184
    {
185
        return $this->_backend->get_leaf($leaf_id);
186
    }
187
188
    /**
189
     * Returns the ID of the node to which $leaf_id is associated to, false
190
     * on failure.
191
     *
192
     * @param string $leaf_id    The Leaf-ID to search an uplink for.
193
     * @return int             The ID of the Node for which we have a match, or false on failure.
194
     * @see midcom_helper_nav_backend::get_leaf_uplink()
195
     */
196
    function get_leaf_uplink ($leaf_id)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
197
    {
198
        return $this->_backend->get_leaf_uplink($leaf_id);
199
    }
200
201
    /**
202
     * Returns the ID of the node to which $node_id is associated to, false
203
     * on failure. The root node's uplink is -1.
204
     *
205
     * @param int $node_id    The Leaf-ID to search an uplink for.
206
     * @return int             The ID of the Node for which we have a match, -1 for the root node, or false on failure.
207
     * @see midcom_helper_nav_backend::get_node_uplink()
208
     */
209
    public function get_node_uplink($node_id)
210
    {
211
        return $this->_backend->get_node_uplink($node_id);
212
    }
213
214
    /**
215
     * Checks if the given node is within the tree of another node.
216
     *
217
     * @param int    $node_id    The node in question.
218
     * @param int    $root_id    The root node to use.
219
     * @return boolean                True, if the node is a subnode of the root node, false otherwise.
220
     */
221
    public function is_node_in_tree($node_id, $root_id)
222
    {
223
        $uplink = $this->get_node_uplink($node_id);
224
        if ($uplink == $root_id)
225
        {
226
            return true;
227
        }
228
        if (   $uplink == false
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $uplink of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
229
            || $uplink == -1)
230
        {
231
            return false;
232
        }
233
        return $this->is_node_in_tree($uplink, $root_id);
234
    }
235
236
    /**
237
     * List all child elements, nodes and leaves alike, of the node with ID
238
     * $parent_node_id. For every child element, an array of ID and type (node/leaf)
239
     * is given as
240
     *
241
     * - MIDCOM_NAV_ID => 0,
242
     * - MIDCOM_NAV_TYPE => 'node'
243
     *
244
     * If there are no child elements at all the method will return an empty array,
245
     * in case of an error false.  NOTE: This method should be quite slow, there's
246
     * room for improvement... :-)
247
     *
248
     * @param int $parent_node_id    The ID of the parent node.
249
     * @return Array                A list of found elements, or false on failure.
250
     */
251
    public function list_child_elements($parent_node_id)
252
    {
253
        $parent_node = $this->get_node($parent_node_id);
254
        if (!$parent_node)
0 ignored issues
show
Bug Best Practice introduced by
The expression $parent_node of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
255
        {
256
            return false;
257
        }
258
259
        $guid = $parent_node[MIDCOM_NAV_GUID];
260
        if (midcom::get()->config->get('symlinks'))
261
        {
262
            $guid = $parent_node[MIDCOM_NAV_OBJECT]->guid;
263
        }
264
265
        $navorder = (int) midcom_db_parameter::get_by_objectguid($guid, 'midcom.helper.nav', 'navorder');
266
        if ($navorder == MIDCOM_NAVORDER_ARTICLESFIRST)
267
        {
268
            $navorder = 'articlesfirst';
269
        }
270
        else if ($navorder == MIDCOM_NAVORDER_SCORE)
271
        {
272
            $navorder = 'score';
273
        }
274
        else
275
        {
276
            $navorder = 'topicsfirst';
277
        }
278
279
        $nav_object = midcom_helper_nav_itemlist::factory($navorder, $this, $parent_node_id);
280
        return $nav_object->get_sorted_list();
281
    }
282
283
    /**
284
     * Try to resolve a guid into a NAP object.
285
     *
286
     * The code is optimized trying to avoid a full-scan if possible. To do this it
287
     * will treat topic and article guids specially: In both cases the system will
288
     * translate it using the topic id into a node id and scan only that part of the
289
     * tree non-recursively.
290
     *
291
     * A full scan of the NAP data is only done if another MidgardObject is used.
292
     *
293
     * Note: If you want to resolve a GUID you got from a Permalink, use the Permalinks
294
     * service within MidCOM, as it covers more objects than the NAP listings.
295
     *
296
     * @param string $guid The GUID of the object to be looked up.
297
     * @param boolean $node_is_sufficient if we could return a good guess of correct parent node but said node does not list the $guid in leaves return the node or try to do a full (and very expensive) NAP scan ?
298
     * @return mixed Either a node or leaf structure, distinguishable by MIDCOM_NAV_TYPE, or false on failure.
299
     * @see midcom_services_permalinks
300
     */
301
    public function resolve_guid($guid, $node_is_sufficient = false)
302
    {
303
        // First, check if the GUID is already known by the backend:
304
        if ($cached_result = $this->_backend->get_loaded_object_by_guid($guid))
305
        {
306
            debug_add('The GUID was already known by the backend instance, returning the cached copy directly.');
307
            return $cached_result;
308
        }
309
310
        // Fetch the object in question for a start, so that we know what to do (tm)
311
        // Note, that objects that cannot be resolved will still be processed using a full-scan of
312
        // the tree. This is, for example, used by the on-delete cache invalidation.
313
        try
314
        {
315
            $object = midcom::get()->dbfactory->get_object_by_guid($guid);
316
        }
317
        catch (midcom_error $e)
318
        {
319
            debug_add("Could not load GUID {$guid}, trying to continue anyway. Last error was: " . $e->getMessage(), MIDCOM_LOG_WARN);
320
        }
321
        if (!empty($object))
322
        {
323
            if (is_a($object, 'midcom_db_topic'))
324
            {
325
                // Ok. This topic should be within the content tree,
326
                // we check this and return the node if everything is ok.
327
                if (!$this->is_node_in_tree($object->id, $this->get_root_node()))
328
                {
329
                    debug_add("The GUID {$guid} leads to an unknown topic not in our tree.", MIDCOM_LOG_WARN);
330
                    return false;
331
                }
332
333
                return $this->get_node($object->id);
334
            }
335
336
            if (is_a($object, 'midcom_db_article'))
337
            {
338
                // Ok, let's try to find the article using the topic in the tree.
339
                if (!$this->is_node_in_tree($object->topic, $this->get_root_node()))
340
                {
341
                    debug_add("The GUID {$guid} leads to an unknown topic not in our tree.", MIDCOM_LOG_WARN);
342
                    return false;
343
                }
344
                if ($leaf = $this->_find_leaf_in_topic($object->topic, $guid))
345
                {
346
                    return $leaf;
347
                }
348
349
                debug_add("The Article GUID {$guid} is somehow hidden from the NAP data in its topic, no results shown.", MIDCOM_LOG_INFO);
350
                return false;
351
            }
352
353
            // Ok, unfortunately, this is not an immediate topic. We try to traverse
354
            // upwards in the object chain to find a topic.
355
            if ($topic = $this->find_closest_topic($object))
356
            {
357
                debug_add("Found topic #{$topic->id}, searching the leaves");
358
                if ($leaf = $this->_find_leaf_in_topic($topic->id, $guid))
359
                {
360
                    return $leaf;
361
                }
362
                if ($node_is_sufficient)
363
                {
364
                    debug_add("Could not find guid in leaves (maybe not listed?), but node is sufficient, returning node");
365
                    return $this->get_node($topic->id);
366
                }
367
            }
368
        }
369
370
        // this is the rest of the lot, we need to traverse everything, unfortunately.
371
        // First, we traverse a list of nodes to be checked on by one, avoiding a recursive
372
        // function call.
373
        $unprocessed_node_ids = Array ($this->get_root_node());
374
375
        while (count ($unprocessed_node_ids) > 0)
376
        {
377
            $node_id = array_shift($unprocessed_node_ids);
378
379
            // Check leaves of this node first.
380
            if ($leaf = $this->_find_leaf_in_topic($node_id, $guid))
381
            {
382
                return $leaf;
383
            }
384
385
            // Ok, append all subnodes to the queue.
386
            $unprocessed_node_ids = array_merge($unprocessed_node_ids, $this->list_nodes($node_id));
387
        }
388
389
        debug_add("We were unable to find the GUID {$guid} in the MidCOM tree even with a full scan.", MIDCOM_LOG_INFO);
390
        return false;
391
    }
392
393
    private function _find_leaf_in_topic($topic, $guid)
394
    {
395
        foreach ($this->list_leaves($topic, true) as $leafid)
396
        {
397
            $leaf = $this->get_leaf($leafid);
398
            if ($leaf[MIDCOM_NAV_GUID] == $guid)
399
            {
400
                return $leaf;
401
            }
402
        }
403
        return false;
404
    }
405
406
    public function find_closest_topic($object)
407
    {
408
        if (!is_object($object))
409
        {
410
            return null;
411
        }
412
        debug_add('Looking for a topic to use via get_parent()');
413
        while ($parent = $object->get_parent())
414
        {
415
            if (is_a($parent, 'midcom_db_topic'))
416
            {
417
                // Verify that this topic is within the current sites tree, if it is not,
418
                // we ignore it. This might happen on symlink topics with n.n.static & co
419
                // which point to the outside f.x.
420
                if ($this->is_node_in_tree($parent->id, $this->get_root_node()))
421
                {
422
                    return $parent;
423
                }
424
            }
425
            $object = $parent;
426
        }
427
        return null;
428
    }
429
430
    /* The more complex interface methods starts here */
431
432
    /**
433
     * Construct a breadcrumb line.
434
     *
435
     * Gives you a line like 'Start > Topic1 > Topic2 > Article' using NAP to
436
     * traverse upwards till the root node. $separator is inserted between the
437
     * pairs, $class, if non-null, will be used as CSS-class for the A-Tags.
438
     *
439
     * The parameter skip_levels indicates how much nodes should be skipped at
440
     * the beginning of the current path. Default is to show the complete path. A
441
     * value of 1 will skip the home link, 2 will skip the home link and the first
442
     * subtopic and so on. If a leaf or node is selected, that normally would be
443
     * hidden, only its name will be shown.
444
     *
445
     * @param string    $separator        The separator to use between the elements.
446
     * @param string    $class            If not-null, it will be assigned to all A tags.
447
     * @param int       $skip_levels      The number of topic levels to skip before starting to work (use this to skip 'Home' links etc.).
448
     * @param string    $current_class    The class that should be assigned to the currently active element.
449
     * @param array     $skip_guids       Array of guids that are skipped.
450
     * @return string    The computed breadcrumb line.
451
     */
452
    public function get_breadcrumb_line($separator = ' &gt; ', $class = null, $skip_levels = 0, $current_class = null, $skip_guids = array())
453
    {
454
        $breadcrumb_data = $this->get_breadcrumb_data();
455
        $result = '';
456
457
        // We traverse this list using the iterator of the array, since this allows
458
        // us direct treatment of the final element.
459
        reset($breadcrumb_data);
460
461
        // Detect real starting Node
462
        if ($skip_levels > 0)
463
        {
464
            if ($skip_levels >= count($breadcrumb_data))
465
            {
466
                debug_add('We were asked to skip all breadcrumb elements that were present (or even more). Returning an empty breadcrumb line therefore.', MIDCOM_LOG_INFO);
467
                return '';
468
            }
469
            $breadcrumb_data = array_slice($breadcrumb_data, $skip_levels);
470
        }
471
472
        $class = is_null($class) ? '' : ' class="' . $class . '"';
473
        while (current($breadcrumb_data) !== false)
474
        {
475
            $data = current($breadcrumb_data);
476
            $entry = htmlspecialchars($data[MIDCOM_NAV_NAME]);
477
478
            // Add the next element sensitive to the fact whether we are at the end or not.
479
            if (next($breadcrumb_data) === false)
480
            {
481
                if ($current_class !== null)
482
                {
483
                    $entry = "<span class=\"{$current_class}\">{$entry}</span>";
484
                }
485
            }
486
            else
487
            {
488
                if (   !empty($data['napobject'][MIDCOM_NAV_GUID])
489
                    && in_array($data['napobject'][MIDCOM_NAV_GUID], $skip_guids))
490
                {
491
                    continue;
492
                }
493
494
                $entry = "<a href=\"{$data[MIDCOM_NAV_URL]}\"{$class}>{$entry}</a>{$separator}";
495
            }
496
            $result .= $entry;
497
        }
498
499
        return $result;
500
    }
501
502
    /**
503
     * Construct source data for a breadcrumb line.
504
     *
505
     * Gives you the data needed to construct a line like
506
     * 'Start > Topic1 > Topic2 > Article' using NAP to
507
     * traverse upwards till the root node. The components custom breadcrumb
508
     * data is inserted at the end of the computed breadcrumb line after any
509
     * set NAP leaf.
510
     *
511
     * See get_breadcrumb_line for a more end-user oriented way of life.
512
     *
513
     * <b>Return Value</b>
514
     *
515
     * The breadcrumb data will be returned as a list of associative arrays each
516
     * containing these keys:
517
     *
518
     * - MIDCOM_NAV_URL The fully qualified URL to the node.
519
     * - MIDCOM_NAV_NAME The clear-text name of the node.
520
     * - MIDCOM_NAV_TYPE One of 'node', 'leaf', 'custom' indicating what type of entry
521
     *   this is.
522
     * - MIDCOM_NAV_ID The Identifier of the structure used to build this entry, this is
523
     *   either a NAP node/leaf ID or the list key set by the component for custom data.
524
     * - 'napobject' This contains the original NAP object retrieved by the function.
525
     *   Just in case you need more information than is available directly.
526
     *
527
     * The entry of every level is indexed by its MIDCOM_NAV_ID, where custom keys preserve
528
     * their original key (as passed by the component) and prefixing it with 'custom-'. This
529
     * allows you to easily check if a given node/leave is within the current breadcrumb-line
530
     * by checking with array_key_exists.
531
     *
532
     * <b>Adding custom data</b>
533
     *
534
     * Custom elements are added to this array by using the MidCOM custom component context
535
     * at this time. You need to add a list with the same structure as above into the
536
     * custom component context key <i>midcom.helper.nav.breadcrumb</i>. (This needs
537
     * to be an array always, even if you return only one element.)
538
     *
539
     * Note, that the URL you pass in that list is always prepended with the current anchor
540
     * prefix. It is not possible to specify absolute URLs there. No leading slash is required.
541
     *
542
     * Example:
543
     *
544
     * <code>
545
     * $tmp = Array
546
     * (
547
     *     Array
548
     *     (
549
     *         MIDCOM_NAV_URL => "list/{$this->_category}/{$this->_mode}/1/",
550
     *         MIDCOM_NAV_NAME => $this->_category_name,
551
     *     ),
552
     * );
553
     * midcom_core_context::get()->set_custom_key('midcom.helper.nav.breadcrumb', $tmp);
554
     * </code>
555
     *
556
     * @return array The computed breadcrumb data as outlined above.
557
     * @todo Maybe cache this? I don't know how complex it really is, but DB accesses are
558
     *     already cached by the _backend core. So it is not that hard.
559
     */
560
    public function get_breadcrumb_data($id = null)
561
    {
562
        $prefix = midcom_core_context::get($this->_contextid)->get_key(MIDCOM_CONTEXT_ANCHORPREFIX);
563
        $result = Array();
564
565
        if (!$id)
566
        {
567
            $curr_leaf = $this->get_current_leaf();
568
            $curr_node = $this->get_current_node();
569
        }
570
        else
571
        {
572
            $curr_leaf = $this->get_leaf($id);
573
            $curr_node = -1;
574
575
            if (!$curr_leaf)
0 ignored issues
show
Bug Best Practice introduced by
The expression $curr_leaf of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
576
            {
577
                if ($node = $this->get_node($id))
578
                {
579
                    $curr_node = $node[MIDCOM_NAV_ID];
580
                }
581
            }
582
            else
583
            {
584
                $curr_node = $this->get_node($curr_leaf[MIDCOM_NAV_NODEID]);
585
            }
586
        }
587
        foreach ($this->get_node_path($curr_node) as $node_id)
588
        {
589
            $node = $this->get_node($node_id);
590
            $result[$node[MIDCOM_NAV_ID]] = Array
591
            (
592
                MIDCOM_NAV_URL => $node[MIDCOM_NAV_ABSOLUTEURL],
593
                MIDCOM_NAV_NAME => $node[MIDCOM_NAV_NAME],
594
                MIDCOM_NAV_TYPE => 'node',
595
                MIDCOM_NAV_ID => $node_id,
596
                'napobject' => $node,
597
            );
598
        }
599
        if ($curr_leaf !== false)
600
        {
601
            $leaf = $this->get_leaf($curr_leaf);
602
603
            // Ignore Index Article Leaves
604
            if ($leaf[MIDCOM_NAV_URL] != '')
605
            {
606
                $result[$leaf[MIDCOM_NAV_ID]] = Array
607
                (
608
                    MIDCOM_NAV_URL => $leaf[MIDCOM_NAV_ABSOLUTEURL],
609
                    MIDCOM_NAV_NAME => $leaf[MIDCOM_NAV_NAME],
610
                    MIDCOM_NAV_TYPE => 'leaf',
611
                    MIDCOM_NAV_ID => $curr_leaf,
612
                    'napobject' => $leaf,
613
                );
614
            }
615
        }
616
617
        if (midcom_core_context::get()->has_custom_key('midcom.helper.nav.breadcrumb'))
618
        {
619
            $customdata = midcom_core_context::get()->get_custom_key('midcom.helper.nav.breadcrumb');
620
            if (is_array($customdata))
621
            {
622
                foreach ($customdata as $key => $entry)
623
                {
624
                    $id = "custom-{$key}";
625
626
                    $url = "{$prefix}{$entry[MIDCOM_NAV_URL]}";
627
                    if (   substr($entry[MIDCOM_NAV_URL], 0, 1) == '/'
628
                        || preg_match('|^https?://|', $entry[MIDCOM_NAV_URL]))
629
                    {
630
                        $url = $entry[MIDCOM_NAV_URL];
631
                    }
632
633
                    $result[$id] = Array
634
                    (
635
                        MIDCOM_NAV_URL => $url,
636
                        MIDCOM_NAV_NAME => $entry[MIDCOM_NAV_NAME],
637
                        MIDCOM_NAV_TYPE => 'custom',
638
                        MIDCOM_NAV_ID => $id,
639
                        'napobject' => $entry,
640
                    );
641
                }
642
            }
643
        }
644
        return $result;
645
    }
646
647
    /**
648
     * Retrieve the IDs of the nodes from the URL. First value at key 0 is
649
     * the root node ID, possible second value is the first subnode ID etc.
650
     * Contains only visible nodes (nodes which can be loaded).
651
     *
652
     * @return Array    The node path array.
653
     */
654
    public function get_node_path($node_id = null)
655
    {
656
        if ($node_id === null)
657
        {
658
            return $this->_backend->get_node_path();
659
        }
660
        $path = array();
661
        $node = $this->get_node($node_id);
662
        while ($node)
0 ignored issues
show
Bug Best Practice introduced by
The expression $node of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
663
        {
664
            $path[] = $node[MIDCOM_NAV_ID];
665
            if ($node[MIDCOM_NAV_NODEID] === -1)
666
            {
667
                break;
668
            }
669
            $node = $this->get_node($node[MIDCOM_NAV_NODEID]);
670
        }
671
        return array_reverse($path);
672
    }
673
674
    /**
675
     * Retrieve the ID of the upper node of the currently displayed node.
676
     *
677
     * @return mixed    The ID of the node in question.
678
     */
679
    public function get_current_upper_node()
680
    {
681
        return $this->_backend->get_current_upper_node();
682
    }
683
}
684