northrook/pathfinder

Resolve paths for files and directories at runtime using predefined key-value pairs

Maintainers

Package info

codeberg.org/northrook/pathfinder

Issues

pkg:composer/northrook/pathfinder

Transparency log

Statistics

Installs: 356

Dependents: 11

Suggesters: 0

dev-main 2026-07-21 15:45 UTC

This package is auto-updated.

Last update: 2026-07-21 16:54:06 UTC


README

Resolves configured parameter references into typed filesystem paths (Path) and URLs (Url).

Implements Northrook\Contracts\Interfaces\PathfinderInterface.

Install

composer require northrook/pathfinder

Requires PHP 8.4+, northrook/core-contracts, and northrook/php-filesystem.

Quick start

use Northrook\Pathfinder;

$pathfinder = new Pathfinder([
    'project.dir' => '/srv/app',
    'url.base'    => 'https://example.test',

    'path.cache'  => '{project.dir}/var/cache',
    'url.assets'  => '{url.base}/assets',
]);

$pathfinder->getPath('{path.cache}/items.json'); // Path → /srv/app/var/cache/items.json
$pathfinder->getUrl('{url.assets}/app.css');     // Url  → https://example.test/assets/app.css
$pathfinder->getPath('robots.txt');              // Path → robots.txt (passthrough)
$pathfinder->getUrl('resources/icon.svg');       // Url  → resources/icon.svg (passthrough)

References

FormMeaning
{key}Expanded parameter value
{key}/relative/suffixValue + joined suffix (URL suffixes insert before ? / #)
{key}/…/{other}Leading key joined as above; further {…} in the suffix expanded
…/{key}/…Any {key} in a non-leading form expanded left-to-right
Bare / absolute / URI (no {…})Passed through unchanged, then type-checked

Parameters always use braces. A bare dotted name like path.cache is a literal string — not a parameter lookup. There is no implicit join onto project.dir or url.base.

Parameter values may contain any number of {nested.key} placeholders (and literal %). Nested unknown keys inside configured values throw; unknown keys at the call site (any placeholder in the reference) return null.

Path vs URL

CallResolved shape is a URLResolved shape is a filesystem path
getPathInvalidArgumentExceptionPath
getUrlUrlInvalidArgumentException

“Filesystem path” here means Windows drive / UNC shapes (C:\…, \\server\share). POSIX absolute strings (/assets/…) are path-absolute URIs: getUrl preserves them; getPath accepts them as filesystem paths.

Non-existent filesystem targets may still yield a Path — existence is checked on the object (exists(), etc.).

Null vs throw

OutcomeWhen
nullMissing / unresolvable reference (unknown {key}, empty string)
ThrowCycles, empty/{} or invalid placeholders, unbalanced {, wrong {key} remainder, path/URL shape mismatch

Url mutators (with*, query helpers, append) also throw on invalid proposed state — the instance is left unchanged (validate-then-commit).

Constructor

use Northrook\Pathfinder\PathfinderConfig;

new Pathfinder(
    array $parameters = [],
    ?PathfinderConfig $config = null,
    ?FilesystemInterface $filesystem = null,
    ?CurlInterface $curl = null,     // required for Url::probe / fetch / download
    ?LoggerInterface $logger = null,
);
new PathfinderConfig(
    bool $preload = false,              // call preload() in the constructor
    bool|string $useCache = false,      // false = off; true = {cacheParameter} or Contracts::cache('pathfinder.cache'); string = path
    bool $commitOnDestruct = true,
    string $cacheParameter = 'path.pathfinder_cache',
);

Defaults live on PathfinderConfig::DEFAULTS and can be passed (or merged) into PathfinderConfig::from().

Construction is light unless $preload is true — the cache dump is not loaded until preload(). Call preload() after Autowire (logger, etc.) when you need the dump hydrated before the first resolve. getPath, getUrl, commit, and bustCache call preload() automatically if it has not run yet.

Cache

Optional PHP dump-file persistence of resolved parameter values (placeholders already expanded). Speeds up repeated boots by skipping placeholder parsing.

  • The dump is keyed by a checksum of the raw constructor map. If that map changes, the dump is ignored and rewritten on the next commit.
  • A malformed or unreadable cache file is logged at critical and treated as empty — boot continues.
  • commit(bool $force = false): bool expands every parameter, then writes when the source checksum changed (or always when $force).
  • bustCache(): bool clears the in-memory resolved map and deletes the dump file (true when a file was removed).
  • When $commitOnDestruct is true and a cache file is configured, __destruct preloads (if needed) and commits; failures there are logged, not thrown. commitOnDestruct is ignored when caching is off.
  • When $useCache is true, the path comes from the parameter named by $cacheParameter (default path.pathfinder_cache), else Contracts::cache('pathfinder.cache').

Parameter key names have no inherent path/URL meaning — prefixes like path. or url. are never trusted; only the resolved string value matters.

Path and Url

getPath / getUrl return concrete Northrook\Pathfinder\Path and Url, implementing the contract interfaces (append, existence/introspection, filesystem I/O on Path; scheme/host/query/with* and HTTP helpers on Url).

HTTP operations on Url require a CurlInterface injection on the Pathfinder (or Url) constructor.

Path

  • mkdir() creates the parent directory of this path (for file writes), not the path itself when it names a directory.
  • glob($pattern) runs patterns relative to this path as a directory base. When the path is an existing file, the base is dirname($path).

Url

Mutations rebuild and re-validate the full URL before committing. Prefer exceptions over malformed strings.

MutationBehavior
withHost('')Throws — host must not be empty
withHost(null) on scheme://…Throws — cannot strip host while keeping a hierarchical scheme
withHost(null) when host already absentNo-op
withHost(null) on protocol-relative //host/…Drops authority (e.g. /path)
Query valuesMust be null, scalar, or Stringable (including list items); otherwise throws
Malformed authority on construct / assignThrows (https:/x, https:///x, http://, …). Empty authority remains allowed for file: (file:///…)

Parameter keys

Validated via is_valid_key with separator . and charset alnum, _, \, -, :.

Rejected in keys: % and / (suffixes are never part of the key). Values must be non-empty after trim.