Blame view

components/com_jmap/router.php 9.07 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
<?php
// namespace components\com_jmap;
/**
 *
 * @package JMAP::components::com_jmap
 * @author Joomla! Extensions Store
 * @copyright (C) 2015 - Joomla! Extensions Store
 * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html
 */
defined ( '_JEXEC' ) or die ( 'Restricted access' );

/**
 * Polyfill abstract class for class based router on Joomla 3.3-
 *
 * @package JMAP::components::com_jmap
 * @since 2.3
 */
if (! class_exists ( 'JComponentRouterBase' )) {
	abstract class JComponentRouterBase {
		abstract public function build(&$query);
		abstract public function parse(&$segments);
	}
}

/**
 * Routing class from com_jmap
 *
 * @package JMAP::components::com_jmap
 * @since 2.3
 */
class JMapRouter extends JComponentRouterBase {
	/**
	 * Sitemap Joomla router, embeds little helper route
	 *
	 * @package JMAP::components::com_jmap
	 */
	function build(&$query) {
		$config = JFactory::getConfig ();
		static $appSuffix;
		if ($appSuffix) {
			$config->set ( 'sef_suffix', $appSuffix );
		}
		$componentParams = JComponentHelper::getParams ( 'com_jmap' );
		
		// Segments that will be translated and built for this URL, subtracted from $query that will be untranslated and not built
		$segments = array ();
		
		$app = JFactory::getApplication ();
		// Get all site menus
		$menus = $app->getMenu ( 'site' );
		
		// Mapping fallback for generic task name = view name if view is not used. View concept is only used wrong way by Joomla menus
		if (! isset ( $query ['view'] ) && isset ( $query ['task'] )) {
			if (strpos ( $query ['task'], '.' )) {
				list ( $controller_name, $controller_task ) = explode ( '.', $query ['task'] );
			}
			$mappedView = $controller_name;
		}
		
		// Helper Route here for existing menu item pointing to this $query, so try finding Itemid before all
		if (empty ( $query ['Itemid'] ) && $app->getClientId () != 1) {
			$component = JComponentHelper::getComponent ( 'com_jmap' );
			$menuItems = $menus->getItems ( 'component_id', $component->id );
			if (! empty ( $menuItems )) {
				// Route helper priority 1: view + dataset
				if (isset ( $query ['dataset'] )) {
					foreach ( $menuItems as $menuItem ) {
						if (isset ( $menuItem->query ) && isset ( $menuItem->query ['dataset'] )) {
							if ($menuItem->query ['dataset'] == $query ['dataset']) {
								// Found a link exact match to sitemap view default html format within a site menu, use the Itemid for alias: component/com_jmap=>alias
								$query ['Itemid'] = $menuItem->id;
								break;
							}
						}
					}
				}
				
				// Route helper priority 2: view only
				if (empty ( $query ['Itemid'] )) {
					foreach ( $menuItems as $menuItem ) {
						if (isset ( $menuItem->query ['dataset'] ) && is_numeric ( $menuItem->query ['dataset'] )) {
							continue;
						}
						if (isset ( $menuItem->query ) && isset ( $menuItem->query ['view'] )) {
							if (isset ( $query ['view'] ) && $menuItem->query ['view'] == $query ['view']) {
								// Found a link exact match to sitemap view default html format within a site menu, use the Itemid for alias: component/com_jmap=>alias
								$query ['Itemid'] = $menuItem->id;
								break;
							}
							
							if (isset ( $mappedView ) && $menuItem->query ['view'] == $mappedView) {
								// Found a link exact match to sitemap view default html format within a site menu, use the Itemid for alias: component/com_jmap=>alias
								$query ['Itemid'] = $menuItem->id;
								break;
							}
						}
					}
				}
			}
		}
		
		// Lookup for an menu itemid in $query, should be helped by route helper if any, for mod_menu links there is always $query = http://domain.com/?Itemid=123, and all is desetted by default
		if (empty ( $query ['Itemid'] )) {
			$menuItem = $menus->getActive ();
		} else {
			$menuItem = $menus->getItem ( $query ['Itemid'] );
		}
		// Store query info for menu, for example view name, for the menu selected fom Itemid or current as fallback
		$mView = (empty ( $menuItem->query ['view'] )) ? null : $menuItem->query ['view'];
		$mFormat = (empty ( $menuItem->query ['format'] )) ? 'html' : $menuItem->query ['format'];
		$mDataset = (empty ( $menuItem->query ['dataset'] )) ? null : $menuItem->query ['dataset'];
		// If this is a link to HTML sitemap format view assigned already to a menu, ensure to unset all by default to leave only menu alias
		if (isset ( $query ['view'] ) && ($mView == $query ['view']) && (! isset ( $query ['format'] ) || $mFormat == $query ['format']) && (! isset ( $query ['dataset'] ) || $mDataset == $query ['dataset'])) {
			unset ( $query ['view'] );
			unset ( $query ['format'] );
			unset ( $query ['dataset'] );
			// Return empty segments ONLY if link has a view specified that match a menu item. Controller.task is always left as a segment because could have specific behavior
			return $segments;
		}
		
		// Start desetting $query chunks assigning to segments
		// UNSET VIEW
		if (isset ( $query ['view'] )) {
			// Store view info for $query link
			$view = $query ['view'];
			// Assign and unset
			$segments [] = $query ['view'];
			unset ( $query ['view'] );
		}
		
		// UNSET TASK
		if (isset ( $query ['task'] )) {
			// Assign and unset
			$segments [] = str_replace ( '.', '-', $query ['task'] );
			unset ( $query ['task'] );
		}
		
		// UNSET FORMAT
		if (isset ( $query ['format'] )) {
			// Assign and unset
			$segments [] = $query ['format'];
			unset ( $query ['format'] );
			
			// Manage XML/NOT HTML JDocument format if detected
			$appSuffix = $config->get ( 'sef_suffix' );
			$config->set ( 'sef_suffix', false );
			
			// Manage suffix for backend routing executing site application
			if ($app->getClientId () == 1 && $componentParams->get ( 'sitemap_links_sef', false )) {
				$siteApplication = JApplicationCms::getInstance ( 'site' );
				if (method_exists ( $siteApplication, 'set' )) {
					$siteApplication->set ( 'sef_suffix', false );
				}
			}
		}
		
		// UNSET XSLT
		$foundXslt = false;
		if (isset ( $query ['xslt'] )) {
			// Assign and unset
			$segments [] = $query ['xslt'] . '-formatted';
			unset ( $query ['xslt'] );
			$foundXslt = true;
		}
		
		// UNSET DATASET
		if (isset ( $query ['dataset'] )) {
			// Assign and unset
			if (! $foundXslt) {
				$segments [] = '0-formatted';
			}
			$segments [] = $query ['dataset'] . '-dataset';
			unset ( $query ['dataset'] );
		}
		
		// Finally return processed segments
		return $segments;
	}
	
	/**
	 * Parse the segments of a URL with following shapes:
	 *
	 * http://mydomain/component/jmap/view-task
	 *
	 * http://mydomain/component/jmap/viewname -> http://mydomain/component/jmap/viewname.display
	 * http://mydomain/component/jmap/controller-task
	 *
	 * component/jmap/ has to be handled through route helper for menu Itemid
	 * By convention view based Joomla components are overwritten by mapping viewname = taskname.display ex. view=sitemap is mapped to task=sitemap.display
	 * Even the task is considered and built/parsed fully as a dashed - entity like an article, a generic entity, etc: sitemap-display, sitemap-export AKA 1-myarticle
	 *
	 * @param
	 *        	array	The segments of the URL to parse.
	 * @return array URL attributes to be used by the application.
	 */
	function parse(&$segments) {
		$vars = array ();
		$count = count ( $segments );
		$app = JFactory::getApplication ();
		$componentParams = JComponentHelper::getParams ( 'com_jmap' );
		
		if ($count) {
			$count --;
			// VIEW-TASK is always 1 segment
			$segment = array_shift ( $segments );
			
			// Found a view/task
			if (version_compare ( JVERSION, '3.3', '>=' )) { // Fixed the semicolon/dash router issue?
				if (strpos ( $segment, '-' )) {
					$vars ['task'] = str_replace ( '-', '.', $segment );
				} else {
					$vars ['view'] = $segment;
				}
			} else { // Fallback on the compat mode 1:item
				if (strpos ( $segment, ':' )) {
					$vars ['task'] = str_replace ( ':', '.', $segment );
				} else {
					$vars ['view'] = $segment;
				}
			}
		}
		
		if ($count) {
			$count --;
			// FORMAT is always 2 segment
			$segment = array_shift ( $segments );
			if ($segment) {
				$vars ['format'] = $segment;
			}
		}
		
		if ($count) {
			$count --;
			// XSLT stylesheet is always 3 segment
			$segment = array_shift ( $segments );
			if (is_numeric ( ( int ) $segment )) {
				$vars ['xslt'] = ( int ) $segment;
			}
		}
		
		if ($count) {
			$count --;
			// Dataset is always 4 segment
			$segment = array_shift ( $segments );
			if (is_numeric ( ( int ) $segment )) {
				$vars ['dataset'] = ( int ) $segment;
			}
		}
		
		// Evaluate a forcing Itemid into vars and JMenu setter, link with no alias substitution, partially SEF from backend
		if (($ItemidByLink = $app->input->get ( 'Itemid', null )) && $componentParams->get ( 'sitemap_links_sef', false )) {
			$vars ['Itemid'] = $ItemidByLink;
			$menu = $app->getMenu ();
			$menu->setActive ( $vars ['Itemid'] );
		}
		
		return $vars;
	}
}

/**
 * JSitemap router functions
 *
 * These functions are proxys for the new router interface
 * for old SEF extensions.
 */
function JMapBuildRoute(&$query) {
	$router = new JMapRouter ();
	
	return $router->build ( $query );
}
function JMapParseRoute($segments) {
	$router = new JMapRouter ();
	
	return $router->parse ( $segments );
}