Find this useful? Enter your email to receive occasional updates for securing PHP code.

Signing you up...

Thank you for signing up!

PHP Decode

<?php namespace Illuminate\Tests\Routing; use Illuminate\Contracts\Routing\UrlRoutable; ..

Decoded Output download

<?php

namespace Illuminate\Tests\Routing;

use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Routing\Exceptions\UrlGenerationException;
use Illuminate\Routing\Route;
use Illuminate\Routing\RouteCollection;
use Illuminate\Routing\UrlGenerator;
use InvalidArgumentException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Symfony\Component\Routing\Exception\RouteNotFoundException;

include_once 'Enums.php';

class RoutingUrlGeneratorTest extends TestCase
{
    public function testBasicGeneration()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $this->assertSame('http://www.foo.com/foo/bar', $url->to('foo/bar'));
        $this->assertSame('https://www.foo.com/foo/bar', $url->to('foo/bar', [], true));
        $this->assertSame('https://www.foo.com/foo/bar/baz/boom', $url->to('foo/bar', ['baz', 'boom'], true));
        $this->assertSame('https://www.foo.com/foo/bar/baz?foo=bar', $url->to('foo/bar?foo=bar', ['baz'], true));

        /*
         * Test HTTPS request URL generation...
         */
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('https://www.foo.com/')
        );

        $this->assertSame('https://www.foo.com/foo/bar', $url->to('foo/bar'));
    }

    public function testQueryGeneration()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $this->assertSame('http://www.foo.com/foo/bar', $url->query('foo/bar'));
        $this->assertSame('http://www.foo.com/foo/bar?0=foo', $url->query('foo/bar', ['foo']));
        $this->assertSame('http://www.foo.com/foo/bar?baz=boom', $url->query('foo/bar', ['baz' => 'boom']));
        $this->assertSame('http://www.foo.com/foo/bar?baz=zee&zal=bee', $url->query('foo/bar?baz=boom&zal=bee', ['baz' => 'zee']));
        $this->assertSame('http://www.foo.com/foo/bar?zal=bee', $url->query('foo/bar?baz=boom&zal=bee', ['baz' => null]));
        $this->assertSame('http://www.foo.com/foo/bar?baz=boom', $url->query('foo/bar?baz=boom', ['nonexist' => null]));
        $this->assertSame('http://www.foo.com/foo/bar', $url->query('foo/bar?baz=boom', ['baz' => null]));
        $this->assertSame('https://www.foo.com/foo/bar/baz?foo=bar&zal=bee', $url->query('foo/bar?foo=bar', ['zal' => 'bee'], ['baz'], true));
        $this->assertSame('http://www.foo.com/foo/bar?baz[0]=boom&baz[1]=bam&baz[2]=bim', urldecode($url->query('foo/bar', ['baz' => ['boom', 'bam', 'bim']])));
    }

    public function testAssetGeneration()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/index.php/')
        );

        $this->assertSame('http://www.foo.com/foo/bar', $url->asset('foo/bar'));
        $this->assertSame('https://www.foo.com/foo/bar', $url->asset('foo/bar', true));

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

        $this->assertSame('/foo/bar', $url->asset('foo/bar'));
        $this->assertSame('/foo/bar', $url->asset('foo/bar', true));
    }

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

        $route = new Route(['GET'], '/named-route', ['as' => 'plain']);
        $routes->add($route);

        $url->formatHostUsing(function ($host) {
            return str_replace('foo.com', 'foo.org', $host);
        });

        $this->assertSame('http://www.foo.org/foo/bar', $url->to('foo/bar'));
        $this->assertSame('/named-route', $url->route('plain', [], false));
    }

    public function testBasicGenerationWithRequestBaseUrlWithSubfolder()
    {
        $request = Request::create('http://www.foo.com/subfolder/foo/bar/subfolder/');

        $request->server->set('SCRIPT_FILENAME', '/var/www/laravel-project/public/subfolder/index.php');
        $request->server->set('PHP_SELF', '/subfolder/index.php');

        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request
        );

        $route = new Route(['GET'], 'foo/bar/subfolder', ['as' => 'foobar']);
        $routes->add($route);

        $this->assertSame('/subfolder', $request->getBaseUrl());
        $this->assertSame('/foo/bar/subfolder', $url->route('foobar', [], false));
    }

    public function testBasicGenerationWithRequestBaseUrlWithSubfolderAndFileSuffix()
    {
        $request = Request::create('http://www.foo.com/subfolder/index.php');

        $request->server->set('SCRIPT_FILENAME', '/var/www/laravel-project/public/subfolder/index.php');
        $request->server->set('PHP_SELF', '/subfolder/index.php');

        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request
        );

        $route = new Route(['GET'], 'foo/bar/subfolder', ['as' => 'foobar']);
        $routes->add($route);

        $this->assertSame('/subfolder', $request->getBasePath());
        $this->assertSame('/subfolder/index.php', $request->getBaseUrl());
        $this->assertSame('/foo/bar/subfolder', $url->route('foobar', [], false));
    }

    public function testBasicGenerationWithRequestBaseUrlWithFileSuffix()
    {
        $request = Request::create('http://www.foo.com/other.php');

        $request->server->set('SCRIPT_FILENAME', '/var/www/laravel-project/public/other.php');
        $request->server->set('PHP_SELF', '/other.php');

        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request
        );

        $route = new Route(['GET'], 'foo/bar/subfolder', ['as' => 'foobar']);
        $routes->add($route);

        $this->assertSame('', $request->getBasePath());
        $this->assertSame('/other.php', $request->getBaseUrl());
        $this->assertSame('/foo/bar/subfolder', $url->route('foobar', [], false));
    }

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

        $route = new Route(['GET'], '/named-route', ['as' => 'plain']);
        $routes->add($route);

        $url->formatPathUsing(function ($path) {
            return '/something'.$path;
        });

        $this->assertSame('http://www.foo.com/something/foo/bar', $url->to('foo/bar'));
        $this->assertSame('/something/named-route', $url->route('plain', [], false));
    }

    public function testUrlFormattersShouldReceiveTargetRoute()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('http://abc.com/')
        );

        $namedRoute = new Route(['GET'], '/bar', ['as' => 'plain', 'root' => 'bar.com', 'path' => 'foo']);
        $routes->add($namedRoute);

        $url->formatHostUsing(function ($root, $route) {
            return $route ? 'http://'.$route->getAction('root') : $root;
        });

        $url->formatPathUsing(function ($path, $route) {
            return $route ? '/'.$route->getAction('path') : $path;
        });

        $this->assertSame('http://abc.com/foo/bar', $url->to('foo/bar'));
        $this->assertSame('http://bar.com/foo', $url->route('plain'));
    }

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

        /*
         * Empty Named Route
         */
        $route = new Route(['GET'], '/', ['as' => 'plain']);
        $routes->add($route);

        /*
         * Named Routes
         */
        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo']);
        $routes->add($route);

        /*
         * Parameters...
         */
        $route = new Route(['GET'], 'foo/bar/{baz}/breeze/{boom}', ['as' => 'bar']);
        $routes->add($route);

        /*
         * Single Parameter...
         */
        $route = new Route(['GET'], 'foo/bar/{baz}', ['as' => 'foobar']);
        $routes->add($route);

        /*
         * Optional parameter
         */
        $route = new Route(['GET'], 'foo/bar/{baz?}', ['as' => 'optional']);
        $routes->add($route);

        /*
         * HTTPS...
         */
        $route = new Route(['GET'], 'foo/baz', ['as' => 'baz', 'https']);
        $routes->add($route);

        /*
         * Controller Route Route
         */
        $route = new Route(['GET'], 'foo/bam', ['controller' => 'foo@bar']);
        $routes->add($route);

        /*
         * Non ASCII routes
         */
        $route = new Route(['GET'], 'foo/bar//{baz}', ['as' => 'foobarbaz']);
        $routes->add($route);

        /*
         * Fragments
         */
        $route = new Route(['GET'], 'foo/bar#derp', ['as' => 'fragment']);
        $routes->add($route);

        /*
         * Invoke action
         */
        $route = new Route(['GET'], 'foo/invoke', ['controller' => 'InvokableActionStub']);
        $routes->add($route);

        /*
         * With Default Parameter
         */
        $url->defaults(['locale' => 'en']);
        $route = new Route(['GET'], 'foo', ['as' => 'defaults', 'domain' => '{locale}.example.com', function () {
            //
        }]);
        $routes->add($route);

        $this->assertSame('/', $url->route('plain', [], false));
        $this->assertSame('/?foo=bar', $url->route('plain', ['foo' => 'bar'], false));
        $this->assertSame('http://www.foo.com/foo/bar', $url->route('foo'));
        $this->assertSame('/foo/bar', $url->route('foo', [], false));
        $this->assertSame('/foo/bar?foo=bar', $url->route('foo', ['foo' => 'bar'], false));
        $this->assertSame('http://www.foo.com/foo/bar/taylor/breeze/otwell?fly=wall', $url->route('bar', ['taylor', 'otwell', 'fly' => 'wall']));
        $this->assertSame('http://www.foo.com/foo/bar/otwell/breeze/taylor?fly=wall', $url->route('bar', ['boom' => 'taylor', 'baz' => 'otwell', 'fly' => 'wall']));
        $this->assertSame('http://www.foo.com/foo/bar/0', $url->route('foobar', 0));
        $this->assertSame('http://www.foo.com/foo/bar/2', $url->route('foobar', 2));
        $this->assertSame('http://www.foo.com/foo/bar/taylor', $url->route('foobar', 'taylor'));
        $this->assertSame('/foo/bar/taylor/breeze/otwell?fly=wall', $url->route('bar', ['taylor', 'otwell', 'fly' => 'wall'], false));
        $this->assertSame('https://www.foo.com/foo/baz', $url->route('baz'));
        $this->assertSame('http://www.foo.com/foo/bam', $url->action('foo@bar'));
        $this->assertSame('http://www.foo.com/foo/bam', $url->action(['foo', 'bar']));
        $this->assertSame('http://www.foo.com/foo/invoke', $url->action('InvokableActionStub'));
        $this->assertSame('http://www.foo.com/foo/bar/taylor/breeze/otwell?wall&woz', $url->route('bar', ['wall', 'woz', 'boom' => 'otwell', 'baz' => 'taylor']));
        $this->assertSame('http://www.foo.com/foo/bar/taylor/breeze/otwell?wall&woz', $url->route('bar', ['taylor', 'otwell', 'wall', 'woz']));
        $this->assertSame('http://www.foo.com/foo/bar', $url->route('optional'));
        $this->assertSame('http://www.foo.com/foo/bar', $url->route('optional', ['baz' => null]));
        $this->assertSame('http://www.foo.com/foo/bar', $url->route('optional', ['baz' => '']));
        $this->assertSame('http://www.foo.com/foo/bar/0', $url->route('optional', ['baz' => 0]));
        $this->assertSame('http://www.foo.com/foo/bar/taylor', $url->route('optional', 'taylor'));
        $this->assertSame('http://www.foo.com/foo/bar/taylor', $url->route('optional', ['taylor']));
        $this->assertSame('http://www.foo.com/foo/bar/taylor?breeze', $url->route('optional', ['taylor', 'breeze']));
        $this->assertSame('http://www.foo.com/foo/bar/taylor?wall=woz', $url->route('optional', ['wall' => 'woz', 'taylor']));
        $this->assertSame('http://www.foo.com/foo/bar/taylor?wall=woz&breeze', $url->route('optional', ['wall' => 'woz', 'breeze', 'baz' => 'taylor']));
        $this->assertSame('http://www.foo.com/foo/bar?wall=woz', $url->route('optional', ['wall' => 'woz']));
        $this->assertSame('http://www.foo.com/foo/bar/%C3%A5%CE%B1%D1%84/%C3%A5%CE%B1%D1%84', $url->route('foobarbaz', ['baz' => '']));
        $this->assertSame('/foo/bar#derp', $url->route('fragment', [], false));
        $this->assertSame('/foo/bar?foo=bar#derp', $url->route('fragment', ['foo' => 'bar'], false));
        $this->assertSame('/foo/bar?baz=%C3%A5%CE%B1%D1%84#derp', $url->route('fragment', ['baz' => ''], false));
        $this->assertSame('http://en.example.com/foo', $url->route('defaults'));
    }

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

        /*
         * Named Routes
         */
        $route = new Route(['GET'], 'foo/bar', []);
        $route->name('foo');
        $routes->add($route);
        $routes->refreshNameLookups();

        $this->assertSame('http://www.foo.com/foo/bar', $url->route('foo'));
    }

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

        $url->setRootControllerNamespace('namespace');

        /*
         * Controller Route Route
         */
        $route = new Route(['GET'], 'foo/bar', ['controller' => 'namespace\foo@bar']);
        $routes->add($route);

        $route = new Route(['GET'], 'something/else', ['controller' => 'something\foo@bar']);
        $routes->add($route);

        $route = new Route(['GET'], 'foo/invoke', ['controller' => 'namespace\InvokableActionStub']);
        $routes->add($route);

        $this->assertSame('http://www.foo.com/foo/bar', $url->action('foo@bar'));
        $this->assertSame('http://www.foo.com/something/else', $url->action('\something\foo@bar'));
        $this->assertSame('http://www.foo.com/foo/invoke', $url->action('InvokableActionStub'));
    }

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

        $url->setRootControllerNamespace('namespace');

        $route = new Route(['GET'], 'root/namespace', ['controller' => '\root\namespace@foo']);
        $routes->add($route);

        $route = new Route(['GET'], 'invokable/namespace', ['controller' => '\root\namespace\InvokableActionStub']);
        $routes->add($route);

        $this->assertSame('http://www.foo.com/root/namespace', $url->action('\root\namespace@foo'));
        $this->assertSame('http://www.foo.com/invokable/namespace', $url->action('\root\namespace\InvokableActionStub'));
    }

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

        $route = new Route(['GET'], 'foo/{bar}', ['as' => 'routable']);
        $routes->add($route);

        $model = new RoutableInterfaceStub;
        $model->key = 'routable';

        $this->assertSame('/foo/routable', $url->route('routable', [$model], false));
    }

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

        $route = new Route(['GET'], 'foo/{bar:slug}', ['as' => 'routable']);
        $routes->add($route);

        $model = new RoutableInterfaceStub;
        $model->key = 'routable';

        $this->assertSame('/foo/test-slug', $url->route('routable', ['bar' => $model], false));
        $this->assertSame('/foo/test-slug', $url->route('routable', [$model], false));
    }

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

        $route = new Route(['GET'], 'foo', ['as' => 'query-string']);
        $routes->add($route);

        $model = new RoutableInterfaceStub;
        $model->key = 'routable';

        $this->assertSame('/foo?routable', $url->route('query-string', $model, false));
        $this->assertSame('/foo?routable', $url->route('query-string', [$model], false));
        $this->assertSame('/foo?foo=routable', $url->route('query-string', ['foo' => $model], false));
    }

    /**
     * @todo Fix bug related to route keys
     *
     * @link https://github.com/laravel/framework/pull/42425
     */
    public function testRoutableInterfaceRoutingWithSeparateBindingFieldOnlyForSecondParameter()
    {
        $this->markTestSkipped('See https://github.com/laravel/framework/pull/43255');

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

        $route = new Route(['GET'], 'foo/{bar}/{baz:slug}', ['as' => 'routable']);
        $routes->add($route);

        $model1 = new RoutableInterfaceStub;
        $model1->key = 'routable-1';

        $model2 = new RoutableInterfaceStub;
        $model2->key = 'routable-2';

        $this->assertSame('/foo/routable-1/test-slug', $url->route('routable', ['bar' => $model1, 'baz' => $model2], false));
        $this->assertSame('/foo/routable-1/test-slug', $url->route('routable', [$model1, $model2], false));
    }

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

        $route = new Route(['GET'], 'foo/{bar}', ['as' => 'routable']);
        $routes->add($route);

        $model = new RoutableInterfaceStub;
        $model->key = 'routable';

        $this->assertSame('/foo/routable', $url->route('routable', $model, false));
    }

    public function testRoutesMaintainRequestScheme()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('https://www.foo.com/')
        );

        /*
         * Named Routes
         */
        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo']);
        $routes->add($route);

        $this->assertSame('https://www.foo.com/foo/bar', $url->route('foo'));
    }

    public function testHttpOnlyRoutes()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('https://www.foo.com/')
        );

        /*
         * Named Routes
         */
        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'http']);
        $routes->add($route);

        $this->assertSame('http://www.foo.com/foo/bar', $url->route('foo'));
    }

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

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'sub.foo.com']);
        $routes->add($route);

        /*
         * Wildcards & Domains...
         */
        $route = new Route(['GET'], 'foo/bar/{baz}', ['as' => 'bar', 'domain' => 'sub.{foo}.com']);
        $routes->add($route);

        $this->assertSame('http://sub.foo.com/foo/bar', $url->route('foo'));
        $this->assertSame('http://sub.taylor.com/foo/bar/otwell', $url->route('bar', ['taylor', 'otwell']));
        $this->assertSame('/foo/bar/otwell', $url->route('bar', ['taylor', 'otwell'], false));
    }

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

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'sub.foo.com']);
        $routes->add($route);

        /*
         * Wildcards & Domains...
         */
        $route = new Route(['GET'], 'foo/bar/{baz}', ['as' => 'bar', 'domain' => 'sub.{foo}.com']);
        $routes->add($route);

        $this->assertSame('http://sub.foo.com:8080/foo/bar', $url->route('foo'));
        $this->assertSame('http://sub.taylor.com:8080/foo/bar/otwell', $url->route('bar', ['taylor', 'otwell']));
    }

    public function testRoutesWithDomainsStripsProtocols()
    {
        /*
         * http:// Route
         */
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'http://sub.foo.com']);
        $routes->add($route);

        $this->assertSame('http://sub.foo.com/foo/bar', $url->route('foo'));

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

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'https://sub.foo.com']);
        $routes->add($route);

        $this->assertSame('https://sub.foo.com/foo/bar', $url->route('foo'));
    }

    public function testHttpsRoutesWithDomains()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('https://foo.com/')
        );

        /*
         * When on HTTPS, no need to specify 443
         */
        $route = new Route(['GET'], 'foo/bar', ['as' => 'baz', 'domain' => 'sub.foo.com']);
        $routes->add($route);

        $this->assertSame('https://sub.foo.com/foo/bar', $url->route('baz'));
    }

    public function testRoutesWithDomainsThroughProxy()
    {
        Request::setTrustedProxies(['10.0.0.1'], SymfonyRequest::HEADER_X_FORWARDED_FOR | SymfonyRequest::HEADER_X_FORWARDED_HOST | SymfonyRequest::HEADER_X_FORWARDED_PORT | SymfonyRequest::HEADER_X_FORWARDED_PROTO);

        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('http://www.foo.com/', 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1', 'HTTP_X_FORWARDED_PORT' => '80'])
        );

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'sub.foo.com']);
        $routes->add($route);

        $this->assertSame('http://sub.foo.com/foo/bar', $url->route('foo'));
    }

    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));
    }

    public static function provideParametersAndExpectedMeaningfulExceptionMessages()
    {
        return [
            'Missing parameters "one", "two" and "three"' => [
                [],
                'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: one, two, three].',
            ],
            'Missing parameters "two" and "three"' => [
                ['one' => '123'],
                'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: two, three].',
            ],
            'Missing parameters "one" and "three"' => [
                ['two' => '123'],
                'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: one, three].',
            ],
            'Missing parameters "one" and "two"' => [
                ['three' => '123'],
                'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: one, two].',
            ],
            'Missing parameter "three"' => [
                ['one' => '123', 'two' => '123'],
                'Missing required parameter for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameter: three].',
            ],
            'Missing parameter "two"' => [
                ['one' => '123', 'three' => '123'],
                'Missing required parameter for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameter: two].',
            ],
            'Missing parameter "one"' => [
                ['two' => '123', 'three' => '123'],
                'Missing required parameter for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameter: one].',
            ],
        ];
    }

    #[DataProvider('provideParametersAndExpectedMeaningfulExceptionMessages')]
    public function testUrlGenerationThrowsExceptionForMissingParametersWithMeaningfulMessage($parameters, $expectedMeaningfulExceptionMessage)
    {
        $this->expectException(UrlGenerationException::class);
        $this->expectExceptionMessage($expectedMeaningfulExceptionMessage);

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

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

        $url->route('foo', $parameters);
    }

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

        $url->forceRootUrl('https://www.bar.com');
        $this->assertSame('http://www.bar.com/foo/bar', $url->to('foo/bar'));

        // Ensure trailing slash is trimmed from root URL as UrlGenerator already handles this
        $url->forceRootUrl('http://www.foo.com/');
        $this->assertSame('http://www.foo.com/bar', $url->to('/bar'));

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

        $url->forceScheme('https');
        $route = new Route(['GET'], '/foo', ['as' => 'plain']);
        $routes->add($route);

        $this->assertSame('https://www.foo.com/foo', $url->route('plain'));

        $url->forceRootUrl('https://www.bar.com');
        $this->assertSame('https://www.bar.com/foo', $url->route('plain'));
    }

    public function testPrevious()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $url->getRequest()->headers->set('referer', 'http://www.bar.com/');
        $this->assertSame('http://www.bar.com/', $url->previous());

        $url->getRequest()->headers->remove('referer');
        $this->assertEquals($url->to('/'), $url->previous());

        $this->assertEquals($url->to('/foo'), $url->previous('/foo'));
    }

    public function testPreviousPath()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $url->getRequest()->headers->set('referer', 'http://www.foo.com?baz=bah');
        $this->assertSame('/', $url->previousPath());

        $url->getRequest()->headers->set('referer', 'http://www.foo.com/?baz=bah');
        $this->assertSame('/', $url->previousPath());

        $url->getRequest()->headers->set('referer', 'http://www.foo.com/bar?baz=bah');
        $this->assertSame('/bar', $url->previousPath());

        $url->getRequest()->headers->remove('referer');
        $this->assertSame('/', $url->previousPath());

        $this->assertSame('/bar', $url->previousPath('/bar'));
    }

    public function testRouteNotDefinedException()
    {
        $this->expectException(RouteNotFoundException::class);
        $this->expectExceptionMessage('Route [not_exists_route] not defined.');

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

        $url->route('not_exists_route');
    }

    public function testSignedUrl()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

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

        $request = Request::create($url->signedRoute('foo'));

        $this->assertTrue($url->hasValidSignature($request));

        $request = Request::create($url->signedRoute('foo').'?tampered=true');

        $this->assertFalse($url->hasValidSignature($request));
    }

    public function testSignedUrlImplicitModelBinding()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

        $route = new Route(['GET'], 'foo/{user:uuid}', ['as' => 'foo', function () {
            //
        }]);
        $routes->add($route);

        $user = new RoutingUrlGeneratorTestUser(['uuid' => '0231d4ac-e9e3-4452-a89a-4427cfb23c3e']);

        $request = Request::create($url->signedRoute('foo', $user));

        $this->assertTrue($url->hasValidSignature($request));
    }

    public function testSignedRelativeUrl()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

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

        $result = $url->signedRoute('foo', [], null, false);

        $request = Request::create($result);

        $this->assertTrue($url->hasValidSignature($request, false));

        $request = Request::create($url->signedRoute('foo', [], null, false).'?tampered=true');

        $this->assertFalse($url->hasValidSignature($request, false));
    }

    public function testSignedUrlParameterCannotBeNamedSignature()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

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

        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('reserved');

        Request::create($url->signedRoute('foo', ['signature' => 'bar']));
    }

    public function testSignedUrlParameterCannotBeNamedExpires()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

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

        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('reserved');

        Request::create($url->signedRoute('foo', ['expires' => 253402300799]));
    }

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

        $namedRoute = new Route(['GET'], '/foo/{bar}', ['as' => 'foo.bar']);
        $routes->add($namedRoute);

        $this->assertSame('http://www.foo.com/foo/fruits', $url->route('foo.bar', CategoryBackedEnum::Fruits));
    }

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

        $namedRoute = new Route(['GET'], '/foo', ['as' => 'foo']);
        $routes->add($namedRoute);

        $this->assertSame(
            'http://www.foo.com/foo?filter%5B0%5D=people&filter%5B1%5D=fruits',
            $url->route('foo', ['filter' => [CategoryBackedEnum::People, CategoryBackedEnum::Fruits]]),
        );
    }

    public function testSignedUrlWithKeyResolver()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'first-secret';
        });

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

        $firstRequest = Request::create($url->signedRoute('foo'));

        $this->assertTrue($url->hasValidSignature($firstRequest));

        $request = Request::create($url->signedRoute('foo').'?tampered=true');

        $this->assertFalse($url->hasValidSignature($request));

        $url2 = $url->withKeyResolver(function () {
            return 'second-secret';
        });

        $this->assertFalse($url2->hasValidSignature($firstRequest));

        $secondRequest = Request::create($url2->signedRoute('foo'));

        $this->assertTrue($url2->hasValidSignature($secondRequest));
        $this->assertFalse($url->hasValidSignature($secondRequest));

        // Key resolver also supports multiple keys, for app key rotation via the config "app.previous_keys"
        $url3 = $url->withKeyResolver(function () {
            return ['first-secret', 'second-secret'];
        });

        $this->assertTrue($url3->hasValidSignature($firstRequest));
        $this->assertTrue($url3->hasValidSignature($secondRequest));
    }

    public function testMissingNamedRouteResolution()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $url->resolveMissingNamedRoutesUsing(fn ($name, $parameters, $absolute) => 'test-url');

        $this->assertSame('test-url', $url->route('foo'));
    }
}

class RoutableInterfaceStub implements UrlRoutable
{
    public $key;
    public $slug = 'test-slug';

    public function getRouteKey()
    {
        return $this->{$this->getRouteKeyName()};
    }

    public function getRouteKeyName()
    {
        return 'key';
    }

    public function resolveRouteBinding($routeKey, $field = null)
    {
        //
    }

    public function resolveChildRouteBinding($childType, $routeKey, $field = null)
    {
        //
    }
}

class InvokableActionStub
{
    public function __invoke()
    {
        return 'hello';
    }
}

class RoutingUrlGeneratorTestUser extends Model
{
    protected $fillable = ['uuid'];
}
 ?>

Did this file decode correctly?

Original Code

<?php

namespace Illuminate\Tests\Routing;

use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Routing\Exceptions\UrlGenerationException;
use Illuminate\Routing\Route;
use Illuminate\Routing\RouteCollection;
use Illuminate\Routing\UrlGenerator;
use InvalidArgumentException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Symfony\Component\Routing\Exception\RouteNotFoundException;

include_once 'Enums.php';

class RoutingUrlGeneratorTest extends TestCase
{
    public function testBasicGeneration()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $this->assertSame('http://www.foo.com/foo/bar', $url->to('foo/bar'));
        $this->assertSame('https://www.foo.com/foo/bar', $url->to('foo/bar', [], true));
        $this->assertSame('https://www.foo.com/foo/bar/baz/boom', $url->to('foo/bar', ['baz', 'boom'], true));
        $this->assertSame('https://www.foo.com/foo/bar/baz?foo=bar', $url->to('foo/bar?foo=bar', ['baz'], true));

        /*
         * Test HTTPS request URL generation...
         */
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('https://www.foo.com/')
        );

        $this->assertSame('https://www.foo.com/foo/bar', $url->to('foo/bar'));
    }

    public function testQueryGeneration()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $this->assertSame('http://www.foo.com/foo/bar', $url->query('foo/bar'));
        $this->assertSame('http://www.foo.com/foo/bar?0=foo', $url->query('foo/bar', ['foo']));
        $this->assertSame('http://www.foo.com/foo/bar?baz=boom', $url->query('foo/bar', ['baz' => 'boom']));
        $this->assertSame('http://www.foo.com/foo/bar?baz=zee&zal=bee', $url->query('foo/bar?baz=boom&zal=bee', ['baz' => 'zee']));
        $this->assertSame('http://www.foo.com/foo/bar?zal=bee', $url->query('foo/bar?baz=boom&zal=bee', ['baz' => null]));
        $this->assertSame('http://www.foo.com/foo/bar?baz=boom', $url->query('foo/bar?baz=boom', ['nonexist' => null]));
        $this->assertSame('http://www.foo.com/foo/bar', $url->query('foo/bar?baz=boom', ['baz' => null]));
        $this->assertSame('https://www.foo.com/foo/bar/baz?foo=bar&zal=bee', $url->query('foo/bar?foo=bar', ['zal' => 'bee'], ['baz'], true));
        $this->assertSame('http://www.foo.com/foo/bar?baz[0]=boom&baz[1]=bam&baz[2]=bim', urldecode($url->query('foo/bar', ['baz' => ['boom', 'bam', 'bim']])));
    }

    public function testAssetGeneration()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/index.php/')
        );

        $this->assertSame('http://www.foo.com/foo/bar', $url->asset('foo/bar'));
        $this->assertSame('https://www.foo.com/foo/bar', $url->asset('foo/bar', true));

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

        $this->assertSame('/foo/bar', $url->asset('foo/bar'));
        $this->assertSame('/foo/bar', $url->asset('foo/bar', true));
    }

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

        $route = new Route(['GET'], '/named-route', ['as' => 'plain']);
        $routes->add($route);

        $url->formatHostUsing(function ($host) {
            return str_replace('foo.com', 'foo.org', $host);
        });

        $this->assertSame('http://www.foo.org/foo/bar', $url->to('foo/bar'));
        $this->assertSame('/named-route', $url->route('plain', [], false));
    }

    public function testBasicGenerationWithRequestBaseUrlWithSubfolder()
    {
        $request = Request::create('http://www.foo.com/subfolder/foo/bar/subfolder/');

        $request->server->set('SCRIPT_FILENAME', '/var/www/laravel-project/public/subfolder/index.php');
        $request->server->set('PHP_SELF', '/subfolder/index.php');

        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request
        );

        $route = new Route(['GET'], 'foo/bar/subfolder', ['as' => 'foobar']);
        $routes->add($route);

        $this->assertSame('/subfolder', $request->getBaseUrl());
        $this->assertSame('/foo/bar/subfolder', $url->route('foobar', [], false));
    }

    public function testBasicGenerationWithRequestBaseUrlWithSubfolderAndFileSuffix()
    {
        $request = Request::create('http://www.foo.com/subfolder/index.php');

        $request->server->set('SCRIPT_FILENAME', '/var/www/laravel-project/public/subfolder/index.php');
        $request->server->set('PHP_SELF', '/subfolder/index.php');

        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request
        );

        $route = new Route(['GET'], 'foo/bar/subfolder', ['as' => 'foobar']);
        $routes->add($route);

        $this->assertSame('/subfolder', $request->getBasePath());
        $this->assertSame('/subfolder/index.php', $request->getBaseUrl());
        $this->assertSame('/foo/bar/subfolder', $url->route('foobar', [], false));
    }

    public function testBasicGenerationWithRequestBaseUrlWithFileSuffix()
    {
        $request = Request::create('http://www.foo.com/other.php');

        $request->server->set('SCRIPT_FILENAME', '/var/www/laravel-project/public/other.php');
        $request->server->set('PHP_SELF', '/other.php');

        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request
        );

        $route = new Route(['GET'], 'foo/bar/subfolder', ['as' => 'foobar']);
        $routes->add($route);

        $this->assertSame('', $request->getBasePath());
        $this->assertSame('/other.php', $request->getBaseUrl());
        $this->assertSame('/foo/bar/subfolder', $url->route('foobar', [], false));
    }

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

        $route = new Route(['GET'], '/named-route', ['as' => 'plain']);
        $routes->add($route);

        $url->formatPathUsing(function ($path) {
            return '/something'.$path;
        });

        $this->assertSame('http://www.foo.com/something/foo/bar', $url->to('foo/bar'));
        $this->assertSame('/something/named-route', $url->route('plain', [], false));
    }

    public function testUrlFormattersShouldReceiveTargetRoute()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('http://abc.com/')
        );

        $namedRoute = new Route(['GET'], '/bar', ['as' => 'plain', 'root' => 'bar.com', 'path' => 'foo']);
        $routes->add($namedRoute);

        $url->formatHostUsing(function ($root, $route) {
            return $route ? 'http://'.$route->getAction('root') : $root;
        });

        $url->formatPathUsing(function ($path, $route) {
            return $route ? '/'.$route->getAction('path') : $path;
        });

        $this->assertSame('http://abc.com/foo/bar', $url->to('foo/bar'));
        $this->assertSame('http://bar.com/foo', $url->route('plain'));
    }

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

        /*
         * Empty Named Route
         */
        $route = new Route(['GET'], '/', ['as' => 'plain']);
        $routes->add($route);

        /*
         * Named Routes
         */
        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo']);
        $routes->add($route);

        /*
         * Parameters...
         */
        $route = new Route(['GET'], 'foo/bar/{baz}/breeze/{boom}', ['as' => 'bar']);
        $routes->add($route);

        /*
         * Single Parameter...
         */
        $route = new Route(['GET'], 'foo/bar/{baz}', ['as' => 'foobar']);
        $routes->add($route);

        /*
         * Optional parameter
         */
        $route = new Route(['GET'], 'foo/bar/{baz?}', ['as' => 'optional']);
        $routes->add($route);

        /*
         * HTTPS...
         */
        $route = new Route(['GET'], 'foo/baz', ['as' => 'baz', 'https']);
        $routes->add($route);

        /*
         * Controller Route Route
         */
        $route = new Route(['GET'], 'foo/bam', ['controller' => 'foo@bar']);
        $routes->add($route);

        /*
         * Non ASCII routes
         */
        $route = new Route(['GET'], 'foo/bar//{baz}', ['as' => 'foobarbaz']);
        $routes->add($route);

        /*
         * Fragments
         */
        $route = new Route(['GET'], 'foo/bar#derp', ['as' => 'fragment']);
        $routes->add($route);

        /*
         * Invoke action
         */
        $route = new Route(['GET'], 'foo/invoke', ['controller' => 'InvokableActionStub']);
        $routes->add($route);

        /*
         * With Default Parameter
         */
        $url->defaults(['locale' => 'en']);
        $route = new Route(['GET'], 'foo', ['as' => 'defaults', 'domain' => '{locale}.example.com', function () {
            //
        }]);
        $routes->add($route);

        $this->assertSame('/', $url->route('plain', [], false));
        $this->assertSame('/?foo=bar', $url->route('plain', ['foo' => 'bar'], false));
        $this->assertSame('http://www.foo.com/foo/bar', $url->route('foo'));
        $this->assertSame('/foo/bar', $url->route('foo', [], false));
        $this->assertSame('/foo/bar?foo=bar', $url->route('foo', ['foo' => 'bar'], false));
        $this->assertSame('http://www.foo.com/foo/bar/taylor/breeze/otwell?fly=wall', $url->route('bar', ['taylor', 'otwell', 'fly' => 'wall']));
        $this->assertSame('http://www.foo.com/foo/bar/otwell/breeze/taylor?fly=wall', $url->route('bar', ['boom' => 'taylor', 'baz' => 'otwell', 'fly' => 'wall']));
        $this->assertSame('http://www.foo.com/foo/bar/0', $url->route('foobar', 0));
        $this->assertSame('http://www.foo.com/foo/bar/2', $url->route('foobar', 2));
        $this->assertSame('http://www.foo.com/foo/bar/taylor', $url->route('foobar', 'taylor'));
        $this->assertSame('/foo/bar/taylor/breeze/otwell?fly=wall', $url->route('bar', ['taylor', 'otwell', 'fly' => 'wall'], false));
        $this->assertSame('https://www.foo.com/foo/baz', $url->route('baz'));
        $this->assertSame('http://www.foo.com/foo/bam', $url->action('foo@bar'));
        $this->assertSame('http://www.foo.com/foo/bam', $url->action(['foo', 'bar']));
        $this->assertSame('http://www.foo.com/foo/invoke', $url->action('InvokableActionStub'));
        $this->assertSame('http://www.foo.com/foo/bar/taylor/breeze/otwell?wall&woz', $url->route('bar', ['wall', 'woz', 'boom' => 'otwell', 'baz' => 'taylor']));
        $this->assertSame('http://www.foo.com/foo/bar/taylor/breeze/otwell?wall&woz', $url->route('bar', ['taylor', 'otwell', 'wall', 'woz']));
        $this->assertSame('http://www.foo.com/foo/bar', $url->route('optional'));
        $this->assertSame('http://www.foo.com/foo/bar', $url->route('optional', ['baz' => null]));
        $this->assertSame('http://www.foo.com/foo/bar', $url->route('optional', ['baz' => '']));
        $this->assertSame('http://www.foo.com/foo/bar/0', $url->route('optional', ['baz' => 0]));
        $this->assertSame('http://www.foo.com/foo/bar/taylor', $url->route('optional', 'taylor'));
        $this->assertSame('http://www.foo.com/foo/bar/taylor', $url->route('optional', ['taylor']));
        $this->assertSame('http://www.foo.com/foo/bar/taylor?breeze', $url->route('optional', ['taylor', 'breeze']));
        $this->assertSame('http://www.foo.com/foo/bar/taylor?wall=woz', $url->route('optional', ['wall' => 'woz', 'taylor']));
        $this->assertSame('http://www.foo.com/foo/bar/taylor?wall=woz&breeze', $url->route('optional', ['wall' => 'woz', 'breeze', 'baz' => 'taylor']));
        $this->assertSame('http://www.foo.com/foo/bar?wall=woz', $url->route('optional', ['wall' => 'woz']));
        $this->assertSame('http://www.foo.com/foo/bar/%C3%A5%CE%B1%D1%84/%C3%A5%CE%B1%D1%84', $url->route('foobarbaz', ['baz' => '']));
        $this->assertSame('/foo/bar#derp', $url->route('fragment', [], false));
        $this->assertSame('/foo/bar?foo=bar#derp', $url->route('fragment', ['foo' => 'bar'], false));
        $this->assertSame('/foo/bar?baz=%C3%A5%CE%B1%D1%84#derp', $url->route('fragment', ['baz' => ''], false));
        $this->assertSame('http://en.example.com/foo', $url->route('defaults'));
    }

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

        /*
         * Named Routes
         */
        $route = new Route(['GET'], 'foo/bar', []);
        $route->name('foo');
        $routes->add($route);
        $routes->refreshNameLookups();

        $this->assertSame('http://www.foo.com/foo/bar', $url->route('foo'));
    }

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

        $url->setRootControllerNamespace('namespace');

        /*
         * Controller Route Route
         */
        $route = new Route(['GET'], 'foo/bar', ['controller' => 'namespace\foo@bar']);
        $routes->add($route);

        $route = new Route(['GET'], 'something/else', ['controller' => 'something\foo@bar']);
        $routes->add($route);

        $route = new Route(['GET'], 'foo/invoke', ['controller' => 'namespace\InvokableActionStub']);
        $routes->add($route);

        $this->assertSame('http://www.foo.com/foo/bar', $url->action('foo@bar'));
        $this->assertSame('http://www.foo.com/something/else', $url->action('\something\foo@bar'));
        $this->assertSame('http://www.foo.com/foo/invoke', $url->action('InvokableActionStub'));
    }

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

        $url->setRootControllerNamespace('namespace');

        $route = new Route(['GET'], 'root/namespace', ['controller' => '\root\namespace@foo']);
        $routes->add($route);

        $route = new Route(['GET'], 'invokable/namespace', ['controller' => '\root\namespace\InvokableActionStub']);
        $routes->add($route);

        $this->assertSame('http://www.foo.com/root/namespace', $url->action('\root\namespace@foo'));
        $this->assertSame('http://www.foo.com/invokable/namespace', $url->action('\root\namespace\InvokableActionStub'));
    }

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

        $route = new Route(['GET'], 'foo/{bar}', ['as' => 'routable']);
        $routes->add($route);

        $model = new RoutableInterfaceStub;
        $model->key = 'routable';

        $this->assertSame('/foo/routable', $url->route('routable', [$model], false));
    }

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

        $route = new Route(['GET'], 'foo/{bar:slug}', ['as' => 'routable']);
        $routes->add($route);

        $model = new RoutableInterfaceStub;
        $model->key = 'routable';

        $this->assertSame('/foo/test-slug', $url->route('routable', ['bar' => $model], false));
        $this->assertSame('/foo/test-slug', $url->route('routable', [$model], false));
    }

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

        $route = new Route(['GET'], 'foo', ['as' => 'query-string']);
        $routes->add($route);

        $model = new RoutableInterfaceStub;
        $model->key = 'routable';

        $this->assertSame('/foo?routable', $url->route('query-string', $model, false));
        $this->assertSame('/foo?routable', $url->route('query-string', [$model], false));
        $this->assertSame('/foo?foo=routable', $url->route('query-string', ['foo' => $model], false));
    }

    /**
     * @todo Fix bug related to route keys
     *
     * @link https://github.com/laravel/framework/pull/42425
     */
    public function testRoutableInterfaceRoutingWithSeparateBindingFieldOnlyForSecondParameter()
    {
        $this->markTestSkipped('See https://github.com/laravel/framework/pull/43255');

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

        $route = new Route(['GET'], 'foo/{bar}/{baz:slug}', ['as' => 'routable']);
        $routes->add($route);

        $model1 = new RoutableInterfaceStub;
        $model1->key = 'routable-1';

        $model2 = new RoutableInterfaceStub;
        $model2->key = 'routable-2';

        $this->assertSame('/foo/routable-1/test-slug', $url->route('routable', ['bar' => $model1, 'baz' => $model2], false));
        $this->assertSame('/foo/routable-1/test-slug', $url->route('routable', [$model1, $model2], false));
    }

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

        $route = new Route(['GET'], 'foo/{bar}', ['as' => 'routable']);
        $routes->add($route);

        $model = new RoutableInterfaceStub;
        $model->key = 'routable';

        $this->assertSame('/foo/routable', $url->route('routable', $model, false));
    }

    public function testRoutesMaintainRequestScheme()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('https://www.foo.com/')
        );

        /*
         * Named Routes
         */
        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo']);
        $routes->add($route);

        $this->assertSame('https://www.foo.com/foo/bar', $url->route('foo'));
    }

    public function testHttpOnlyRoutes()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('https://www.foo.com/')
        );

        /*
         * Named Routes
         */
        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'http']);
        $routes->add($route);

        $this->assertSame('http://www.foo.com/foo/bar', $url->route('foo'));
    }

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

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'sub.foo.com']);
        $routes->add($route);

        /*
         * Wildcards & Domains...
         */
        $route = new Route(['GET'], 'foo/bar/{baz}', ['as' => 'bar', 'domain' => 'sub.{foo}.com']);
        $routes->add($route);

        $this->assertSame('http://sub.foo.com/foo/bar', $url->route('foo'));
        $this->assertSame('http://sub.taylor.com/foo/bar/otwell', $url->route('bar', ['taylor', 'otwell']));
        $this->assertSame('/foo/bar/otwell', $url->route('bar', ['taylor', 'otwell'], false));
    }

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

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'sub.foo.com']);
        $routes->add($route);

        /*
         * Wildcards & Domains...
         */
        $route = new Route(['GET'], 'foo/bar/{baz}', ['as' => 'bar', 'domain' => 'sub.{foo}.com']);
        $routes->add($route);

        $this->assertSame('http://sub.foo.com:8080/foo/bar', $url->route('foo'));
        $this->assertSame('http://sub.taylor.com:8080/foo/bar/otwell', $url->route('bar', ['taylor', 'otwell']));
    }

    public function testRoutesWithDomainsStripsProtocols()
    {
        /*
         * http:// Route
         */
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'http://sub.foo.com']);
        $routes->add($route);

        $this->assertSame('http://sub.foo.com/foo/bar', $url->route('foo'));

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

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'https://sub.foo.com']);
        $routes->add($route);

        $this->assertSame('https://sub.foo.com/foo/bar', $url->route('foo'));
    }

    public function testHttpsRoutesWithDomains()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('https://foo.com/')
        );

        /*
         * When on HTTPS, no need to specify 443
         */
        $route = new Route(['GET'], 'foo/bar', ['as' => 'baz', 'domain' => 'sub.foo.com']);
        $routes->add($route);

        $this->assertSame('https://sub.foo.com/foo/bar', $url->route('baz'));
    }

    public function testRoutesWithDomainsThroughProxy()
    {
        Request::setTrustedProxies(['10.0.0.1'], SymfonyRequest::HEADER_X_FORWARDED_FOR | SymfonyRequest::HEADER_X_FORWARDED_HOST | SymfonyRequest::HEADER_X_FORWARDED_PORT | SymfonyRequest::HEADER_X_FORWARDED_PROTO);

        $url = new UrlGenerator(
            $routes = new RouteCollection,
            Request::create('http://www.foo.com/', 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1', 'HTTP_X_FORWARDED_PORT' => '80'])
        );

        $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'sub.foo.com']);
        $routes->add($route);

        $this->assertSame('http://sub.foo.com/foo/bar', $url->route('foo'));
    }

    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));
    }

    public static function provideParametersAndExpectedMeaningfulExceptionMessages()
    {
        return [
            'Missing parameters "one", "two" and "three"' => [
                [],
                'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: one, two, three].',
            ],
            'Missing parameters "two" and "three"' => [
                ['one' => '123'],
                'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: two, three].',
            ],
            'Missing parameters "one" and "three"' => [
                ['two' => '123'],
                'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: one, three].',
            ],
            'Missing parameters "one" and "two"' => [
                ['three' => '123'],
                'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: one, two].',
            ],
            'Missing parameter "three"' => [
                ['one' => '123', 'two' => '123'],
                'Missing required parameter for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameter: three].',
            ],
            'Missing parameter "two"' => [
                ['one' => '123', 'three' => '123'],
                'Missing required parameter for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameter: two].',
            ],
            'Missing parameter "one"' => [
                ['two' => '123', 'three' => '123'],
                'Missing required parameter for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameter: one].',
            ],
        ];
    }

    #[DataProvider('provideParametersAndExpectedMeaningfulExceptionMessages')]
    public function testUrlGenerationThrowsExceptionForMissingParametersWithMeaningfulMessage($parameters, $expectedMeaningfulExceptionMessage)
    {
        $this->expectException(UrlGenerationException::class);
        $this->expectExceptionMessage($expectedMeaningfulExceptionMessage);

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

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

        $url->route('foo', $parameters);
    }

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

        $url->forceRootUrl('https://www.bar.com');
        $this->assertSame('http://www.bar.com/foo/bar', $url->to('foo/bar'));

        // Ensure trailing slash is trimmed from root URL as UrlGenerator already handles this
        $url->forceRootUrl('http://www.foo.com/');
        $this->assertSame('http://www.foo.com/bar', $url->to('/bar'));

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

        $url->forceScheme('https');
        $route = new Route(['GET'], '/foo', ['as' => 'plain']);
        $routes->add($route);

        $this->assertSame('https://www.foo.com/foo', $url->route('plain'));

        $url->forceRootUrl('https://www.bar.com');
        $this->assertSame('https://www.bar.com/foo', $url->route('plain'));
    }

    public function testPrevious()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $url->getRequest()->headers->set('referer', 'http://www.bar.com/');
        $this->assertSame('http://www.bar.com/', $url->previous());

        $url->getRequest()->headers->remove('referer');
        $this->assertEquals($url->to('/'), $url->previous());

        $this->assertEquals($url->to('/foo'), $url->previous('/foo'));
    }

    public function testPreviousPath()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $url->getRequest()->headers->set('referer', 'http://www.foo.com?baz=bah');
        $this->assertSame('/', $url->previousPath());

        $url->getRequest()->headers->set('referer', 'http://www.foo.com/?baz=bah');
        $this->assertSame('/', $url->previousPath());

        $url->getRequest()->headers->set('referer', 'http://www.foo.com/bar?baz=bah');
        $this->assertSame('/bar', $url->previousPath());

        $url->getRequest()->headers->remove('referer');
        $this->assertSame('/', $url->previousPath());

        $this->assertSame('/bar', $url->previousPath('/bar'));
    }

    public function testRouteNotDefinedException()
    {
        $this->expectException(RouteNotFoundException::class);
        $this->expectExceptionMessage('Route [not_exists_route] not defined.');

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

        $url->route('not_exists_route');
    }

    public function testSignedUrl()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

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

        $request = Request::create($url->signedRoute('foo'));

        $this->assertTrue($url->hasValidSignature($request));

        $request = Request::create($url->signedRoute('foo').'?tampered=true');

        $this->assertFalse($url->hasValidSignature($request));
    }

    public function testSignedUrlImplicitModelBinding()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

        $route = new Route(['GET'], 'foo/{user:uuid}', ['as' => 'foo', function () {
            //
        }]);
        $routes->add($route);

        $user = new RoutingUrlGeneratorTestUser(['uuid' => '0231d4ac-e9e3-4452-a89a-4427cfb23c3e']);

        $request = Request::create($url->signedRoute('foo', $user));

        $this->assertTrue($url->hasValidSignature($request));
    }

    public function testSignedRelativeUrl()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

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

        $result = $url->signedRoute('foo', [], null, false);

        $request = Request::create($result);

        $this->assertTrue($url->hasValidSignature($request, false));

        $request = Request::create($url->signedRoute('foo', [], null, false).'?tampered=true');

        $this->assertFalse($url->hasValidSignature($request, false));
    }

    public function testSignedUrlParameterCannotBeNamedSignature()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

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

        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('reserved');

        Request::create($url->signedRoute('foo', ['signature' => 'bar']));
    }

    public function testSignedUrlParameterCannotBeNamedExpires()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'secret';
        });

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

        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('reserved');

        Request::create($url->signedRoute('foo', ['expires' => 253402300799]));
    }

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

        $namedRoute = new Route(['GET'], '/foo/{bar}', ['as' => 'foo.bar']);
        $routes->add($namedRoute);

        $this->assertSame('http://www.foo.com/foo/fruits', $url->route('foo.bar', CategoryBackedEnum::Fruits));
    }

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

        $namedRoute = new Route(['GET'], '/foo', ['as' => 'foo']);
        $routes->add($namedRoute);

        $this->assertSame(
            'http://www.foo.com/foo?filter%5B0%5D=people&filter%5B1%5D=fruits',
            $url->route('foo', ['filter' => [CategoryBackedEnum::People, CategoryBackedEnum::Fruits]]),
        );
    }

    public function testSignedUrlWithKeyResolver()
    {
        $url = new UrlGenerator(
            $routes = new RouteCollection,
            $request = Request::create('http://www.foo.com/')
        );
        $url->setKeyResolver(function () {
            return 'first-secret';
        });

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

        $firstRequest = Request::create($url->signedRoute('foo'));

        $this->assertTrue($url->hasValidSignature($firstRequest));

        $request = Request::create($url->signedRoute('foo').'?tampered=true');

        $this->assertFalse($url->hasValidSignature($request));

        $url2 = $url->withKeyResolver(function () {
            return 'second-secret';
        });

        $this->assertFalse($url2->hasValidSignature($firstRequest));

        $secondRequest = Request::create($url2->signedRoute('foo'));

        $this->assertTrue($url2->hasValidSignature($secondRequest));
        $this->assertFalse($url->hasValidSignature($secondRequest));

        // Key resolver also supports multiple keys, for app key rotation via the config "app.previous_keys"
        $url3 = $url->withKeyResolver(function () {
            return ['first-secret', 'second-secret'];
        });

        $this->assertTrue($url3->hasValidSignature($firstRequest));
        $this->assertTrue($url3->hasValidSignature($secondRequest));
    }

    public function testMissingNamedRouteResolution()
    {
        $url = new UrlGenerator(
            new RouteCollection,
            Request::create('http://www.foo.com/')
        );

        $url->resolveMissingNamedRoutesUsing(fn ($name, $parameters, $absolute) => 'test-url');

        $this->assertSame('test-url', $url->route('foo'));
    }
}

class RoutableInterfaceStub implements UrlRoutable
{
    public $key;
    public $slug = 'test-slug';

    public function getRouteKey()
    {
        return $this->{$this->getRouteKeyName()};
    }

    public function getRouteKeyName()
    {
        return 'key';
    }

    public function resolveRouteBinding($routeKey, $field = null)
    {
        //
    }

    public function resolveChildRouteBinding($childType, $routeKey, $field = null)
    {
        //
    }
}

class InvokableActionStub
{
    public function __invoke()
    {
        return 'hello';
    }
}

class RoutingUrlGeneratorTestUser extends Model
{
    protected $fillable = ['uuid'];
}

Function Calls

None

Variables

None

Stats

MD5 be82e9fd3e9b3d7a386b474d7ab2ef8b
Eval Count 0
Decode Time 155 ms