Browse Source

Merge pull request #4220 from cakephp/3.0-router-url

3.0 router url
Mark Story 11 years ago
parent
commit
8e101dff07
2 changed files with 70 additions and 68 deletions
  1. 44 60
      src/Routing/Router.php
  2. 26 8
      tests/TestCase/Routing/RouterTest.php

+ 44 - 60
src/Routing/Router.php

@@ -468,10 +468,10 @@ class Router {
  *
  * - `Router::url('/posts/edit/1');` Returns the string with the base dir prepended.
  *   This usage does not use reverser routing.
- * - `Router::url(array('controller' => 'posts', 'action' => 'edit'));` Returns a URL
+ * - `Router::url(['controller' => 'posts', 'action' => 'edit']);` Returns a URL
  *   generated through reverse routing.
- * - `Router::url('custom-name', array(...));` Returns a URL generated through reverse
- *   routing.  This form allows you to leverage named routes.
+ * - `Router::url(['_name' => 'custom-name', ...]);` Returns a URL generated
+ *   through reverse routing. This form allows you to leverage named routes.
  *
  * There are a few 'special' parameters that can change the final URL string that is generated
  *
@@ -485,43 +485,23 @@ class Router {
  * - `_full` - If true output of `Router::fullBaseUrl()` will be prepended to generated URLs.
  * - `#` - Allows you to set URL hash fragments.
  * - `_ssl` - Set to true to convert the generated URL to https, or false to force http.
- *
- * @param string|array $url Cake-relative URL, like "/products/edit/92" or "/presidents/elect/4"
- *   or an array specifying any of the following: 'controller', 'action', 'plugin'
- *   additionally, you can provide routed elements or query string parameters.
- * @param bool|array $options If (bool) true, the full base URL will be prepended to the result.
- *   If an array accepts the following keys.  If used with a named route you can provide
- *   a list of query string parameters.
+ * - `_name` - Name of route. If you have setup named routes you can use this key
+ *   to specify it.
+ *
+ * @param string|array $url An array specifying any of the following:
+ *   'controller', 'action', 'plugin' additionally, you can provide routed
+ *   elements or query string parameters. If string it can be name any valid url
+ *   string.
+ * @param bool $full If true, the full base URL will be prepended to the result.
+ *   Default is false.
  * @return string Full translated URL with base path.
  * @throws \Cake\Error\Exception When the route name is not found
  */
-	public static function url($url = null, $options = []) {
+	public static function url($url = null, $full = false) {
 		if (!static::$initialized) {
 			static::_loadRoutes();
 		}
 
-		$full = false;
-		if (is_bool($options)) {
-			list($full, $options) = array($options, []);
-		}
-		$urlType = gettype($url);
-		$hasLeadingSlash = $plainString = false;
-
-		if ($urlType === 'string') {
-			$plainString = (
-				strpos($url, 'javascript:') === 0 ||
-				strpos($url, 'mailto:') === 0 ||
-				strpos($url, 'tel:') === 0 ||
-				strpos($url, 'sms:') === 0 ||
-				strpos($url, '#') === 0 ||
-				strpos($url, '?') === 0 ||
-				strpos($url, '//') === 0 ||
-				strpos($url, '://') !== false
-			);
-
-			$hasLeadingSlash = isset($url[0]) ? $url[0] === '/' : false;
-		}
-
 		$params = array(
 			'plugin' => null,
 			'controller' => null,
@@ -546,7 +526,7 @@ class Router {
 				$output = static::fullBaseUrl() . $base . $output;
 			}
 			return $output;
-		} elseif ($urlType === 'array') {
+		} elseif (is_array($url)) {
 			if (isset($url['_full']) && $url['_full'] === true) {
 				$full = true;
 				unset($url['_full']);
@@ -566,38 +546,42 @@ class Router {
 				unset($url['_ssl']);
 			}
 
-			// Copy the current action if the controller is the current one.
-			if (
-				empty($url['action']) &&
-				(empty($url['controller']) || $params['controller'] === $url['controller'])
-			) {
-				$url['action'] = $params['action'];
-			}
+			if (!isset($url['_name'])) {
+				// Copy the current action if the controller is the current one.
+				if (
+					empty($url['action']) &&
+					(empty($url['controller']) || $params['controller'] === $url['controller'])
+				) {
+					$url['action'] = $params['action'];
+				}
+
+				// Keep the current prefix around if none set.
+				if (isset($params['prefix']) && !isset($url['prefix'])) {
+					$url['prefix'] = $params['prefix'];
+				}
 
-			// Keep the current prefix around if none set.
-			if (isset($params['prefix']) && !isset($url['prefix'])) {
-				$url['prefix'] = $params['prefix'];
+				$url += array(
+					'plugin' => $params['plugin'],
+					'controller' => $params['controller'],
+					'action' => 'index',
+					'_ext' => $params['_ext']
+				);
 			}
 
-			$url += array(
-				'plugin' => $params['plugin'],
-				'controller' => $params['controller'],
-				'action' => 'index',
-				'_ext' => $params['_ext']
-			);
-			$url = static::_applyUrlFilters($url);
-			$output = static::$_collection->match($url, static::$_requestContext);
-		} elseif (
-			$urlType === 'string' &&
-			!$hasLeadingSlash &&
-			!$plainString
-		) {
-			// named route.
-			$url = $options + ['_name' => $url];
 			$url = static::_applyUrlFilters($url);
 			$output = static::$_collection->match($url, static::$_requestContext);
 		} else {
-			// String urls.
+			$plainString = (
+				strpos($url, 'javascript:') === 0 ||
+				strpos($url, 'mailto:') === 0 ||
+				strpos($url, 'tel:') === 0 ||
+				strpos($url, 'sms:') === 0 ||
+				strpos($url, '#') === 0 ||
+				strpos($url, '?') === 0 ||
+				strpos($url, '//') === 0 ||
+				strpos($url, '://') !== false
+			);
+
 			if ($plainString) {
 				return $url;
 			}

+ 26 - 8
tests/TestCase/Routing/RouterTest.php

@@ -1050,14 +1050,32 @@ class RouterTest extends TestCase {
 			array('controller' => 'users', 'action' => 'view'),
 			array('_name' => 'test')
 		);
-		$url = Router::url('test', array('name' => 'mark'));
+		Router::connect(
+			'/view/*',
+			['action' => 'view'],
+			['_name' => 'Articles::view']
+		);
+
+		$url = Router::url(['_name' => 'test', 'name' => 'mark']);
 		$this->assertEquals('/users/mark', $url);
 
-		$url = Router::url('test', array('name' => 'mark', 'page' => 1, 'sort' => 'title', 'dir' => 'desc'));
+		$url = Router::url([
+			'_name' => 'test', 'name' => 'mark',
+			'page' => 1, 'sort' => 'title', 'dir' => 'desc'
+		]);
 		$this->assertEquals('/users/mark?page=1&sort=title&dir=desc', $url);
 
-		$url = Router::url('users-index');
-		$this->assertEquals('/users', $url);
+		$url = Router::url(['_name' => 'Articles::view']);
+		$this->assertEquals('/view/', $url);
+
+		$url = Router::url(['_name' => 'Articles::view', '1']);
+		$this->assertEquals('/view/1', $url);
+
+		$url = Router::url(['_name' => 'Articles::view', '_full' => true, '1']);
+		$this->assertEquals('http://localhost/view/1', $url);
+
+		$url = Router::url(['_name' => 'Articles::view', '1', '#' => 'frag']);
+		$this->assertEquals('/view/1#frag', $url);
 	}
 
 /**
@@ -1072,7 +1090,7 @@ class RouterTest extends TestCase {
 			array('controller' => 'users', 'action' => 'view'),
 			array('_name' => 'test')
 		);
-		$url = Router::url('junk', array('name' => 'mark'));
+		$url = Router::url(['_name' => 'junk', 'name' => 'mark']);
 	}
 
 /**
@@ -1695,9 +1713,9 @@ class RouterTest extends TestCase {
  */
 	public function testGenerationWithSslOption() {
 		Router::connect('/:controller/:action/*');
-		$_SERVER['HTTP_HOST'] = 'localhost';
 
 		$request = new Request();
+		$request->env('HTTP_HOST', 'localhost');
 		Router::pushRequest(
 			$request->addParams(array(
 				'plugin' => null, 'controller' => 'images', 'action' => 'index'
@@ -1726,10 +1744,10 @@ class RouterTest extends TestCase {
  */
 	public function testGenerateWithSslInSsl() {
 		Router::connect('/:controller/:action/*');
-		$_SERVER['HTTP_HOST'] = 'localhost';
-		$_SERVER['HTTPS'] = 'on';
 
 		$request = new Request();
+		$request->env('HTTP_HOST', 'localhost');
+		$request->env('HTTPS', 'on');
 		Router::pushRequest(
 			$request->addParams(array(
 				'plugin' => null,