1<?php
2/**
3 * The Horde_Menu:: class provides standardized methods for creating menus in
4 * Horde applications.
5 *
6 * Copyright 1999-2017 Horde LLC (http://www.horde.org/)
7 *
8 * See the enclosed file COPYING for license information (LGPL). If you
9 * did not receive this file, see http://www.horde.org/licenses/lgpl21.
10 *
11 * @author   Chuck Hagenbuch <chuck@horde.org>
12 * @author   Jon Parise <jon@horde.org>
13 * @category Horde
14 * @package  Core
15 */
16class Horde_Menu
17{
18    /**
19     * Menu array.
20     *
21     * @var array
22     */
23    protected $_menu = array();
24
25    /**
26     * Add an item to the menu array.
27     *
28     * @param string $url        String containing the value for the hyperlink.
29     * @param string $text       String containing the label for this menu
30     *                           item.
31     * @param string $icon       String containing the filename of the image
32     *                           icon to display for this menu item.
33     * @param string $icon_path  If the icon lives in a non-default directory,
34     *                           where is it?
35     * @param string $target     If the link needs to open in another frame or
36     *                           window, what is its name?
37     * @param string $onclick    Onclick javascript, if desired.
38     * @param string $class      CSS class for the menu item.
39     */
40    public function add($url, $text, $icon = '', $icon_path = null,
41                        $target = '', $onclick = null, $class = null)
42    {
43        $this->_menu[] = array(
44            'url' => ($url instanceof Horde_Url) ? $url : new Horde_Url($url),
45            'text' => $text,
46            'icon' => $icon,
47            'icon_path' => $icon_path,
48            'target' => $target,
49            'onclick' => $onclick,
50            'class' => $class
51        );
52    }
53
54    /**
55     * Add an item to the menu array.
56     *
57     * @param mixed $item  The item to add.  Either a string containing the
58     *                     value 'separator' or an array contianing the
59     *                     following valid keys:
60     * <pre>
61     * 'class' - (string) CSS classname.
62     * 'icon' - (string) Filename of the image icon.
63     * 'icon_path' - (string) Non-default directory path for icon.
64     * 'onclick' - (string) Onclick javascript.
65     * 'target' - (string) HREF target parameter.
66     * 'text' - (string) Label.
67     * 'url' - (string) Hyperlink.
68     * 'container' - (string) Name of sidebar container to add to, if not the
69     *               default.
70     * </pre>
71     */
72    public function addArray($item)
73    {
74        if (!is_array($item) && $item == 'separator') {
75            $this->_menu[] = $item;
76            return;
77        }
78
79        if (!isset($item['url'])) {
80            $item['url'] = new Horde_Url();
81        } elseif (!($item['url'] instanceof Horde_Url)) {
82            $item['url'] = new Horde_Url($item['url']);
83        }
84
85        $this->_menu[] = array_merge(array(
86            'class' => null,
87            'icon' => '',
88            'icon_path' => null,
89            'onclick' => null,
90            'target' => '',
91            'text' => '',
92            'container' => '',
93        ), $item);
94    }
95
96    /**
97     * Return the rendered representation of the menu items.
98     *
99     * @return Horde_View_Sidebar  Sidebar view of menu elements.
100     */
101    public function render()
102    {
103        /* Add any custom menu items. */
104        $this->addSiteLinks();
105
106        /* Sort to match explicitly set positions. */
107        ksort($this->_menu);
108        if ($GLOBALS['registry']->nlsconfig->curr_rtl) {
109            $this->_menu = array_reverse($this->_menu);
110        }
111
112        return $this->_render();
113    }
114
115    /**
116     * Converts the menu to a sidebar view.
117     *
118     * @return Horde_View_Sidebar  Sidebar view of menu elements.
119     */
120    protected function _render()
121    {
122        $sidebar = $GLOBALS['injector']->getInstance('Horde_View_Sidebar');
123
124        foreach ($this->_menu as $m) {
125            /* Check for separators. */
126            if ($m == 'separator') {
127                continue;
128            }
129
130            $row = array(
131                'cssClass' => $m['icon'],
132                'url' => $m['url'],
133                'label' => $m['text'],
134                'target' => $m['target'],
135                'onclick' => $m['onclick'],
136            );
137
138            /* Item class and selected indication. */
139            if (!isset($m['class'])) {
140                /* Try to match the item's path against the current
141                 * script filename as well as other possible URLs to
142                 * this script. */
143                if ($this->isSelected($m['url'])) {
144                    $row['selected'] = true;
145                }
146            } elseif ($m['class'] === '__noselection') {
147                unset($m['class']);
148            } elseif ($m['class'] === 'current') {
149                $row['selected'] = true;
150            } else {
151                $row['class'] = $m['class'];
152            }
153
154            $container = !empty($m['container'])
155                ? $m['container']
156                : '';
157
158            $sidebar->addRow($row, $container);
159        }
160
161        return $sidebar;
162    }
163
164    /**
165     * Add links found in the application's menu configuration.
166     */
167    public function addSiteLinks()
168    {
169        foreach ($this->getSiteLinks() as $item) {
170            $this->addArray($item);
171        }
172    }
173
174    /**
175     * Get the list of site links to add to the menu.
176     *
177     * @return array  A list of menu items to add.
178     */
179    public function getSiteLinks()
180    {
181        $menufile = $GLOBALS['registry']->get('fileroot') . '/config/menu.php';
182
183        if (is_readable($menufile)) {
184            include $menufile;
185            if (isset($_menu) && is_array($_menu)) {
186                return $_menu;
187            }
188        }
189
190        return array();
191    }
192
193    /**
194     * Checks to see if the current url matches the given url.
195     *
196     * @return boolean  Whether the given URL is the current location.
197     */
198    public static function isSelected($url)
199    {
200        $server_url = parse_url($_SERVER['PHP_SELF']);
201        $check_url = parse_url($url);
202
203        /* Try to match the item's path against the current script
204           filename as well as other possible URLs to this script. */
205        return isset($check_url['path']) &&
206            (($check_url['path'] == $server_url['path']) ||
207             ($check_url['path'] . 'index.php' == $server_url['path']) ||
208             ($check_url['path'] . '/index.php' == $server_url['path']));
209    }
210
211}
212