mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 16:26:59 +02:00
Update the new path hooks to support $wire->addHook('/foo/{bar}/baz', ...) where {bar} would match any segment and populate it to a $bar variable on the HookEvent. Plus add enforced trailing slash vs. non-trailing slash with redirect, depending on whether your match pattern uses a trailing slash.
This commit is contained in:
@@ -90,14 +90,14 @@ class HookEvent extends WireData {
|
||||
*
|
||||
*/
|
||||
public function arguments($n = null, $value = null) {
|
||||
if(is_null($n)) return $this->arguments;
|
||||
if(!is_null($value)) {
|
||||
if($n === null) return $this->data['arguments'];
|
||||
if($value !== null) {
|
||||
$this->setArgument($n, $value);
|
||||
return $value;
|
||||
}
|
||||
if(isset($this->data['arguments'][$n])) return $this->data['arguments'][$n];
|
||||
if(is_string($n)) return $this->argumentsByName($n);
|
||||
$arguments = $this->arguments;
|
||||
return isset($arguments[$n]) ? $arguments[$n] : null;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +119,7 @@ class HookEvent extends WireData {
|
||||
*/
|
||||
public function argumentsByName($n = '') {
|
||||
|
||||
$arguments = $this->arguments();
|
||||
$arguments = $this->data['arguments'];
|
||||
if(isset($arguments[$n])) return $arguments[$n];
|
||||
|
||||
$names = $this->getArgumentNames();
|
||||
@@ -165,9 +165,7 @@ class HookEvent extends WireData {
|
||||
if($n === false) throw new WireException("Unknown argument name: $n");
|
||||
}
|
||||
|
||||
$arguments = $this->arguments;
|
||||
$arguments[(int)$n] = $value;
|
||||
$this->set('arguments', $arguments);
|
||||
$this->data['arguments'][(int)$n] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@@ -153,6 +153,14 @@ class WireHooks {
|
||||
*/
|
||||
protected $allowPathHooks = true;
|
||||
|
||||
/**
|
||||
* Populated when a path hook requires a redirect
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
*/
|
||||
protected $pathHookRedirect = '';
|
||||
|
||||
/**
|
||||
* @var ProcessWire
|
||||
*
|
||||
@@ -1067,7 +1075,9 @@ class WireHooks {
|
||||
$pathHook = $this->pathHooks[$id];
|
||||
$matchPath = $pathHook['match'];
|
||||
$requestPath = $arguments[0];
|
||||
$slashed = substr($requestPath, -1) === '/' && strlen($requestPath) > 1;
|
||||
$filterFail = false;
|
||||
$regexDelim = ''; // populated only for user-specified regex
|
||||
|
||||
// first pre-filter the requestPath against any words matchPath (filters)
|
||||
foreach($pathHook['filters'] as $filter) {
|
||||
@@ -1080,29 +1090,56 @@ class WireHooks {
|
||||
|
||||
if(strpos('!@#%', $matchPath[0]) !== false) {
|
||||
// already in delimited regex format
|
||||
$regexDelim = $matchPath[0];
|
||||
} else {
|
||||
// needs to be in regex format
|
||||
if(strpos($matchPath, '/') === 0) $matchPath = "^$matchPath";
|
||||
$matchPath = "!$matchPath$!";
|
||||
$matchPath = "#$matchPath$#";
|
||||
}
|
||||
|
||||
|
||||
if(strpos($matchPath, ':') && strpos($matchPath, '(') !== false) {
|
||||
// named arguments converted to named PCRE capture groups
|
||||
$matchPath = preg_replace('!\(([-_a-z0-9]+):!i', '(?P<$1>', $matchPath);
|
||||
// named arguments in format “(name: value)” converted to named PCRE capture groups
|
||||
$matchPath = preg_replace('#\(([-_a-z0-9]+):#i', '(?P<$1>', $matchPath);
|
||||
}
|
||||
|
||||
if(strpos($matchPath, '{') !== false) {
|
||||
// named arguments in format “{name}” converted to named PCRE capture groups
|
||||
// note that the match pattern of any URL segment is assumed for this case
|
||||
$matchPath = preg_replace('#\{([_a-z][-_a-z0-9]*)\}#i', '(?P<$1>[^/]+)', $matchPath);
|
||||
}
|
||||
|
||||
if(!preg_match($matchPath, $requestPath, $matches)) {
|
||||
// if match fails, try again with trailing slash state reversed
|
||||
if(substr($requestPath, -1) === '/') {
|
||||
$requestPath = rtrim($requestPath, '/');
|
||||
if($slashed) {
|
||||
$requestPath2 = rtrim($requestPath, '/');
|
||||
} else {
|
||||
$requestPath .= '/';
|
||||
$requestPath2 = "$requestPath/";
|
||||
}
|
||||
if(!preg_match($matchPath, $requestPath, $matches)) return false;
|
||||
if(!preg_match($matchPath, $requestPath2, $matches)) return false;
|
||||
}
|
||||
|
||||
// check on trailing slash
|
||||
if(strpos($matchPath, '/?') === false) {
|
||||
// either slash or no-slash is required, depending on whether match pattern ends with one
|
||||
$slashRequired = substr(rtrim($pathHook['match'], $regexDelim . '$)+'), -1) === '/';
|
||||
$this->pathHookRedirect = '';
|
||||
if($slashRequired && !$slashed) {
|
||||
// trailing slash required and not present
|
||||
$this->pathHookRedirect = $requestPath . '/';
|
||||
return false;
|
||||
} else if(!$slashRequired && $slashed) {
|
||||
// lack of trailing slash required and one is present
|
||||
$this->pathHookRedirect = rtrim($requestPath, '/');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// success: at this point the requestPath has matched
|
||||
$arguments['path'] = $arguments[0];
|
||||
|
||||
foreach($matches as $key => $value) {
|
||||
if($key !== 0) $arguments[$key] = $value;
|
||||
// populate requested arguments
|
||||
if($key !== 0) $arguments[$key] = $value;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1254,6 +1291,17 @@ class WireHooks {
|
||||
return $this->allowPathHooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return redirect URL required by an applicable path hook, or blank otherwise
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.173
|
||||
*
|
||||
*/
|
||||
public function getPathHookRedirect() {
|
||||
return $this->pathHookRedirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
|
@@ -196,7 +196,7 @@ class ProcessPageView extends Process {
|
||||
|
||||
if(!$this->delayRedirects) {
|
||||
$this->checkProtocol($page);
|
||||
if($this->redirectURL) $this->wire()->session->redirect($this->redirectURL);
|
||||
if($this->redirectURL) $this->redirect($this->redirectURL);
|
||||
}
|
||||
|
||||
$this->wire('page', $page);
|
||||
@@ -205,7 +205,7 @@ class ProcessPageView extends Process {
|
||||
|
||||
if($this->delayRedirects) {
|
||||
$this->checkProtocol($page);
|
||||
if($this->redirectURL) $this->wire()->session->redirect($this->redirectURL);
|
||||
if($this->redirectURL) $this->redirect($this->redirectURL);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -285,8 +285,15 @@ class ProcessPageView extends Process {
|
||||
|
||||
$this->setResponseType(self::responseTypeNoPage);
|
||||
}
|
||||
|
||||
// did a path hook require a redirect for trailing slash (vs non-trailing slash)?
|
||||
$redirect = $hooks->getPathHookRedirect();
|
||||
if($redirect) {
|
||||
$this->redirect($config->urls->root . ltrim($redirect, '/'));
|
||||
}
|
||||
|
||||
$this->pathHooksReturnValue = false; // no longer applicable
|
||||
$this->pathHooksReturnValue = false; // no longer applicable once this line reached
|
||||
$hooks->allowPathHooks(false); // no more path hooks allowed
|
||||
|
||||
if($page && $page->id && $page->id !== $page404->id && $page instanceof Page) {
|
||||
// one of the path hooks set the page
|
||||
@@ -899,7 +906,7 @@ class ProcessPageView extends Process {
|
||||
$config = $this->wire()->config;
|
||||
$disallowIDs = array($config->trashPageID); // don't allow login redirect for these pages
|
||||
$loginRequestURL = $this->redirectURL;
|
||||
$loginPageID = $this->wire()->config->loginPageID;
|
||||
$loginPageID = $config->loginPageID;
|
||||
$requestPage = $page;
|
||||
$session = $this->wire()->session;
|
||||
$input = $this->wire()->input;
|
||||
@@ -1107,7 +1114,7 @@ class ProcessPageView extends Process {
|
||||
if(!$page->secureFiles()) {
|
||||
// if file is not secured, redirect to it
|
||||
// (potentially deprecated, only necessary for method 2 in checkRequestFile)
|
||||
$this->wire()->session->redirect($page->filesManager->url() . $basename);
|
||||
$this->redirect($page->filesManager->url() . $basename);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1199,6 +1206,23 @@ class ProcessPageView extends Process {
|
||||
$n++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform redirect
|
||||
*
|
||||
* @param string $url
|
||||
* @param bool $permanent
|
||||
*
|
||||
*/
|
||||
protected function redirect($url, $permanent = true) {
|
||||
$session = $this->wire()->session;
|
||||
$this->setResponseType(self::responseTypeRedirect);
|
||||
if($permanent) {
|
||||
$session->redirect($url);
|
||||
} else {
|
||||
$session->location($url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the response type for this request, as one of the responseType constants
|
||||
*
|
||||
|
Reference in New Issue
Block a user