@@ -48,16 +48,29 @@ public function generateFromRequest($locale = null, $parameters = null, $absolut
4848 {
4949 $ urlBuilder = UrlBuilder::make (Request::fullUrl ());
5050 $ locale = $ locale ?: $ this ->detectLocale ($ urlBuilder );
51- $ parameters = $ this ->prepareParameters ($ locale , $ parameters ?: $ this ->getRouteParameters ());
5251
53- if ( $ url = $ this -> generateFromNamedRoute ( $ locale , $ parameters , $ absolute )) {
54- return $ url . $ urlBuilder -> getQueryString ();
55- }
52+ // $parameters can be an array, a function or it can contain model instances!
53+ // Normalize the parameters so we end up with an array of key => value pairs.
54+ $ parameters = $ this -> prepareParameters ( $ locale , $ parameters ?: $ this -> getRouteParameters ());
5655
5756 if ( ! $ this ->is404 ()) {
58- $ urlBuilder ->setPath ($ this ->replaceParameters ($ this ->route ->uri (), $ parameters ));
57+ $ urlBuilder ->setPath ($ this ->route ->uri ());
58+
59+ list ($ slugs , $ query ) = $ this ->extractQueryParameters ($ urlBuilder ->getPath (), $ parameters );
60+
61+ if (count ($ query )) {
62+ $ urlBuilder ->setQuery ($ query );
63+ }
64+
65+ if ($ url = $ this ->generateFromNamedRoute ($ locale , $ parameters , $ absolute )) {
66+ return empty ($ query ) ? $ url . $ urlBuilder ->getQueryString () : $ url ;
67+ }
68+
69+ $ urlBuilder ->setPath ($ this ->replaceParameters ($ this ->route ->uri (), $ slugs ));
5970 }
6071
72+ // If custom domains are not used and it is not a registered,
73+ // non localized route, update the locale slug in the path.
6174 if ( ! $ this ->hasCustomDomains () && ($ this ->is404 () || $ this ->isLocalized ())) {
6275 $ urlBuilder ->setSlugs ($ this ->updateLocaleInSlugs ($ urlBuilder ->getSlugs (), $ locale ));
6376 }
@@ -284,21 +297,54 @@ protected function updateLocaleInSlugs(array $slugs, $locale)
284297 }
285298
286299 /**
287- * Replace parameter placeholders with their value .
300+ * Extract URI parameters and query string parameters .
288301 *
289302 * @param string $uri
290303 * @param array $parameters
291304 *
292- * @return string
305+ * @return array
293306 */
294- protected function replaceParameters ($ uri , $ parameters )
307+ protected function extractQueryParameters ($ uri , $ parameters )
295308 {
296309 preg_match_all ('/{([a-z_.-]+)}/ ' , $ uri , $ matches );
297310 $ paramKeys = $ matches [1 ] ?? [];
298311
299- foreach ($ paramKeys as $ index => $ key ) {
300- $ value = $ parameters [$ key ] ?? $ parameters [$ index ];
301- $ uri = str_replace ("{ {$ key }} " , $ value , $ uri );
312+ $ slugs = [];
313+ $ query = [];
314+ $ i = 0 ;
315+
316+ foreach ($ parameters as $ key => $ value ) {
317+ // Parameters should be in the same order as the placeholders.
318+ // $key can be a name or an index, so grab the matching key name from the URI.
319+ $ paramKey = $ paramKeys [$ i ] ?? null ;
320+
321+ // If there is a matching $paramKey,
322+ // we are dealing with a normal parameter,
323+ // else we are dealing with a query string parameter.
324+ if ($ paramKey ) {
325+ $ slugs ["{ {$ paramKey }} " ] = $ value ;
326+ } else {
327+ $ query [$ key ] = $ value ;
328+ }
329+
330+ $ i ++;
331+ }
332+
333+ return [$ slugs , $ query ];
334+ }
335+
336+ /**
337+ * Replace parameter placeholders with their value.
338+ *
339+ * @param string $uri
340+ * @param array $parameters
341+ *
342+ * @return string
343+ */
344+ protected function replaceParameters ($ uri , $ parameters )
345+ {
346+ foreach ($ parameters as $ placeholder => $ value ) {
347+ $ uri = str_replace ($ placeholder , $ value , $ uri );
302348 }
303349
304350 return $ uri ;
0 commit comments