Skip to content

Path matching

Greg Bowler edited this page Apr 14, 2026 · 1 revision

The callback router decides which route has matched. PathMatcher helps us decide which files belong to that route.

This is the layer that WebEngine uses to map request paths to page logic and page view files on disk, but applies to any application's usage.

PathMatcher

PathMatcher scans a directory tree and returns file paths that match a request URI.

On its own, it only walks the filesystem and filters by extension. The actual matching rules come from filter callbacks that we add with addFilter().

use GT\Routing\Path\PathMatcher;

$matcher = new PathMatcher("page");
$matcher->addFilter(function(
	string $filePath,
	string $uriPath,
	string $baseDir
):bool {
	// return true when this file belongs to the request
});

findForUriPath() then returns the matching files:

$matches = $matcher->findForUriPath("/shop/phones", "page", "php", "html");

File matching helpers

The repository provides three important helper types for building those filters.

BasicFileMatch

BasicFileMatch handles direct path-to-file matching.

Examples:

  • /about matches page/about.html
  • /blog matches page/blog/index.html
  • /shop/cakes/chocolate matches page/shop/@category/@item.html

It also takes sibling files into account so that dynamic placeholders do not swallow real files. For example, if both page/request/@request-id.html and page/request/secrets.html exist, the URI /request/secrets matches the concrete file rather than the dynamic placeholder.

MagicFileMatch

MagicFileMatch recognises shared wrapper files that apply to a request because of where they sit in the directory tree.

The recognised magic names are:

  • _common
  • _header
  • _footer

So a request for /shop/item can legitimately include:

  • page/_header.html
  • page/shop/_common.php
  • page/shop/item.html
  • page/_footer.html

DirectoryExpander

DirectoryExpander is the low-level iterator used by PathMatcher to walk a directory tree recursively.

Most applications will not use it directly, but it can be swapped in for testing or custom directory behaviour.

Typical filter setup

The repository's example project uses both basic and magic matching:

$pathMatcher->addFilter(function(string $filePath, string $uriPath, string $baseDir):bool {
	$basicFileMatch = new BasicFileMatch($filePath, $baseDir);
	if($basicFileMatch->matches($uriPath)) {
		return true;
	}

	$magicFileMatch = new MagicFileMatch($filePath, $baseDir);
	return $magicFileMatch->matches($uriPath);
});

Ordering

PathMatcher returns matching paths in directory-depth order. Applications often perform an additional sort before dispatching so that wrappers such as headers and footers are rendered in the correct place.


When dynamic placeholders are involved, we usually want to read the actual URI values back out. That is what dynamic path mapping covers.

Clone this wiki locally