1

This is my code:

class Route
{
     public function createURL($pattern, array $params = array())
     {
          $url = $pattern;
          if ($params && preg_match_all('#([^/\(\)]*)?#', $pattern, $args)) {
                $args = $args[1];
                foreach ($params as $value) {
                    foreach ($args as $key) {
                        if ($key && preg_match('/'. $key .'/', $value)) {
                            $url = preg_replace('/'. $key .'/', $value, $url, 1);
                        }
                    }
                }
          }
          return $url;
     }
}

now, i call the method:

$r = new Route();
$r->createURL('/user/[0-9]+', array(3));

It return result: '/user/[3-9]+'

I want it return result: '/user/3'

Somebody can help me?

taratula
  • 497
  • 1
  • 5
  • 11

2 Answers2

1

The preg_replace should be changed to:

$url = str_replace($key, $value, $url);

The preg_replace was treating the [0-9]+ as a regular expression which means match any number between 0 to 9.

Then you had that in your url, where it was being treated as a string, so it was matching the 0 in the url and replacing it with the number.

Antony D'Andrea
  • 991
  • 1
  • 16
  • 35
0

Your code is really hard to debug...

I've made it to work by replacing:

$url = preg_replace('/'. $key .'/', $value, $url, 1);

by this:

$url = str_replace($key, $value, $url);

You will have to find a way to only replace it once.

Something like this:

$pieces = explode($key);
$pieces[1] .= $pieces[0].$value;
$url = implode($key, $pieces);

MAY work for you!

Disclainer: Although Antony D'Andrea said it first to use the str_replace, I've provided an alternative method. I didn't read his answer and didn't paid attention to it's content.


Offtopic:

I've used your brilliant idea and rewrote it like this:

class Route
{
    static function createURL($pattern, array $params = array())
    {

        $func = function($matches) use ($params) {

            if (preg_match('@^([a-z]+):(.*)$@', $matches[1], $patterns) && preg_match('@^'.$patterns[2].'$@', $params[$patterns[1]]) )
                return $params[$patterns[1]];
            else return '';

        };

        return preg_replace_callback('@%\\[([a-z]+:(?:[^]]|\\][^%])*)\\]%@', $func, $pattern);

    }
}

echo Route::createURL('/users/%[id:\d+]%/',array('id'=>5));

It's working as intended, but you can't use [] inside the pattern, for now.
Using the regex @%\\[([a-z]+:(?:[^]]|\\][^%])*)\\]%@ instead of @%\\[([a-z]+:(?:[^]]|\\\])*)\\]%@ seems to overcome this.

To make the coding easier, I've decided to do something different than you.

It looks for something between %[ ... ]%, and expects something like key:pattern inside.

Then, on your array, you provide a value matching that key. If none is found or the pattern doesn't match the value, tries to remove it.

The aproach using preg_replace_callback() has the advantage of allowing you to process the match the way you wish and you can be sure that you are replacing it only once.

Ismael Miguel
  • 4,185
  • 1
  • 31
  • 42