78 private $patterns = [];
90 protected function doAdd(
$path, $params, $options, $key =
null ) {
92 if (
$path[0] !==
'/' ) {
96 if ( !isset( $options[
'strict'] ) || !$options[
'strict'] ) {
98 if ( strpos(
$path,
'$1' ) ===
false ) {
99 if ( substr(
$path, -1 ) !==
'/' ) {
108 if ( !isset( $params[
'title'] ) && strpos(
$path,
'$1' ) !==
false ) {
109 $params[
'title'] =
'$1';
112 if ( isset( $params[
'title'] ) && $params[
'title'] ===
false ) {
113 unset( $params[
'title'] );
118 foreach ( $params as $paramName => $paramData ) {
119 if ( is_string( $paramData ) ) {
120 if ( preg_match(
'/\$(\d+|key)/u', $paramData ) ) {
121 $paramArrKey =
'pattern';
125 $paramArrKey =
'value';
127 $params[$paramName] = [
128 $paramArrKey => $paramData
135 foreach ( $options as $optionName => $optionData ) {
136 if ( preg_match(
'/^\$\d+$/u', $optionName ) && !is_array( $optionData ) ) {
137 $options[$optionName] = [ $optionData ];
144 'options' => $options,
147 $pattern->weight = self::makeWeight( $pattern );
148 $this->patterns[] = $pattern;
158 public function add(
$path, $params = [], $options = [] ) {
159 if ( is_array(
$path ) ) {
160 foreach (
$path as $key => $onePath ) {
161 $this->
doAdd( $onePath, $params, $options, $key );
176 if (
$path && !preg_match(
'/^(https?:\/\/|\/)/',
$path ) ) {
179 "If you use a relative URL for \$$varName, it must start " .
180 'with a slash (<code>/</code>).<br><br>See ' .
181 "<a href=\"https://www.mediawiki.org/wiki/Manual:\$$varName\">" .
182 "https://www.mediawiki.org/wiki/Manual:\$$varName</a>."
195 $options[
'strict'] =
true;
196 $this->
add(
$path, $params, $options );
205 foreach ( $this->patterns as $key => $pattern ) {
206 $weights[$key] = $pattern->weight;
208 array_multisort( $weights, SORT_DESC, SORT_NUMERIC, $this->patterns );
216 # Start with a weight of 0
220 $path = explode(
'/', $pattern->path );
222 # For each level of the path
223 foreach (
$path as $piece ) {
224 if ( preg_match(
'/^\$(\d+|key)$/u', $piece ) ) {
225 # For a piece that is only a $1 variable add 1 points of weight
227 } elseif ( preg_match(
'/\$(\d+|key)/u', $piece ) ) {
228 # For a piece that simply contains a $1 variable add 2 points of weight
231 # For a solid piece add a full 3 points of weight
236 foreach ( $pattern->options as $key => $option ) {
237 if ( preg_match(
'/^\$\d+$/u', $key ) ) {
238 # Add 0.5 for restrictions to values
239 # This way given two separate "/$2/$1" patterns the
240 # one with a limited set of $2 values will dominate
241 # the one that'll match more loosely
284 foreach ( $this->patterns as $pattern ) {
300 $regexp = preg_quote( $pattern->path,
'#' );
302 $regexp = preg_replace(
'#\\\\\$1#u',
'(?P<par1>.*)', $regexp );
304 $regexp = preg_replace(
'#\\\\\$(\d+)#u',
'(?P<par$1>.+?)', $regexp );
305 $regexp =
"#^{$regexp}$#";
311 if ( preg_match( $regexp,
$path, $m ) ) {
314 foreach ( $pattern->options as $key => $option ) {
315 if ( preg_match(
'/^\$\d+$/u', $key ) ) {
316 $n = intval( substr( $key, 1 ) );
317 $value = rawurldecode( $m[
"par{$n}"] );
318 if ( !in_array( $value, $option ) ) {
327 foreach ( $m as $matchKey => $matchValue ) {
328 if ( preg_match(
'/^par\d+$/u', $matchKey ) ) {
329 $n = intval( substr( $matchKey, 3 ) );
330 $data[
'$' . $n] = rawurldecode( $matchValue );
334 if ( isset( $pattern->key ) ) {
335 $data[
'$key'] = $pattern->key;
339 foreach ( $pattern->params as $paramName => $paramData ) {
343 if ( preg_match(
'/^data:/u', $paramName ) ) {
345 $key = substr( $paramName, 5 );
351 if ( isset( $paramData[
'value'] ) ) {
353 $value = $paramData[
'value'];
354 } elseif ( isset( $paramData[
'pattern'] ) ) {
356 $value = self::expandParamValue( $m, $pattern->key ??
null,
357 $paramData[
'pattern'] );
358 if ( $value ===
false ) {
366 $data[$key] = $value;
373 if ( isset( $pattern->options[
'callback'] ) ) {
374 call_user_func_array( $pattern->options[
'callback'], [ &
$matches, $data ] );
395 $replacer =
static function ( $m ) use ( $pathMatches, $key, &$error ) {
396 if ( $m[1] ==
"key" ) {
397 if ( $key ===
null ) {
406 if ( !isset( $pathMatches[
"par$d"] ) ) {
412 return rawurldecode( $pathMatches[
"par$d"] );
416 $value = preg_replace_callback(
'/\$(\d+|key)/u', $replacer, $value );
431 if ( !$actionPaths ) {
436 if ( !isset( $actionPaths[
'view'] ) ) {
437 $actionPaths[
'view'] = $articlePath;
wfRemoveDotSegments( $urlPath)
Remove all dot-segments in the provided URL path.
Abort the web request with a custom HTML string that will represent the entire response.
static getActionPaths(array $actionPaths, $articlePath)
sortByWeight()
Protected helper to re-sort our patterns so that the most specific (most heavily weighted) patterns a...
static extractTitle( $path, $pattern)
add( $path, $params=[], $options=[])
Add a new path pattern to the path router.
static expandParamValue( $pathMatches, $key, $value)
Replace $key etc.
addStrict( $path, $params=[], $options=[])
Add a new path pattern to the path router with the strict option on.
static makeWeight( $pattern)
parse( $path)
Parse a path and return the query matches for the path.
doAdd( $path, $params, $options, $key=null)
Protected helper to do the actual bulk work of adding a single pattern.
internalParse( $path)
Match a path against each defined pattern.
validateRoute( $path, $varName)