source: trunk/lib/Navigation.inc.php @ 534

Last change on this file since 534 was 534, checked in by anonymous, 9 years ago

Improved module maker validation output. Allow disabling cache at run time for ACL. Added ACL getList() method. Improved ACL CLI listing. Fixed app boomerang array initialization. Now retaining identical boomerang URLs if the key is different. Added a maximum boomerang time. Added a way to disable cache per request through a query string. Added validator isDecimal() method. Added disableSelectOptions() HTML method. Added getGravatarURL() method. Change how navigation page array is managed. Updated navigation currentPage() method to test an array of URLs.

File size: 15.9 KB
Line 
1<?php
2/**
3 * The Strangecode Codebase - a general application development framework for PHP
4 * For details visit the project site: <http://trac.strangecode.com/codebase/>
5 * Copyright 2001-2012 Strangecode, LLC
6 *
7 * This file is part of The Strangecode Codebase.
8 *
9 * The Strangecode Codebase is free software: you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your option)
12 * any later version.
13 *
14 * The Strangecode Codebase is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/**
24 * Navigation.inc.php
25 *
26 * The Nav class provides a system for working with navigation elements.
27 * It supports storing page titles and URLs for printing breadcrumbs
28 * and titles, as well as setting page params such as hiding the page title on
29 * some pages but not others, and storing vars like the page title itself.
30 *
31 * Note: this class was renamed from "Nav" because of the change in API and to be more descriptive.
32 *
33 * @author  Quinn Comendant <quinn@strangecode.com>
34 * @version 2.0
35 */
36class Navigation
37{
38
39    // Configuration parameters for this object.
40    protected $_params = array(
41        'head_title' => true,
42        'body_title' => true,
43        'title' => true,
44        'path' => true,
45        'breadcrumbs' => true,
46        'chop_breadcrumbs' => 0,
47        'chop_breadcrumb_links' => 1,
48        'path_delimiter' => ' / ',
49        'last_crumb_format' => '%s',
50        'current_page_url' => null, // This should be set at runtime using, e.g., $_SERVER['REQUEST_URI']
51    );
52    public $pages = array();
53
54    /**
55     * Navigation constructor.
56     */
57    public function __construct($params=null)
58    {
59        $app =& App::getInstance();
60
61        // Define current_page_url here because _SERVER, not a static scalar, cannot be defined in the defaults above.
62        // Using PHP_SELF for legacy compatability, but it might make sense to override this with REQUEST_URI.
63        // This could be overwritten by passed params.
64        $this->_params['current_page_url'] = $_SERVER['PHP_SELF'];
65
66        if (isset($params) && is_array($params)) {
67            // Merge new parameters with old overriding only those passed.
68            $this->_params = array_merge($this->_params, $params);
69        }
70    }
71
72    /**
73     * Add a page to the internal pages array. Pages must be added sequentially
74     * as they are to be printed. The root page must be added first, and the
75     * current page added last. Vars can be specified for any page, but only vars
76     * from the "current" page will be accessed with Nav::get.
77     *
78     * @access  public
79     * @param   string  $title      The title of the page.
80     * @param   string  $url        The URL to the page. Set to null to use REQUEST_URI.
81     * @param   array   $vars       Additional page variables.
82     */
83    public function add($title, $url=null, $vars=array())
84    {
85        $page = array(
86            'title' => $title,
87            'head_title' => $title,
88            'body_title' => $title,
89            'url' => is_null($url) ? $this->_params['current_page_url'] : $url,
90        );
91        // An "unformed page element" has settings applied (via ->set()) but no page added (via ->add()).
92        if (empty($this->pages) || isset(end($this->pages)['title'])) {
93            // There are no unformed page elements; add a whole new page.
94            $this->pages[] = array_merge($page, $vars);
95        } else {
96            // Append the new page to the unformed page element.
97            $curr_page =& $this->pages[key($this->pages)];
98            $curr_page = array_merge($curr_page, $page, $vars);
99        }
100    }
101
102    /**
103     * Set (or overwrite existing) parameters by passing an array of new parameters.
104     *
105     * @access public
106     * @param  array    $params     Array of parameters (key => val pairs).
107     */
108    public function setParam($params)
109    {
110        $app =& App::getInstance();
111
112        if (isset($params) && is_array($params)) {
113            // Merge new parameters with old overriding only those passed.
114            $this->_params = array_merge($this->_params, $params);
115        } else {
116            $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__);
117        }
118    }
119
120    /**
121     * Return the value of a parameter, if it exists.
122     *
123     * @access public
124     * @param string $param        Which parameter to return.
125     * @return mixed               Configured parameter value.
126     */
127    public function getParam($param)
128    {
129        $app =& App::getInstance();
130
131        if (array_key_exists($param, $this->_params)) {
132            return $this->_params[$param];
133        } else {
134            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
135            return null;
136        }
137    }
138
139    /**
140     * Unsets all pages.
141     *
142     * @access  public
143     */
144    public function clear()
145    {
146        $this->pages = array();
147    }
148
149    /**
150     * Sets a variable into the current page.
151     *
152     * @access public
153     * @param mixed $key      Which value to set.
154     * @param mixed $val      Value to set variable to.
155     */
156    public function set($key, $val)
157    {
158        // Set params of current page.
159        if (empty($this->pages)) {
160            // If we're setting a value on an empty pages array, we need to add one "unformed" element first.
161            $this->pages[] = array();
162        }
163        end($this->pages);
164        $curr_page =& $this->pages[key($this->pages)];
165        $curr_page[$key] = $val;
166    }
167
168    /**
169     * Returns a specified value from the current page.
170     *
171     * @access public
172     * @param mixed $key      Which value to return.
173     * @param mixed $default  Value to return if key not found in user_data.
174     * @return mixed          Value stored in session.
175     */
176    public function get($key, $default='')
177    {
178        end($this->pages);
179        $curr_page =& $this->pages[key($this->pages)];
180
181        switch ($key) {
182        case 'title' :
183            if ($this->getParam('title') && isset($curr_page['title'])) {
184                return $curr_page['title'];
185            }
186            break;
187
188        case 'head_title' :
189            if ($this->getParam('head_title') && $this->getParam('title') && isset($curr_page['head_title'])) {
190                return $curr_page['head_title'];
191            }
192            break;
193
194        case 'body_title' :
195            if ($this->getParam('body_title') && $this->getParam('title') && isset($curr_page['body_title'])) {
196                return $curr_page['body_title'];
197            }
198            break;
199
200        case 'path' :
201            if ($this->getParam('path')) {
202                return $this->getPath();
203            }
204            break;
205
206        case 'breadcrumbs' :
207            if ($this->getParam('breadcrumbs')) {
208                return $this->getBreadcrumbs();
209            }
210            break;
211
212        default :
213            return isset($curr_page[$key]) ? $curr_page[$key] : $default;
214            break;
215        }
216
217        return $default;
218    }
219
220    /**
221     * Returns the path from root up to the current page as an array.
222     *
223     * @access  public
224     * @param   string   $key   Which value to use in the path (usually head_title or body_title or just title).
225     * @return  mixed           Path (string) or false if path param is not set.
226     */
227    public function getPathArray($key='title')
228    {
229        $path = array();
230        if ($this->getParam('path')) {
231            foreach ($this->pages as $page) {
232                $path[] = strip_tags($page[$key]);
233            }
234        }
235        return $path;
236    }
237
238    /**
239     * Returns the text path from root up to the current page, separated by the
240     * path_delimiter.
241     *
242     * @access  public
243     * @param   string   $key   Which value to use in the path (usually head_title or body_title or just title).
244     * @return  mixed           Path (string) or false if path param is not set.
245     */
246    public function getPath($key='title')
247    {
248
249        $path = $this->getPathArray();
250        return empty($path) ? '' : join(oTxt($this->getParam('path_delimiter'), true), $path);
251    }
252
253    /**
254     * Returns the breadcrumbs from the root page to the current page.
255     * Breadcrumbs are the text path with pages titles linked to that page.
256     *
257     * @access  public
258     * @return  string   Breadcrumbs or empty string if breadcrumbs param not set.
259     */
260    public function getBreadcrumbsArray()
261    {
262        $app =& App::getInstance();
263
264        if ($this->getParam('breadcrumbs')) {
265            $breadcrumbs = array();
266            $crumb_count = sizeof($this->pages);
267            foreach ($this->pages as $page) {
268                if ($crumb_count <= $this->getParam('chop_breadcrumbs')) {
269                    // Stop gathering crumbs.
270                    break;
271                }
272                if ($crumb_count <= 1) {
273                    // The last crumb.
274                    if ('' == trim($page['url']) || $crumb_count <= $this->getParam('chop_breadcrumb_links')) {
275                        // A crumb with no link.
276                        $breadcrumbs[] = array(
277                            'url' => $_SERVER['REQUEST_URI'],
278                            'title' => sprintf($this->getParam('last_crumb_format'), $page['title']),
279                            'class' => 'current'
280                        );
281                    } else if ($crumb_count > $this->getParam('chop_breadcrumb_links')) {
282                        // A normal linked crumb.
283                        $breadcrumbs[] = array(
284                            'url' => $page['url'],
285                            'title' => sprintf($this->getParam('last_crumb_format'), $page['title']),
286                            'class' => '',
287                        );
288                    }
289                } else {
290                    if ('' == trim($page['url'])) {
291                        // A crumb with no link.
292                        $breadcrumbs[] = array(
293                            'url' => false,
294                            'title' => $page['title'],
295                            'class' => 'unavailable',
296                        );
297                    } else {
298                        // A normal linked crumb.
299                        $breadcrumbs[] = array(
300                            'url' => $page['url'],
301                            'title' => $page['title'],
302                            'class' => '',
303                        );
304                    }
305                }
306                $crumb_count--;
307            }
308            return $breadcrumbs;
309        } else {
310            return array();
311        }
312    }
313
314    /**
315     * Returns the breadcrumbs from the root page to the current page.
316     * Breadcrumbs are the text path with pages titles linked to that page.
317     *
318     * @access  public
319     * @return  string   Breadcrumbs or empty string if breadcrumbs param not set.
320     */
321    public function getBreadcrumbs()
322    {
323        $app =& App::getInstance();
324
325        if ($this->getParam('breadcrumbs')) {
326            $breadcrumbs = array();
327            $pathmark = '';
328            $crumb_count = sizeof($this->pages);
329            foreach ($this->pages as $page) {
330                if ($crumb_count <= $this->getParam('chop_breadcrumbs')) {
331                    // Stop gathering crumbs.
332                    break;
333                }
334                if ($crumb_count <= 1) {
335                    // The last crumb.
336                    if ('' == trim($page['url']) || $crumb_count <= $this->getParam('chop_breadcrumb_links')) {
337                        // A crumb with no link.
338                        $breadcrumbs[] =  sprintf($this->getParam('last_crumb_format'), oTxt($page['title'], true));
339                    } else if ($crumb_count > $this->getParam('chop_breadcrumb_links')) {
340                        // A normal linked crumb.
341                        $breadcrumbs[] =  '<a href="' . $page['url'] . '">' . sprintf($this->getParam('last_crumb_format'), oTxt($page['title'], true)) . '</a>';
342                    }
343                } else {
344                    if ('' == trim($page['url'])) {
345                        // A crumb with no link.
346                        $breadcrumbs[] = oTxt($pathmark . $page['title'], true);
347                    } else {
348                        // A normal linked crumb.
349                        $breadcrumbs[] = '<a href="' . $page['url'] . '">' . oTxt($page['title'], true) . '</a>';
350                    }
351                }
352                $pathmark = $this->getParam('path_delimiter');
353                $crumb_count--;
354            }
355            return join(oTxt($pathmark, true), $breadcrumbs);
356        } else {
357            return '';
358        }
359    }
360
361    /*
362    *
363    *
364    * @access   public
365    * @param
366    * @return
367    * @author   Quinn Comendant <quinn@strangecode.com>
368    * @version  1.0
369    * @since    07 Sep 2014 12:22:19
370    */
371    public function getBreadcrumbsUL()
372    {
373        $out = '';
374        $breadcrumbs = $this->getBreadcrumbsArray();
375        if (!empty($breadcrumbs)) {
376            $out = '<ul class="breadcrumbs">';
377            foreach ($breadcrumbs as $b) {
378                $printclass = '' != $b['class'] ? sprintf(' class="%s"', $b['class']) : '';
379                $out .= sprintf('<li%s><a href="%s">%s</a></li>', $printclass, $b['url'], $b['title']);
380            }
381            $out .= '</ul>';
382        }
383        return $out;
384    }
385
386    /**
387     * Test if the given URI matches the URL of the current page. By default the URI is tested
388     * without concern
389     * One use is to change the returned value for a positive match
390     * so a css class prints for an element representing the current page:
391     *   echo $nav->currentPage('/script.php?op=info', ' class="current"', '', true);
392     * The above will match only if the current page (REQUEST_URI) is also '/script.php?op=info',
393     * and will return the string ' class="current"' if it is.
394     *
395     * @access  public
396     *
397     * @param   mixed   $test_uri       A URI, or an array of URIs, to test against the current page.
398     * @param   mixed   $true_return    The value to return if the current page matches the test URI.
399     * @param   mixed   $false_return   The value to return if the current page does not match the test URI.
400     * @param   bool    $include_query  If set true, include the URI query string in the test.
401     *
402     * @return  mixed   If the test URI matches the current page URI, the value given for $true_return
403     *                  is returned (true by default), otherwise the value given for $false_return is
404     *                  returned (false by default).
405     */
406    public function currentPage($test_uri, $true_return=true, $false_return=false, $include_query=false)
407    {
408        $app =& App::getInstance();
409
410        // If given an array, test each URI recursively returning TRUE on a first match, or FALSE if none match.
411        if (is_array($test_uri)) {
412            foreach ($test_uri as $uri) {
413                if ($this->currentPage($uri, $true_return, $false_return, $include_query)) {
414                    return true;
415                }
416            }
417            return false;
418        }
419
420        $actual_uri = $include_query ? $_SERVER['REQUEST_URI'] : strtok($_SERVER['REQUEST_URI'], '?');
421        $test_uri = $include_query ? $test_uri : strtok($test_uri, '?');
422        if (mb_strtolower($test_uri) == mb_strtolower($actual_uri)) {
423            // $app->logMsg(sprintf('Current page (%s) == test URI (%s)', $actual_uri, $test_uri), LOG_DEBUG, __FILE__, __LINE__);
424            return $true_return;
425        }
426        // $app->logMsg(sprintf('Current page (%s) != test URI (%s)', $actual_uri, $test_uri), LOG_DEBUG, __FILE__, __LINE__);
427        return $false_return;
428    }
429
430}
431// End of class.
Note: See TracBrowser for help on using the repository browser.