Skip to content
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

Bug: Missing argument in route when using url_to or route_to with regex routes #9250

Open
bgeneto opened this issue Nov 2, 2024 · 4 comments

Comments

@bgeneto
Copy link

bgeneto commented Nov 2, 2024

PHP Version

8.3

CodeIgniter4 Version

CodeIgniter 4.5.5

CodeIgniter4 Installation Method

Composer (using codeigniter4/appstarter)

Which operating systems have you tested for this bug?

Debian 12

Which server did you use?

fpm-fcgi

Database

N/A

What happened?

The following route definition works fine as long as you don't use url_to or route_to to refer to it:

$routes->get('/test(/(:any))?', 'Test::direct/$1', ['as' => 'test']);

Linking as below works:

<a href="/test">No parameter</a>
<a href="/test/param1">1 parameter</a>
<a href="/test/param1/param2">2 parameters</a>

But using both url_to or route_to fails:

<a href="<?= url_to('test') ?>">No parameter</a>
<a href="<?= url_to('test', 'param1') ?>">1 parameter</a>
<a href="<?= url_to('test', 'param1', 'param2') ?>">2 parameters</a>

Steps to Reproduce

  1. Add the new routes in Routes.php:
$routes->get('/test(/(:any))?', 'Test::direct/$1', ['as' => 'test']);
$routes->get('/test_urlto(/(:any))?', 'Test::urlto/$1', ['as' => 'urlto']);
$routes->get('/test_routeto(/(:any))?', 'Test::routeto/$1', ['as' => 'routeto']);
  1. Create the Test controller:
<?php

namespace App\Controllers;

class Test extends BaseController
{
    public function direct(...$params): string
    {
        return view('test', ['params' => $params]);
    }

    public function urlto(...$params): string
    {
        return view('test_urlto', ['params' => $params]);
    }

    public function routeto(...$params): string
    {
        return view('test_routeto', ['params' => $params]);
    }
}
  1. Create the respective views:

A) direct view

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Test</title>
</head>
<body>
	<h1>Testing CI4 Routing with Parameters</h1>

	<h2>Test using string directly</h2>
	<ul>
		<li>
			<a href="/test">No parameter</a>
		</li>
		<li>
			<a href="/test/param1">1 parameter</a>
		</li>
		<li>
			<a href="/test/param1/param2">2 parameters</a>
		</li>
		<li>
			<a href="/test/param1/param2/param3">3 parameters</a>
		</li>
	</ul>
	<h3>Passed Parameters</h3>
	<ul>
		<?php foreach ($params as $param) : ?>
			<li><?= $param ?></li>
		<?php endforeach; ?>
</body>
</html>

B) view using url_to

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>Test</title>
</head>

<body>
	<h1>Testing CI4 Routing with Parameters</h1>
	<h2>Test using <code>url_to</code></h2>
	<ul>
		<li>
			<a href="<?= url_to('urlto') ?>">No parameter</a>
		</li>
		<li>
			<a href="<?= url_to('urlto', 'param1') ?>">1 parameter</a>
		</li>
		<li>
			<a href="<?= url_to('urlto', 'param1', 'param2') ?>">2 parameters</a>
		</li>
		<li>
			<a href="<?= url_to('urlto', 'param1', 'param2', 'param3') ?>">3 parameters</a>
		</li>
	</ul>

	<h3>Passed Parameters</h3>
	<ul>
		<?php foreach ($params as $param) : ?>
			<li><?= $param ?></li>
		<?php endforeach; ?>
</body>
</html>
  1. Access those views at: /test and /test_urlto

Expected Output

No InvalidArgumentException, Missing argument for "(/(:any)" in route "test_urlto(/(:any))?" while using both url_to and route_to .

Anything else?

  • One can try it with public bool $multipleSegmentsOneParam = true; or public bool $multipleSegmentsOneParam = false; in Routing.php. The error is the same in both situations (just the parameters are treated differently, as expected).

  • One can also use a regex like '(/(.+))?' instead of (/(:any))? . The error remains.

@bgeneto bgeneto added the bug Verified issues on the current code behavior or pull requests that will fix them label Nov 2, 2024
@bgeneto bgeneto changed the title Bug: Missing argument in route Bug: Missing argument in route when using url_to or route_to with regex routes Nov 2, 2024
@michalsn
Copy link
Member

michalsn commented Nov 4, 2024

Using the (:any) placeholder in the route does not mean that the parameter value is optional. You must always put a value.

You can use: url_to('urlto', ''), although in general I don't think it will behave as you expect - the route will not be found.

In any case, this is not a bug.

@michalsn michalsn removed the bug Verified issues on the current code behavior or pull requests that will fix them label Nov 4, 2024
@neznaika0
Copy link
Contributor

I've been trying to use regex in routes for a long time. It failed.
Try to create several routes to get rid of the "?".

$routes->get('/test/(:any)', 'Test::direct/$1', ['as' => 'test_ext']);
$routes->get('/test', 'Test::direct/$1', ['as' => 'test']);

To work, you need to specify a string for :any and not an array
url_to('urlto', 'param1/param2/param3') not url_to('urlto', 'param1', 'param2', 'param3')

@bgeneto
Copy link
Author

bgeneto commented Nov 4, 2024

Using the (:any) placeholder in the route does not mean that the parameter value is optional. You must always put a value.

You can use: url_to('urlto', ''), although in general I don't think it will behave as you expect - the route will not be found.

In any case, this is not a bug.

I couldn't disagree more... Because I'm using regular expressions (note the ? char) with (:any). And it also fails for '(/(.+))?' as mentioned in this carefully written bug report.

And, by running the examples, one can see that routing mechanism is working flawlessly with or without arguments. Problem arises when using url_to. For me this is, at least, a framework inconsistency or missing feature (if not a bug). 😥

@bgeneto
Copy link
Author

bgeneto commented Nov 4, 2024

I've been trying to use regex in routes for a long time. It failed. Try to create several routes to get rid of the "?".

$routes->get('/test/(:any)', 'Test::direct/$1', ['as' => 'test_ext']);
$routes->get('/test', 'Test::direct/$1', ['as' => 'test']);

To work, you need to specify a string for :any and not an array url_to('urlto', 'param1/param2/param3') not url_to('urlto', 'param1', 'param2', 'param3')

Yeah! Unfortunately every time this subject comes up it is treated as a feature, read the docs etc....

So I kindly suggest to remove the partial regex support from routes (a great loss since routing works fine with regex, only additional framework related functions like url_to or route_to do not support it).

We could also explicitly says in the docs not to use the special '?' char in routes because of missing support.

As I carefully showed in this bug report examples, regex with '?' works with or without arguments. Problem is framework support from related helper functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants