normalizeQueryString() public static method

It builds a normalized query string, where keys/value pairs are alphabetized, have consistent escaping and unneeded delimiters are removed.
public static normalizeQueryString ( string $qs ) : string
$qs string Query string
return string A normalized query string for the Request
 /**
  * @param Request $request
  * @param         $view
  *
  * @return string
  */
 private function generateSwitchLink(Request $request, $view)
 {
     $requestSwitchView = $request->duplicate();
     $requestSwitchView->query->set('device_view', $view);
     $requestSwitchView->server->set('QUERY_STRING', Request::normalizeQueryString(http_build_query($requestSwitchView->query->all(), null, '&')));
     return $requestSwitchView->getUri();
 }
 /**
  * Creates a previous page link if avialiable.
  * @param \Symfony\Component\HttpFoundation\Request $request
  * @param int $offset
  * @param int $limit
  * @param int $total
  * @return \Symfony\Component\HttpFoundation\Request mixed
  */
 protected function createNextLink(Request $request, $offset, $limit, $total)
 {
     $nextLink = null;
     $baseUri = $request->getSchemeAndHttpHost() . $request->getBaseUrl() . $request->getPathInfo();
     if ($offset + $limit < $total) {
         parse_str($request->getQueryString(), $qsArray);
         $qsArray['limit'] = $limit;
         $qsArray['offset'] = $limit + $offset;
         $qs = Request::normalizeQueryString(http_build_query($qsArray));
         $nextLink = $baseUri . '?' . $qs;
     }
     return $nextLink;
 }
 /**
  * Regardless of the current view, returns the URL that leads to the equivalent page
  * in the full/desktop view. This is useful for generating <link rel="canonical"> tags
  * on mobile pages for Search Engine Optimization.
  * See: http://searchengineland.com/the-definitive-guide-to-mobile-technical-seo-166066
  * @return string
  */
 public function fullViewUrl()
 {
     if (!isset($this->redirectConf[DeviceView::VIEW_FULL]['host'])) {
         // The host property has not been configured for the full view
         return null;
     }
     $fullHost = $this->redirectConf[DeviceView::VIEW_FULL]['host'];
     if (empty($fullHost)) {
         return null;
     }
     // If not in request scope, we can only return the base URL to the full view
     if (!$this->request) {
         return $fullHost;
     }
     // if fullHost ends with /, skip it since getPathInfo() also starts with /
     $result = rtrim($fullHost, '/') . $this->request->getPathInfo();
     $query = Request::normalizeQueryString(http_build_query($this->request->query->all()));
     if ($query) {
         $result .= '?' . $query;
     }
     return $result;
 }
 /**
  * Get the query string parameters for the current request
  * Not used at present
  *
  * @return null|string
  */
 public function getQueryString()
 {
     $qs = Request::normalizeQueryString($this->request->server->get('QUERY_STRING'));
     return '' === $qs ? null : $qs;
 }
 /**
  * Gets the redirect url.
  *
  * @param string $platform
  *
  * @return string
  */
 protected function getRedirectUrl($platform)
 {
     if ($routingOption = $this->getRoutingOption($platform)) {
         if (self::REDIRECT === $routingOption) {
             // Make sure to hint at the device override, otherwise infinite loop
             // redirections may occur if different device views are hosted on
             // different domains (since the cookie can't be shared across domains)
             $queryParams = $this->container->get('request')->query->all();
             $queryParams[DeviceView::SWITCH_PARAM] = $platform;
             return rtrim($this->redirectConf[$platform]['host'], '/') . $this->container->get('request')->getPathInfo() . '?' . Request::normalizeQueryString(http_build_query($queryParams));
         } elseif (self::REDIRECT_WITHOUT_PATH === $routingOption) {
             // Make sure to hint at the device override, otherwise infinite loop
             // redirections may occur if different device views are hosted on
             // different domains (since the cookie can't be shared across domains)
             return $this->redirectConf[$platform]['host'] . '?' . DeviceView::SWITCH_PARAM . '=' . $platform;
         } else {
             return null;
         }
     } else {
         return null;
     }
 }
 /**
  * Gets the RedirectResponse by switch param.
  *
  * @return \Symfony\Component\HttpFoundation\RedirectResponse
  */
 protected function getRedirectResponseBySwitchParam()
 {
     if ($this->mustRedirect($this->deviceView->getViewType())) {
         // Avoid unnecessary redirects: if we need to redirect to another view,
         // do it in one response while setting the cookie.
         $redirectUrl = $this->getRedirectUrl($this->deviceView->getViewType());
     } else {
         if (true === $this->isFullPath) {
             /* @var $request Request */
             $request = $this->container->get('request');
             $redirectUrl = $request->getUriForPath($request->getPathInfo());
             $queryParams = $request->query->all();
             if (array_key_exists('device_view', $queryParams)) {
                 unset($queryParams['device_view']);
             }
             if (sizeof($queryParams) > 0) {
                 $redirectUrl .= '?' . Request::normalizeQueryString(http_build_query($queryParams));
             }
         } else {
             $redirectUrl = $this->getCurrentHost();
         }
     }
     return $this->deviceView->getRedirectResponseBySwitchParam($redirectUrl);
 }
 /**
  * generic request executor
  *
  * @param   string          $method         GET, POST, PUT, DELETE
  * @param   string          $endpointUrl
  * @param   array           $queryString
  * @param   array|string    $body
  * @param   string          $auth           http-signatures to enable http-signature signing
  * @param   string          $contentMD5Mode body or url
  * @param   float           $timeout        timeout in seconds
  * @return Request
  */
 public function buildRequest($method, $endpointUrl, $queryString = null, $body = null, $auth = null, $contentMD5Mode = null, $timeout = null)
 {
     if (is_null($contentMD5Mode)) {
         $contentMD5Mode = !is_null($body) ? 'body' : 'url';
     }
     $request = new Request($method, $endpointUrl);
     $uri = $request->getUri();
     if ($queryString) {
         foreach ($queryString as $k => $v) {
             $uri = Uri::withQueryValue($uri, $k, $v);
         }
     }
     if (!self::hasQueryValue($uri, 'api_key')) {
         $uri = Uri::withQueryValue($uri, 'api_key', $this->apiKey);
     }
     // normalize the query string the same way the server expects it
     /** @var Request $request */
     $request = $request->withUri($uri->withQuery(\Symfony\Component\HttpFoundation\Request::normalizeQueryString($uri->getQuery())));
     if (!$request->hasHeader('Date')) {
         $request = $request->withHeader('Date', $this->getRFC1123DateString());
     }
     if (!is_null($body)) {
         if (!$request->hasHeader('Content-Type')) {
             $request = $request->withHeader('Content-Type', 'application/json');
         }
         if (!is_string($body)) {
             $body = json_encode($body);
         }
         $request = $request->withBody(\GuzzleHttp\Psr7\stream_for($body));
     }
     // for GET/DELETE requests, MD5 the request URI (excludes domain, includes query strings)
     if ($contentMD5Mode == 'body') {
         $request = $request->withHeader('Content-MD5', md5((string) $body));
     } else {
         $request = $request->withHeader('Content-MD5', md5($request->getRequestTarget()));
     }
     return $request;
 }
 /**
  * generic request executor
  *
  * @param   string          $method         GET, POST, PUT, DELETE
  * @param   string          $endpointUrl
  * @param   array           $queryString
  * @param   array|string    $body
  * @param   string          $auth           http-signatures to enable http-signature signing
  * @param   string          $contentMD5Mode body or url
  * @param   float           $timeout        timeout in seconds
  * @return RequestInterface
  */
 public function buildRequest($method, $endpointUrl, $queryString = null, $body = null, $auth = null, $contentMD5Mode = null, $timeout = null)
 {
     if (is_null($contentMD5Mode)) {
         $contentMD5Mode = !is_null($body) ? 'body' : 'url';
     }
     $request = $this->guzzle->createRequest($method, $endpointUrl);
     if ($queryString) {
         $request->getQuery()->replace($queryString);
     }
     if (!$request->getQuery()->get('api_key')) {
         $request->getQuery()->set('api_key', $this->apiKey);
     }
     // normalize the query string the same way the server expects it
     $request->setQuery(Query::fromString(Request::normalizeQueryString((string) $request->getQuery())));
     if (!$request->hasHeader('Date')) {
         $request->setHeader('Date', $this->getRFC1123DateString());
     }
     if (!is_null($body)) {
         if (!$request->hasHeader('Content-Type')) {
             $request->setHeader('Content-Type', 'application/json');
         }
         if (!is_string($body)) {
             $body = json_encode($body);
         }
         $request->setBody(Stream::factory($body));
     }
     // for GET/DELETE requests, MD5 the request URI (excludes domain, includes query strings)
     if ($contentMD5Mode == 'body') {
         $request->setHeader('Content-MD5', md5((string) $body));
     } else {
         $qs = (string) $request->getQuery();
         $request->setHeader('Content-MD5', md5($request->getPath() . ($qs ? "?{$qs}" : "")));
     }
     if ($auth !== null) {
         $request->getConfig()['auth'] = $auth;
     }
     if ($timeout !== null) {
         $request->getConfig()['timeout'] = $timeout;
     }
     return $request;
 }