Jump to content

URL Hook Regular Expression Error [solved]


FireWire
 Share

Recommended Posts

Hey all,

I've been building a new feature on our PW site and the URL hooks are exactly what the doctor ordered. I am developing a RESTful web API to allow external platforms to integrate with our site. The API endpoints are namespaced at /api/v1. I am having trouble making use of the named route parameter using regex.

I have a hook for /api/v1/offline-events that gets all Offline Event pages. The next route to be defined is /api/v1/offline-events/{event ID}. The event ID is using a custom string (not the Page ID) that is a 15 character alphanumeric string like this: E4LxQRXZadgjstw. However when I use a PCRE compliant regular expression (tested on regexr.com) I get an error.

Here is my hook code for reference and the error produced:

<?php namespace ProcessWire;

$wire->addHook('/api/v1/offline-events/{eventId:#(?=.{15}$)([A-Za-z0-9])\w+#}/?', function($e) {
 // ommitted for brevity
});

// Error thrown: Warning: preg_match(): Unknown modifier '(' in /wire/core/WireHooks.php on line 1170

I've tried using all delimiters in the documentation (!@#%) but no change in the outcome.

The second question is how do I create a wildcard capture for all 404s that occur after the /api endpoint? Currently it is loading the website 404 page.

Many thanks!

Edited by FireWire
Updated title to note as solved.
Link to comment
Share on other sites

Your regex looks strangely complicated for what you're trying to achieve. I got it working using:

<?php namespace ProcessWire;

$wire->addHook('/api/v1/offline-events/(eventId:[[:alnum:]]{15})', function($e) {
	$e->return = "Hello $e->eventId";
});

As for the 404s, if you're not returning anything it will result in a pageNotFound() call you could hook after to check the url and execute code accordingly:

$wire->addHookAfter('ProcessPageView::pageNotFound', function($e) {
	$url = $e->arguments(1);
	if(strpos($url, "/api") === 0) {
		$e->return = "API 404";
	}
});
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Some follow-up thoughts.

Even though @monollonom had a more elegant Regex string that works, I still wanted to find out if I could make my ugly string work since technically it should have and there might be a case where an alternate isn't possible. I found some curiosities that may help some other people if they run into a similar problem.

Original string:

'/api/v1/offline-events/{eventId:#(?=.{15}$)([A-Za-z0-9])\w+#}/?'

First off, I had to remove the # regex delimiters at the start/end. Then I had to replace the {eventId:regex} curly braces and apply parenthesis (eventId:regex) then it worked with the ugly regex.

New String:

'/api/v1/offline-events/(eventId:[[:alnum:]]{15})/?'

This was a little confusing because in the URL hooks documentation I just noticed that /route/(variable) and /route/{variable} are used interchangeably. The second issue is that the documentation states the following:

Quote

Should you want to go full in to a regular expression, feel free to, by using one of the following characters !@#% as the starting and ending delimiters, and any regular expression in-between

Using any of the !@#% characters at the beginning/end of the regex expression caused it to fail whether using {} or () to surround the route argument.

So long story boring, I'm not sure if the documentation could be clarified or if there's a bug somewhere (or if I'm just reading it all wrong). Documentation I am referring to here for reference.

Something @ryan should review?

Link to comment
Share on other sites

1 hour ago, FireWire said:

This was a little confusing because in the URL hooks documentation I just noticed that /route/(variable) and /route/{variable} are used interchangeably.

It's not exactly the case.

{variable} will return anything matching the route and will populate the value $e->variable accordingly, whereas (variable:value) will make sure `variable` is equal to `value` (which can be a regex) before making it accessible as $e->variable. There's an example where there is /route/(variable1|variable2|variable3) but in this case it will be accessible through $e->arguments(1) and will have to match either of the three values.

1 hour ago, FireWire said:

Using any of the !@#% characters at the beginning/end of the regex expression caused it to fail whether using {} or () to surround the route argument.

At first this confused me as well but re-reading I think we misunderstood what Ryan meant: he's not talking about the regex part of (variable:regex) but rather making the whole hook a regex, as in:

$wire->addHook("#/(event|person)/([[:alnum:]]{15})#", function($e) {
  $type = $e->arguments(1);
  $id = $e->arguments(2);
  return "Looking up data for ID $id of type $type";
});

That's why he mentioned that "...PW converts your match path to a regular expression (if it isn't one already)..."

  • Like 2
Link to comment
Share on other sites

  • FireWire changed the title to URL Hook Regular Expression Error [solved]

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...