* Copyright 2001-2012 Strangecode, LLC
*
* This file is part of The Strangecode Codebase.
*
* The Strangecode Codebase is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* The Strangecode Codebase is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* The Strangecode Codebase. If not, see .
*/
/**
* Navigation.inc.php
*
* The Nav class provides a system for working with navigation elements.
* It supports storing page titles and URLs for printing breadcrumbs
* and titles, as well as setting page params such as hiding the page title on
* some pages but not others, and storing vars like the page title itself.
*
* Note: this class was renamed from "Nav" because of the change in API and to be more descriptive.
*
* @author Quinn Comendant
* @version 2.0
*/
class Navigation
{
// Configuration parameters for this object.
protected $_params = array(
'head_title' => true,
'body_title' => true,
'title' => true,
'path' => true,
'breadcrumbs' => true,
'chop_breadcrumbs' => 0,
'chop_breadcrumb_links' => 1,
'path_delimiter' => ' / ',
'last_crumb_format' => '%s',
'current_page_url' => null, // This should be set at runtime using, e.g., $_SERVER['REQUEST_URI']
);
public $pages = array();
/**
* Navigation constructor.
*/
public function __construct(Array $params=[])
{
$app =& App::getInstance();
// Define current_page_url here because _SERVER, not a static scalar, cannot be defined in the defaults above.
// Using PHP_SELF for legacy compatibility, but it might make sense to override this with REQUEST_URI.
// This could be overwritten by passed params.
$this->_params['current_page_url'] = $_SERVER['PHP_SELF'];
if (isset($params) && is_array($params)) {
// Merge new parameters with old overriding only those passed.
$this->_params = array_merge($this->_params, $params);
}
}
/**
* Add a page to the internal pages array. Pages must be added sequentially
* as they are to be printed. The root page must be added first, and the
* current page added last. Vars can be specified for any page, but only vars
* from the "current" page will be accessed with Nav::get.
*
* @access public
* @param string $title The title of the page.
* @param string $url The URL to the page. Set to null to use REQUEST_URI.
* @param array $vars Additional page variables.
*/
public function add($title, $url=null, $vars=array())
{
$page = array(
'title' => $title,
'head_title' => $title,
'body_title' => $title,
'url' => is_null($url) ? $this->_params['current_page_url'] : $url,
);
// An "unformed page element" has settings applied (via ->set()) but no page added (via ->add()).
if (empty($this->pages) || isset(end($this->pages)['title'])) {
// There are no unformed page elements; add a whole new page.
$this->pages[] = array_merge($page, $vars);
} else {
// Append the new page to the unformed page element.
$curr_page =& $this->pages[key($this->pages)];
$curr_page = array_merge($curr_page, $page, $vars);
}
}
/**
* Set (or overwrite existing) parameters by passing an array of new parameters.
*
* @access public
* @param array $params Array of parameters (key => val pairs).
*/
public function setParam($params)
{
$app =& App::getInstance();
if (isset($params) && is_array($params)) {
// Merge new parameters with old overriding only those passed.
$this->_params = array_merge($this->_params, $params);
} else {
$app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__);
}
}
/**
* Return the value of a parameter, if it exists.
*
* @access public
* @param string $param Which parameter to return.
* @return mixed Configured parameter value.
*/
public function getParam($param)
{
$app =& App::getInstance();
if (array_key_exists($param, $this->_params)) {
return $this->_params[$param];
} else {
$app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
return null;
}
}
/**
* Unsets all pages.
*
* @access public
*/
public function clear()
{
$this->pages = array();
}
/**
* Sets a variable into the current page.
*
* @access public
* @param mixed $key Which value to set.
* @param mixed $val Value to set variable to.
*/
public function set($key, $val)
{
// Set params of current page.
if (empty($this->pages)) {
// If we're setting a value on an empty pages array, we need to add one "unformed" element first.
$this->pages[] = array();
}
end($this->pages);
$curr_page =& $this->pages[key($this->pages)];
$curr_page[$key] = $val;
}
/**
* Returns a specified value from the current page.
*
* @access public
* @param mixed $key Which value to return.
* @param mixed $default Value to return if key not found in user_data.
* @return mixed Value stored in session.
*/
public function get($key, $default='')
{
end($this->pages);
$curr_page =& $this->pages[key($this->pages)];
switch ($key) {
case 'title' :
if ($this->getParam('title') && isset($curr_page['title'])) {
return $curr_page['title'];
}
break;
case 'head_title' :
if ($this->getParam('head_title') && $this->getParam('title') && isset($curr_page['head_title'])) {
return $curr_page['head_title'];
}
break;
case 'body_title' :
if ($this->getParam('body_title') && $this->getParam('title') && isset($curr_page['body_title'])) {
return $curr_page['body_title'];
}
break;
case 'path' :
if ($this->getParam('path')) {
return $this->getPath();
}
break;
case 'breadcrumbs' :
if ($this->getParam('breadcrumbs')) {
return $this->getBreadcrumbs();
}
break;
default :
return isset($curr_page[$key]) ? $curr_page[$key] : $default;
break;
}
return $default;
}
/**
* Returns the path from root up to the current page as an array.
*
* @access public
* @param string $key Which value to use in the path (usually head_title or body_title or just title).
* @return mixed Path (string) or false if path param is not set.
*/
public function getPathArray($key='title')
{
$path = array();
if ($this->getParam('path')) {
foreach ($this->pages as $page) {
$path[] = strip_tags($page[$key]);
}
}
return $path;
}
/**
* Returns the text path from root up to the current page, separated by the
* path_delimiter.
*
* @access public
* @param string $key Which value to use in the path (usually head_title or body_title or just title).
* @return mixed Path (string) or false if path param is not set.
*/
public function getPath($key='title')
{
$path = $this->getPathArray($key);
return empty($path) ? '' : join(oTxt($this->getParam('path_delimiter'), true), $path);
}
/**
* Returns the breadcrumbs from the root page to the current page.
* Breadcrumbs are the text path with pages titles linked to that page.
*
* @access public
* @return string Breadcrumbs or empty string if breadcrumbs param not set.
*/
public function getBreadcrumbsArray($carry_args=null)
{
$app =& App::getInstance();
if ($this->getParam('breadcrumbs')) {
$breadcrumbs = array();
$crumb_count = sizeof($this->pages);
foreach ($this->pages as $page) {
if ($crumb_count <= $this->getParam('chop_breadcrumbs')) {
// Stop gathering crumbs.
break;
}
if (!is_null($carry_args)) {
// If this function is called with $carry_args, employ the ohref() method.
$url = $app->ohref($page['url'], $carry_args);
} else {
// Otherwise let the URL pass through as-is (the wise developer must have provided the correct URL when calling $nav->add(…)).
$url = $page['url'];
}
if ($crumb_count <= 1) {
// The last crumb.
if ('' == trim($page['url']) || $crumb_count <= $this->getParam('chop_breadcrumb_links')) {
// A last crumb with no link.
$breadcrumbs[] = array(
'url' => false,
'title' => sprintf($this->getParam('last_crumb_format'), $page['title']),
'class' => 'current'
);
} else if ($crumb_count > $this->getParam('chop_breadcrumb_links')) {
// A last linked crumb.
$breadcrumbs[] = array(
'url' => $url,
'title' => sprintf($this->getParam('last_crumb_format'), $page['title']),
'class' => '',
);
}
} else {
if ('' == trim($page['url'])) {
// A crumb with no link.
$breadcrumbs[] = array(
'url' => false,
'title' => $page['title'],
'class' => 'unavailable',
);
} else {
// A normal linked crumb.
$breadcrumbs[] = array(
'url' => $url,
'title' => $page['title'],
'class' => '',
);
}
}
$crumb_count--;
}
return $breadcrumbs;
} else {
return array();
}
}
/**
* Returns the breadcrumbs from the root page to the current page.
* Breadcrumbs are the text path with pages titles linked to that page.
*
* @access public
* @return string Breadcrumbs or empty string if breadcrumbs param not set.
*/
public function getBreadcrumbs($carry_args=null)
{
$app =& App::getInstance();
if ($this->getParam('breadcrumbs')) {
$breadcrumbs = array();
$pathmark = '';
$crumb_count = sizeof($this->pages);
foreach ($this->pages as $page) {
if ($crumb_count <= $this->getParam('chop_breadcrumbs')) {
// Stop gathering crumbs.
break;
}
if (!is_null($carry_args)) {
// If this function is called with $carry_args, employ the ohref() method.
$url = $app->ohref($page['url'], $carry_args);
} else {
// Otherwise let the URL pass through as-is (the wise developer must have provided the correct URL when calling $nav->add(…)).
$url = $page['url'];
}
if ($crumb_count <= 1) {
// The last crumb.
if ('' == trim($page['url']) || $crumb_count <= $this->getParam('chop_breadcrumb_links')) {
// A last crumb with no link.
$breadcrumbs[] = sprintf($this->getParam('last_crumb_format'), oTxt($page['title'], true));
} else if ($crumb_count > $this->getParam('chop_breadcrumb_links')) {
// A last linked crumb.
$breadcrumbs[] = '' . sprintf($this->getParam('last_crumb_format'), oTxt($page['title'], true)) . '';
}
} else {
if ('' == trim($page['url'])) {
// A crumb with no link.
$breadcrumbs[] = oTxt($pathmark . $page['title'], true);
} else {
// A normal linked crumb.
$breadcrumbs[] = '' . oTxt($page['title'], true) . '';
}
}
$pathmark = $this->getParam('path_delimiter');
$crumb_count--;
}
return join(oTxt($pathmark, true), $breadcrumbs);
} else {
return '';
}
}
/*
*
*
* @access public
* @param
* @return
* @author Quinn Comendant
* @version 1.0
* @since 07 Sep 2014 12:22:19
*/
public function getBreadcrumbsUL($carry_args=null, $ul_open_tag='')
{
$app =& App::getInstance();
$out = '';
$breadcrumbs = $this->getBreadcrumbsArray($carry_args);
if (!empty($breadcrumbs)) {
$out = $ul_open_tag;
foreach ($breadcrumbs as $b) {
$printclass = '' != $b['class'] ? sprintf(' class="%s"', $b['class']) : '';
if ('' == trim($b['url'])) {
// A crumb with no link.
$out .= sprintf('- %s
', $printclass, $b['title']);
} else {
// A normal linked crumb.
$out .= sprintf('- %s
', $printclass, $b['url'], $b['title']);
}
}
$out .= '
';
}
return $out;
}
/**
* Test if the given URI matches the URL of the current page. By default the URI is tested
* without concern
* One use is to change the returned value for a positive match
* so a css class prints for an element representing the current page:
* echo $nav->currentPage('/script.php?op=info', ' class="current"', '', true);
* The above will match only if the current page (REQUEST_URI) is also '/script.php?op=info',
* and will return the string ' class="current"' if it is.
*
* @access public
*
* @param mixed $test_uri A URI, or an array of URIs, to test against the current page.
* @param mixed $true_return The value to return if the current page matches the test URI.
* @param mixed $false_return The value to return if the current page does not match the test URI.
* @param bool $include_query If set true, include the URI query string in the test.
*
* @return mixed If the test URI matches the current page URI, the value given for $true_return
* is returned (true by default), otherwise the value given for $false_return is
* returned (false by default).
*/
public function currentPage($test_uri, $true_return=true, $false_return=false, $include_query=false)
{
$app =& App::getInstance();
// If given an array, test each URI recursively returning TRUE on a first match, or FALSE if none match.
if (is_array($test_uri)) {
foreach ($test_uri as $uri) {
if ($this->currentPage($uri, $true_return, $false_return, $include_query)) {
return true;
}
}
return false;
}
if (empty($test_uri)) {
return $false_return;
}
$actual_uri = $include_query ? $_SERVER['REQUEST_URI'] : (strstr(getenv('REQUEST_URI'), '?', true) ?: getenv('REQUEST_URI')); // strstr() returns false if '?' is not found, so use a shorthand ternary operator.
$test_uri = $include_query ? $test_uri : (strstr($test_uri, '?', true) ?: $test_uri); // strstr() returns false if '?' is not found, so use a shorthand ternary operator.
if (mb_strtolower($test_uri) == mb_strtolower($actual_uri)) {
// $app->logMsg(sprintf('Current page (%s) == test URI (%s)', $actual_uri, $test_uri), LOG_DEBUG, __FILE__, __LINE__);
return $true_return;
}
// $app->logMsg(sprintf('Current page (%s) != test URI (%s)', $actual_uri, $test_uri), LOG_DEBUG, __FILE__, __LINE__);
return $false_return;
}
}
// End of class.