Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Passing empty string for route()'s $parameters no longer works #55269

Closed
apih opened this issue Apr 3, 2025 · 4 comments
Closed

Passing empty string for route()'s $parameters no longer works #55269

apih opened this issue Apr 3, 2025 · 4 comments

Comments

@apih
Copy link
Contributor

apih commented Apr 3, 2025

Laravel Version

12.6.0

PHP Version

8.2.28

Database Driver & Version

No response

Description

Previously, passing an empty string to route()'s $parameters worked without problem.

Let's say a route is defined like this:

// Affiliate referral link
Route::get('r/{slug}', Controllers\AffiliateLinkController::class)->name('affiliate_link');

When the route is called like this, it works in the previous version, but fails in the latest version:

// v12.3.0 and below
route('affiliate_link', ''); // Will generate 'https://domain.test/r'

// v12.4.0 and above
route('affiliate_link', ''); // Will fail with error message: Missing required parameter for [Route: affiliate_link] [URI: r/{slug}] [Missing parameter: slug].

Probably related to #54811. Ping @stancl .

Steps To Reproduce

  • Define a route.
// Affiliate referral link
Route::get('r/{slug}', Controllers\AffiliateLinkController::class)->name('affiliate_link');
  • Call the route with an empty string, using route().
route('affiliate_link', '');
@stancl
Copy link
Contributor

stancl commented Apr 3, 2025

Hmm, a lot of the internal code treated '' as missing values, strange. Will fix, thanks for reporting

@stancl
Copy link
Contributor

stancl commented Apr 4, 2025

To clarify, this is a preexisting bug that is made more apparent due to my PR.

if you instead passed ['slug' => ''] in <= v12.3.0 it would fail with the same error. Only passing the empty string positionally worked around this by bypassing the buggy parts of the URL generation logic.

@stancl
Copy link
Contributor

stancl commented Apr 4, 2025

Hmm, it seems according to tests passing an empty string should NOT be allowed.

I was trying to see if a change like this would work:

diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php
index c823243634..5a75e8a935 100644
--- a/src/Illuminate/Routing/RouteUrlGenerator.php
+++ b/src/Illuminate/Routing/RouteUrlGenerator.php
@@ -316,7 +316,8 @@ protected function replaceNamedParameters($path, &$parameters)
             } elseif (isset($this->defaultParameters[$m[1]])) {
                 return $this->defaultParameters[$m[1]];
             } elseif (isset($parameters[$m[1]])) {
-                Arr::pull($parameters, $m[1]);
+                // If there's neither a provided value nor a default value, we just use the empty string...
+                return Arr::pull($parameters, $m[1]);
             }

             return $m[0];

That however makes this test fail:

public static function providerRouteParameters()
{
    return [
        [['test' => 123]],
        [['one' => null, 'test' => 123]],
        [['one' => '', 'test' => 123]],
    ];
}

#[DataProvider('providerRouteParameters')]
public function testUrlGenerationForControllersRequiresPassingOfRequiredParameters($parameters)
{
    $this->expectException(UrlGenerationException::class);

    $url = new UrlGenerator(
        $routes = new RouteCollection,
        Request::create('http://www.foo.com:8080/')
    );

    $route = new Route(['GET'], 'foo/{one}/{two?}/{three?}', ['as' => 'foo', function () {
        //
    }]);
    $routes->add($route);

    $this->assertSame('http://www.foo.com:8080/foo?test=123', $url->route('foo', $parameters));
}

But the expectation with which this issue is reported is that passing an empty string (third case in the provider) should work.

What my changes do is turn [''], which apparently unintentionally works, into ['paramName' => ''], which is not allowed according to existing tests.

So I think in your case you should just make the parameter optional.

@apih
Copy link
Contributor Author

apih commented Apr 4, 2025

Thanks for your extensive testing @stancl. This issue caught me by surprise in several projects, since several parts relied on this unintended behavior, and works fine before. Based on your explanation, I understand that it was a bug, so moving forward, I will just fix the issue in my projects.

@laravel laravel locked and limited conversation to collaborators Apr 7, 2025
@crynobone crynobone converted this issue into discussion #55305 Apr 7, 2025

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants