diff --git a/.travis.yml b/.travis.yml index 4251d8a1..0db16cb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,7 @@ language: php matrix: include: - - php: 5.3 - env: COMPOSER_FLAGS="--prefer-lowest" SYMFONY_DEPRECATIONS_HELPER=weak - dist: precise + - php: 5.6 - php: 7.1 - php: 7.2 - php: 7.1 diff --git a/Command/DumpCommand.php b/Command/DumpCommand.php index 88929bba..40fdfd42 100644 --- a/Command/DumpCommand.php +++ b/Command/DumpCommand.php @@ -167,6 +167,7 @@ private function doDump(InputInterface $input, OutputInterface $output) $extractor->getRoutes(), $extractor->getPrefix($input->getOption('locale')), $extractor->getHost(), + $extractor->getPort(), $extractor->getScheme() ), 'json', diff --git a/Controller/Controller.php b/Controller/Controller.php index d760ce9b..7e4124be 100644 --- a/Controller/Controller.php +++ b/Controller/Controller.php @@ -96,6 +96,7 @@ public function indexAction(Request $request, $_format) $exposedRoutes, $this->exposedRoutesExtractor->getPrefix($request->getLocale()), $this->exposedRoutesExtractor->getHost(), + $this->exposedRoutesExtractor->getPort(), $this->exposedRoutesExtractor->getScheme(), $request->getLocale() ); diff --git a/Extractor/ExposedRoutesExtractor.php b/Extractor/ExposedRoutesExtractor.php index 15933617..7e26924f 100644 --- a/Extractor/ExposedRoutesExtractor.php +++ b/Extractor/ExposedRoutesExtractor.php @@ -104,14 +104,26 @@ public function getHost() { $requestContext = $this->router->getContext(); - $host = $requestContext->getHost(); + $host = $requestContext->getHost() . + ('' === $this->getPort() ? $this->getPort() : ':' . $this->getPort()); + return $host; + } + + /** + * {@inheritDoc} + */ + public function getPort() + { + $requestContext = $this->router->getContext(); + + $port=""; if ($this->usesNonStandardPort()) { $method = sprintf('get%sPort', ucfirst($requestContext->getScheme())); - $host .= ':' . $requestContext->$method(); + $port = $requestContext->$method(); } - return $host; + return $port; } /** diff --git a/Extractor/ExposedRoutesExtractorInterface.php b/Extractor/ExposedRoutesExtractorInterface.php index 2db32f63..cb09bf2a 100644 --- a/Extractor/ExposedRoutesExtractorInterface.php +++ b/Extractor/ExposedRoutesExtractorInterface.php @@ -49,6 +49,13 @@ public function getPrefix($locale); */ public function getHost(); + /** + * Get the port from RequestContext, only if non standard port (Eg: "8080") + * + * @return string + */ + public function getPort(); + /** * Get the scheme from RequestContext * diff --git a/Resources/js/router.js b/Resources/js/router.js index aa3e30b2..388b6f0d 100644 --- a/Resources/js/router.js +++ b/Resources/js/router.js @@ -19,7 +19,7 @@ class Router { * @param {Object.=} routes */ constructor(context, routes) { - this.context_ = context || {base_url: '', prefix: '', host: '', scheme: ''}; + this.context_ = context || {base_url: '', prefix: '', host: '', port: '', scheme: ''}; this.setRoutes(routes || {}); } @@ -52,6 +52,9 @@ class Router { if ('prefix' in data) { this.setPrefix(data['prefix']); } + if ('port' in data) { + this.setPort(data['port']); + } this.setHost(data['host']); this.setScheme(data['scheme']); @@ -120,6 +123,20 @@ class Router { return this.context_.host; } + /** + * @param {string} port + */ + setPort(port) { + this.context_.port = port; + } + + /** + * @return {string} + */ + getPort() { + return this.context_.port; + }; + /** * Builds query string params added to a URL. * Port of jQuery's $.param() function, so credit is due there. @@ -184,7 +201,8 @@ class Router { unusedParams = Object.assign({}, params), url = '', optional = true, - host = ''; + host = '', + port = (typeof this.getPort() == "undefined" || this.getPort() === null) ? '' : this.getPort(); route.tokens.forEach((token) => { if ('text' === token[0]) { @@ -263,8 +281,8 @@ class Router { url = route.requirements["_scheme"] + "://" + (host || this.getHost()) + url; } else if ("undefined" !== typeof route.schemes && "undefined" !== typeof route.schemes[0] && this.getScheme() !== route.schemes[0]) { url = route.schemes[0] + "://" + (host || this.getHost()) + url; - } else if (host && this.getHost() !== host) { - url = this.getScheme() + "://" + host + url; + } else if (host && this.getHost() !== host + ('' === port ? '' : ':' + port)) { + url = this.getScheme() + "://" + host + ('' === port ? '' : ':' + port) + url; } else if (absolute === true) { url = this.getScheme() + "://" + this.getHost() + url; } diff --git a/Resources/js/router.test.js b/Resources/js/router.test.js index 611b09b7..f4a25ae2 100644 --- a/Resources/js/router.test.js +++ b/Resources/js/router.test.js @@ -406,3 +406,19 @@ function testGenerateWithNullValue() { assertEquals('/blog-post//10', router.generate('posts', { page: null, id: 10 })); } + +function testGenerateWithPort() { + var router = new fos.Router({base_url: '/foo', host: "localhost", scheme: "http", port: 443}, { + homepage: { + tokens: [['text', '/bar']], + defaults: {subdomain: 'api'}, + requirements: {}, + hosttokens: [ + ['text', '.localhost'], + ['variable', '', '', 'subdomain'] + ] + } + }); + + assertEquals('http://api.localhost:443/foo/bar', router.generate('homepage')); +} diff --git a/Resources/public/js/router.js b/Resources/public/js/router.js index 91ef8a6f..5cd2efa5 100644 --- a/Resources/public/js/router.js +++ b/Resources/public/js/router.js @@ -48,7 +48,7 @@ var Router = function () { function Router(context, routes) { _classCallCheck(this, Router); - this.context_ = context || { base_url: '', prefix: '', host: '', scheme: '' }; + this.context_ = context || { base_url: '', prefix: '', host: '', port: '', scheme: '' }; this.setRoutes(routes || {}); } @@ -73,6 +73,9 @@ var Router = function () { if ('prefix' in data) { this.setPrefix(data['prefix']); } + if ('port' in data) { + this.setPort(data['port']); + } this.setHost(data['host']); this.setScheme(data['scheme']); @@ -168,6 +171,29 @@ var Router = function () { return this.context_.host; } + /** + * @param {string} port + */ + + }, { + key: 'setPort', + value: function setPort(port) { + this.context_.port = port; + } + + /** + * @return {string} + */ + + }, { + key: 'getPort', + value: function getPort() { + return this.context_.port; + } + }, { + key: 'buildQueryParams', + + /** * Builds query string params added to a URL. * Port of jQuery's $.param() function, so credit is due there. @@ -176,9 +202,6 @@ var Router = function () { * @param {Array|Object|string} params * @param {Function} add */ - - }, { - key: 'buildQueryParams', value: function buildQueryParams(prefix, params, add) { var _this = this; @@ -245,7 +268,8 @@ var Router = function () { unusedParams = _extends({}, params), url = '', optional = true, - host = ''; + host = '', + port = typeof this.getPort() == "undefined" || this.getPort() === null ? '' : this.getPort(); route.tokens.forEach(function (token) { if ('text' === token[0]) { @@ -324,8 +348,8 @@ var Router = function () { url = route.requirements["_scheme"] + "://" + (host || this.getHost()) + url; } else if ("undefined" !== typeof route.schemes && "undefined" !== typeof route.schemes[0] && this.getScheme() !== route.schemes[0]) { url = route.schemes[0] + "://" + (host || this.getHost()) + url; - } else if (host && this.getHost() !== host) { - url = this.getScheme() + "://" + host + url; + } else if (host && this.getHost() !== host + ('' === port ? '' : ':' + port)) { + url = this.getScheme() + "://" + host + ('' === port ? '' : ':' + port) + url; } else if (absolute === true) { url = this.getScheme() + "://" + this.getHost() + url; } diff --git a/Resources/public/js/router.min.js b/Resources/public/js/router.min.js index 4ce4802f..6b8c4d58 100644 --- a/Resources/public/js/router.min.js +++ b/Resources/public/js/router.min.js @@ -1 +1 @@ -!function(e,t){var n=t();"function"==typeof define&&define.amd?define([],n.Routing):"object"==typeof module&&module.exports?module.exports=n.Routing:(e.Routing=n.Routing,e.fos={Router:n.Router})}(this,function(){"use strict";function e(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var t=Object.assign||function(e){for(var t=1;t2&&void 0!==arguments[2]&&arguments[2],i=this.getRoute(e),r=n||{},s=t({},r),u="",f=!0,a="";if(i.tokens.forEach(function(t){if("text"===t[0])return u=t[1]+u,void(f=!1);{if("variable"!==t[0])throw new Error('The token type "'+t[0]+'" is not supported.');var n=i.defaults&&t[3]in i.defaults;if(!1===f||!n||t[3]in r&&r[t[3]]!=i.defaults[t[3]]){var o=void 0;if(t[3]in r)o=r[t[3]],delete s[t[3]];else{if(!n){if(f)return;throw new Error('The route "'+e+'" requires the parameter "'+t[3]+'".')}o=i.defaults[t[3]]}var a=!0===o||!1===o||""===o;if(!a||!f){var c=encodeURIComponent(o).replace(/%2F/g,"/");"null"===c&&null===o&&(c=""),u=t[1]+c+u}f=!1}else n&&t[3]in s&&delete s[t[3]]}}),""===u&&(u="/"),i.hosttokens.forEach(function(e){var t=void 0;return"text"===e[0]?void(a=e[1]+a):void("variable"===e[0]&&(e[3]in r?(t=r[e[3]],delete s[e[3]]):i.defaults&&e[3]in i.defaults&&(t=i.defaults[e[3]]),a=e[1]+t+a))}),u=this.context_.base_url+u,i.requirements&&"_scheme"in i.requirements&&this.getScheme()!=i.requirements._scheme?u=i.requirements._scheme+"://"+(a||this.getHost())+u:"undefined"!=typeof i.schemes&&"undefined"!=typeof i.schemes[0]&&this.getScheme()!==i.schemes[0]?u=i.schemes[0]+"://"+(a||this.getHost())+u:a&&this.getHost()!==a?u=this.getScheme()+"://"+a+u:o===!0&&(u=this.getScheme()+"://"+this.getHost()+u),Object.keys(s).length>0){var c=void 0,l=[],h=function(e,t){t="function"==typeof t?t():t,t=null===t?"":t,l.push(encodeURIComponent(e)+"="+encodeURIComponent(t))};for(c in s)this.buildQueryParams(c,s[c],h);u=u+"?"+l.join("&").replace(/%20/g,"+")}return u}}],[{key:"getInstance",value:function(){return r}},{key:"setData",value:function(e){var t=i.getInstance();t.setRoutingData(e)}}]),i}();i.Route,i.Context;var r=new i;return{Router:i,Routing:r}}); \ No newline at end of file +!function(e,t){var n=t();"function"==typeof define&&define.amd?define([],n.Routing):"object"==typeof module&&module.exports?module.exports=n.Routing:(e.Routing=n.Routing,e.fos={Router:n.Router})}(this,function(){"use strict";function e(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var t=Object.assign||function(e){for(var t=1;t2&&void 0!==arguments[2]&&arguments[2],r=this.getRoute(e),i=n||{},s=t({},i),u="",f=!0,a="",c="undefined"==typeof this.getPort()||null===this.getPort()?"":this.getPort();if(r.tokens.forEach(function(t){if("text"===t[0])return u=t[1]+u,void(f=!1);{if("variable"!==t[0])throw new Error('The token type "'+t[0]+'" is not supported.');var n=r.defaults&&t[3]in r.defaults;if(!1===f||!n||t[3]in i&&i[t[3]]!=r.defaults[t[3]]){var o=void 0;if(t[3]in i)o=i[t[3]],delete s[t[3]];else{if(!n){if(f)return;throw new Error('The route "'+e+'" requires the parameter "'+t[3]+'".')}o=r.defaults[t[3]]}var a=!0===o||!1===o||""===o;if(!a||!f){var c=encodeURIComponent(o).replace(/%2F/g,"/");"null"===c&&null===o&&(c=""),u=t[1]+c+u}f=!1}else n&&t[3]in s&&delete s[t[3]]}}),""===u&&(u="/"),r.hosttokens.forEach(function(e){var t=void 0;return"text"===e[0]?void(a=e[1]+a):void("variable"===e[0]&&(e[3]in i?(t=i[e[3]],delete s[e[3]]):r.defaults&&e[3]in r.defaults&&(t=r.defaults[e[3]]),a=e[1]+t+a))}),u=this.context_.base_url+u,r.requirements&&"_scheme"in r.requirements&&this.getScheme()!=r.requirements._scheme?u=r.requirements._scheme+"://"+(a||this.getHost())+u:"undefined"!=typeof r.schemes&&"undefined"!=typeof r.schemes[0]&&this.getScheme()!==r.schemes[0]?u=r.schemes[0]+"://"+(a||this.getHost())+u:a&&this.getHost()!==a+(""===c?"":":"+c)?u=this.getScheme()+"://"+a+(""===c?"":":"+c)+u:o===!0&&(u=this.getScheme()+"://"+this.getHost()+u),Object.keys(s).length>0){var h=void 0,l=[],y=function(e,t){t="function"==typeof t?t():t,t=null===t?"":t,l.push(encodeURIComponent(e)+"="+encodeURIComponent(t))};for(h in s)this.buildQueryParams(h,s[h],y);u=u+"?"+l.join("&").replace(/%20/g,"+")}return u}}],[{key:"getInstance",value:function(){return i}},{key:"setData",value:function(e){var t=r.getInstance();t.setRoutingData(e)}}]),r}();r.Route,r.Context;var i=new r;return{Router:r,Routing:i}}); \ No newline at end of file diff --git a/Response/RoutesResponse.php b/Response/RoutesResponse.php index 14116e3e..538be722 100644 --- a/Response/RoutesResponse.php +++ b/Response/RoutesResponse.php @@ -19,15 +19,17 @@ class RoutesResponse private $routes; private $prefix; private $host; + private $port; private $scheme; private $locale; - public function __construct($baseUrl, RouteCollection $routes = null, $prefix = null, $host = null, $scheme = null, $locale = null) + public function __construct($baseUrl, RouteCollection $routes = null, $prefix = null, $host = null, $port = null, $scheme = null, $locale = null) { $this->baseUrl = $baseUrl; $this->routes = $routes ?: new RouteCollection(); $this->prefix = $prefix; $this->host = $host; + $this->port = $port; $this->scheme = $scheme; $this->locale = $locale; } @@ -74,6 +76,11 @@ public function getHost() return $this->host; } + public function getPort() + { + return $this->port; + } + public function getScheme() { return $this->scheme; diff --git a/Serializer/Normalizer/RoutesResponseNormalizer.php b/Serializer/Normalizer/RoutesResponseNormalizer.php index ca659d19..74281903 100644 --- a/Serializer/Normalizer/RoutesResponseNormalizer.php +++ b/Serializer/Normalizer/RoutesResponseNormalizer.php @@ -29,6 +29,7 @@ public function normalize($data, $format = null, array $context = array()) 'routes' => $data->getRoutes(), 'prefix' => $data->getPrefix(), 'host' => $data->getHost(), + 'port' => $data->getPort(), 'scheme' => $data->getScheme(), ); } diff --git a/Tests/Controller/ControllerTest.php b/Tests/Controller/ControllerTest.php index 6d4a2500..10181c4e 100644 --- a/Tests/Controller/ControllerTest.php +++ b/Tests/Controller/ControllerTest.php @@ -49,7 +49,7 @@ public function testIndexAction() $response = $controller->indexAction($this->getRequest('/'), 'json'); - $this->assertEquals('{"base_url":"","routes":{"literal":{"tokens":[["text","\/homepage"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"blog":{"tokens":[["variable","\/","[^\/]++","slug"],["text","\/blog-post"]],"defaults":[],"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]}},"prefix":"","host":"","scheme":""}', $response->getContent()); + $this->assertEquals('{"base_url":"","routes":{"literal":{"tokens":[["text","\/homepage"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"blog":{"tokens":[["variable","\/","[^\/]++","slug"],["text","\/blog-post"]],"defaults":[],"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent()); } public function testIndexActionWithLocalizedRoutes() @@ -65,7 +65,7 @@ public function testIndexActionWithLocalizedRoutes() $response = $controller->indexAction($this->getRequest('/'), 'json'); - $this->assertEquals('{"base_url":"","routes":{"literal":{"tokens":[["text","\/homepage"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"blog":{"tokens":[["variable","\/","[^\/]++","_locale"],["variable","\/","[^\/]++","slug"],["text","\/blog-post"]],"defaults":{"_locale":"en"},"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]}},"prefix":"","host":"","scheme":""}', $response->getContent()); + $this->assertEquals('{"base_url":"","routes":{"literal":{"tokens":[["text","\/homepage"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"blog":{"tokens":[["variable","\/","[^\/]++","_locale"],["variable","\/","[^\/]++","slug"],["text","\/blog-post"]],"defaults":{"_locale":"en"},"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent()); } public function testConfigCache() @@ -79,11 +79,11 @@ public function testConfigCache() ); $response = $controller->indexAction($this->getRequest('/'), 'json'); - $this->assertEquals('{"base_url":"","routes":{"literal":{"tokens":[["text","\/homepage"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]}},"prefix":"","host":"","scheme":""}', $response->getContent()); + $this->assertEquals('{"base_url":"","routes":{"literal":{"tokens":[["text","\/homepage"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent()); // second call should serve the cached content $response = $controller->indexAction($this->getRequest('/'), 'json'); - $this->assertEquals('{"base_url":"","routes":{"literal":{"tokens":[["text","\/homepage"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]}},"prefix":"","host":"","scheme":""}', $response->getContent()); + $this->assertEquals('{"base_url":"","routes":{"literal":{"tokens":[["text","\/homepage"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent()); } /** @@ -95,7 +95,7 @@ public function testGenerateWithCallback($callback) $response = $controller->indexAction($this->getRequest('/', 'GET', array('callback' => $callback)), 'json'); $this->assertEquals( - sprintf('/**/%s({"base_url":"","routes":[],"prefix":"","host":"","scheme":""});', $callback), + sprintf('/**/%s({"base_url":"","routes":[],"prefix":"","host":"","port":null,"scheme":""});', $callback), $response->getContent() ); } @@ -122,7 +122,7 @@ public function testIndexActionWithoutRoutes() $controller = new Controller($this->getSerializer(), $this->getExtractor(), array(), sys_get_temp_dir()); $response = $controller->indexAction($this->getRequest('/'), 'json'); - $this->assertEquals('{"base_url":"","routes":[],"prefix":"","host":"","scheme":""}', $response->getContent()); + $this->assertEquals('{"base_url":"","routes":[],"prefix":"","host":"","port":null,"scheme":""}', $response->getContent()); $this->assertEquals(200, $response->getStatusCode()); $this->assertEquals('application/json', $response->headers->get('Content-Type')); diff --git a/Tests/Serializer/Normalizer/RoutesResponseNormalizerTest.php b/Tests/Serializer/Normalizer/RoutesResponseNormalizerTest.php index f8ce397b..c7b69914 100644 --- a/Tests/Serializer/Normalizer/RoutesResponseNormalizerTest.php +++ b/Tests/Serializer/Normalizer/RoutesResponseNormalizerTest.php @@ -60,6 +60,7 @@ public function testNormalize() 'routes' => array(), 'prefix' => 'prefix', 'host' => 'host', + 'port' => null, 'scheme' => 'scheme', );