chore: fix PSR-12 coding style violations using PHPCBF
Some checks are pending
CI / build (push) Waiting to run

This commit is contained in:
Funky Waddle 2026-02-15 13:15:55 -06:00
parent 41c8c9457c
commit 83c18bd82d
12 changed files with 338 additions and 116 deletions

View file

@ -21,7 +21,7 @@ class ListRoutesCommand
$json = in_array('--json', $argv); $json = in_array('--json', $argv);
$routes = $router->getRoutes(); $routes = $router->getRoutes();
$output = []; $output = [];
foreach ($routes as $route) { foreach ($routes as $route) {
$output[] = $route->toArray(); $output[] = $route->toArray();
} }
@ -32,10 +32,11 @@ class ListRoutesCommand
printf("%-10s | %-30s | %-20s | %-30s\n", "Method", "Path", "Name", "Handler"); printf("%-10s | %-30s | %-20s | %-30s\n", "Method", "Path", "Name", "Handler");
echo str_repeat("-", 100) . PHP_EOL; echo str_repeat("-", 100) . PHP_EOL;
foreach ($output as $r) { foreach ($output as $r) {
printf("%-10s | %-30s | %-20s | %-30s\n", printf(
$r['method'], "%-10s | %-30s | %-20s | %-30s\n",
$r['path'], $r['method'],
$r['name'] ?? '', $r['path'],
$r['name'] ?? '',
is_string($r['handler']) ? $r['handler'] : 'Closure' is_string($r['handler']) ? $r['handler'] : 'Closure'
); );
} }

View file

@ -25,76 +25,261 @@ class TestRouteCommand
$host = 'localhost'; // Default $host = 'localhost'; // Default
// PSR-7 mock request // PSR-7 mock request
$uri = new class($path, $host) implements UriInterface { $uri = new class ($path, $host) implements UriInterface {
public function __construct(private $path, private $host) {} public function __construct(private $path, private $host)
public function getScheme(): string { return 'http'; } {
public function getAuthority(): string { return $this->host; } }
public function getUserInfo(): string { return ''; } public function getScheme(): string
public function getHost(): string { return $this->host; } {
public function getPort(): ?int { return null; } return 'http';
public function getPath(): string { return $this->path; } }
public function getQuery(): string { return ''; } public function getAuthority(): string
public function getFragment(): string { return ''; } {
public function withScheme($scheme): UriInterface { return $this; } return $this->host;
public function withUserInfo($user, $password = null): UriInterface { return $this; } }
public function withHost($host): UriInterface { return $this; } public function getUserInfo(): string
public function withPort($port): UriInterface { return $this; } {
public function withPath($path): UriInterface { return $this; } return '';
public function withQuery($query): UriInterface { return $this; } }
public function withFragment($fragment): UriInterface { return $this; } public function getHost(): string
public function __toString(): string { return "http://{$this->host}{$this->path}"; } {
return $this->host;
}
public function getPort(): ?int
{
return null;
}
public function getPath(): string
{
return $this->path;
}
public function getQuery(): string
{
return '';
}
public function getFragment(): string
{
return '';
}
public function withScheme($scheme): UriInterface
{
return $this;
}
public function withUserInfo($user, $password = null): UriInterface
{
return $this;
}
public function withHost($host): UriInterface
{
return $this;
}
public function withPort($port): UriInterface
{
return $this;
}
public function withPath($path): UriInterface
{
return $this;
}
public function withQuery($query): UriInterface
{
return $this;
}
public function withFragment($fragment): UriInterface
{
return $this;
}
public function __toString(): string
{
return "http://{$this->host}{$this->path}";
}
}; };
$request = new class($method, $uri) implements ServerRequestInterface { $request = new class ($method, $uri) implements ServerRequestInterface {
public function __construct(private $method, private $uri) {} public function __construct(private $method, private $uri)
public function getProtocolVersion(): string { return '1.1'; } {
public function withProtocolVersion($version): ServerRequestInterface { return $this; } }
public function getHeaders(): array { return []; } public function getProtocolVersion(): string
public function hasHeader($name): bool { return false; } {
public function getHeader($name): array { return []; } return '1.1';
public function getHeaderLine($name): string { return ''; } }
public function withHeader($name, $value): ServerRequestInterface { return $this; } public function withProtocolVersion($version): ServerRequestInterface
public function withAddedHeader($name, $value): ServerRequestInterface { return $this; } {
public function withoutHeader($name): ServerRequestInterface { return $this; } return $this;
public function getBody(): \Psr\Http\Message\StreamInterface { return $this->createMockStream(); } }
public function withBody(\Psr\Http\Message\StreamInterface $body): ServerRequestInterface { return $this; } public function getHeaders(): array
public function getRequestTarget(): string { return $this->uri->getPath(); } {
public function withRequestTarget($requestTarget): ServerRequestInterface { return $this; } return [];
public function getMethod(): string { return $this->method; } }
public function withMethod($method): ServerRequestInterface { return $this; } public function hasHeader($name): bool
public function getUri(): UriInterface { return $this->uri; } {
public function withUri(UriInterface $uri, $preserveHost = false): ServerRequestInterface { return $this; } return false;
public function getServerParams(): array { return []; } }
public function getCookieParams(): array { return []; } public function getHeader($name): array
public function withCookieParams(array $cookies): ServerRequestInterface { return $this; } {
public function getQueryParams(): array { return []; } return [];
public function withQueryParams(array $query): ServerRequestInterface { return $this; } }
public function getUploadedFiles(): array { return []; } public function getHeaderLine($name): string
public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface { return $this; } {
public function getParsedBody(): null|array|object { return null; } return '';
public function withParsedBody($data): ServerRequestInterface { return $this; } }
public function getAttributes(): array { return []; } public function withHeader($name, $value): ServerRequestInterface
public function getAttribute($name, $default = null): mixed { return $default; } {
public function withAttribute($name, $value): ServerRequestInterface { return $this; } return $this;
public function withoutAttribute($name): ServerRequestInterface { return $this; } }
public function withAddedHeader($name, $value): ServerRequestInterface
{
return $this;
}
public function withoutHeader($name): ServerRequestInterface
{
return $this;
}
public function getBody(): \Psr\Http\Message\StreamInterface
{
return $this->createMockStream();
}
public function withBody(\Psr\Http\Message\StreamInterface $body): ServerRequestInterface
{
return $this;
}
public function getRequestTarget(): string
{
return $this->uri->getPath();
}
public function withRequestTarget($requestTarget): ServerRequestInterface
{
return $this;
}
public function getMethod(): string
{
return $this->method;
}
public function withMethod($method): ServerRequestInterface
{
return $this;
}
public function getUri(): UriInterface
{
return $this->uri;
}
public function withUri(UriInterface $uri, $preserveHost = false): ServerRequestInterface
{
return $this;
}
public function getServerParams(): array
{
return [];
}
public function getCookieParams(): array
{
return [];
}
public function withCookieParams(array $cookies): ServerRequestInterface
{
return $this;
}
public function getQueryParams(): array
{
return [];
}
public function withQueryParams(array $query): ServerRequestInterface
{
return $this;
}
public function getUploadedFiles(): array
{
return [];
}
public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface
{
return $this;
}
public function getParsedBody(): null|array|object
{
return null;
}
public function withParsedBody($data): ServerRequestInterface
{
return $this;
}
public function getAttributes(): array
{
return [];
}
public function getAttribute($name, $default = null): mixed
{
return $default;
}
public function withAttribute($name, $value): ServerRequestInterface
{
return $this;
}
public function withoutAttribute($name): ServerRequestInterface
{
return $this;
}
private function createMockStream() { private function createMockStream()
{
return new class implements \Psr\Http\Message\StreamInterface { return new class implements \Psr\Http\Message\StreamInterface {
public function __toString(): string { return ''; } public function __toString(): string
public function close(): void {} {
public function detach() { return null; } return '';
public function getSize(): ?int { return 0; } }
public function tell(): int { return 0; } public function close(): void
public function eof(): bool { return true; } {
public function isSeekable(): bool { return false; } }
public function seek($offset, $whence = SEEK_SET): void {} public function detach()
public function rewind(): void {} {
public function isWritable(): bool { return false; } return null;
public function write($string): int { return 0; } }
public function isReadable(): bool { return true; } public function getSize(): ?int
public function read($length): string { return ''; } {
public function getContents(): string { return ''; } return 0;
public function getMetadata($key = null) { return $key ? null : []; } }
public function tell(): int
{
return 0;
}
public function eof(): bool
{
return true;
}
public function isSeekable(): bool
{
return false;
}
public function seek($offset, $whence = SEEK_SET): void
{
}
public function rewind(): void
{
}
public function isWritable(): bool
{
return false;
}
public function write($string): int
{
return 0;
}
public function isReadable(): bool
{
return true;
}
public function read($length): string
{
return '';
}
public function getContents(): string
{
return '';
}
public function getMetadata($key = null)
{
return $key ? null : [];
}
}; };
} }
}; };

View file

@ -23,7 +23,8 @@ class Config implements ArrayAccess, IteratorAggregate
*/ */
public function __construct( public function __construct(
private array $options private array $options
) {} ) {
}
/** /**
* Retrieves a configuration value by key. * Retrieves a configuration value by key.
@ -166,4 +167,4 @@ class Config implements ArrayAccess, IteratorAggregate
{ {
return new \ArrayIterator($this->options); return new \ArrayIterator($this->options);
} }
} }

View file

@ -7,4 +7,4 @@ namespace Atlas\Exception;
*/ */
class MissingConfigurationException extends \RuntimeException class MissingConfigurationException extends \RuntimeException
{ {
} }

View file

@ -7,4 +7,4 @@ namespace Atlas\Exception;
*/ */
class RouteValidationException extends \RuntimeException class RouteValidationException extends \RuntimeException
{ {
} }

View file

@ -12,7 +12,8 @@ class MatchResult implements \JsonSerializable
private readonly RouteDefinition|null $route = null, private readonly RouteDefinition|null $route = null,
private readonly array $parameters = [], private readonly array $parameters = [],
private readonly array $diagnostics = [] private readonly array $diagnostics = []
) {} ) {
}
public function isFound(): bool public function isFound(): bool
{ {

View file

@ -19,7 +19,8 @@ class ModuleLoader
public function __construct( public function __construct(
private readonly Config $config, private readonly Config $config,
private readonly Router|RouteGroup $target private readonly Router|RouteGroup $target
) {} ) {
}
/** /**
* Loads routes for a given module or modules. * Loads routes for a given module or modules.
@ -63,7 +64,7 @@ class ModuleLoader
private function loadModuleRoutes(string $routesFile, string|null $prefix = null, string|null $moduleName = null): void private function loadModuleRoutes(string $routesFile, string|null $prefix = null, string|null $moduleName = null): void
{ {
$moduleRoutes = require $routesFile; $moduleRoutes = require $routesFile;
$options = []; $options = [];
if ($prefix) { if ($prefix) {
$options['prefix'] = $prefix; $options['prefix'] = $prefix;

View file

@ -25,7 +25,8 @@ final class Route
private readonly string $method, private readonly string $method,
private readonly string $path, private readonly string $path,
private readonly mixed $handler private readonly mixed $handler
) {} ) {
}
/** /**
* Gets the HTTP method of this route. * Gets the HTTP method of this route.
@ -56,4 +57,4 @@ final class Route
{ {
return $this->handler; return $this->handler;
} }
} }

View file

@ -65,13 +65,29 @@ class RouteDefinition implements \JsonSerializable, \Serializable
private array $defaults = [], private array $defaults = [],
private string|null $module = null, private string|null $module = null,
private array $attributes = [] private array $attributes = []
) {} ) {
}
public function getMethod(): string { return $this->method; } public function getMethod(): string
public function getPattern(): string { return $this->pattern; } {
public function getPath(): string { return $this->path; } return $this->method;
public function getHandler(): mixed { return $this->handler; } }
public function getName(): ?string { return $this->name; } public function getPattern(): string
{
return $this->pattern;
}
public function getPath(): string
{
return $this->path;
}
public function getHandler(): mixed
{
return $this->handler;
}
public function getName(): ?string
{
return $this->name;
}
public function name(string $name): self public function name(string $name): self
{ {
@ -79,7 +95,10 @@ class RouteDefinition implements \JsonSerializable, \Serializable
return $this; return $this;
} }
public function getMiddleware(): array { return $this->middleware; } public function getMiddleware(): array
{
return $this->middleware;
}
public function middleware(string|array $middleware): self public function middleware(string|array $middleware): self
{ {
@ -91,7 +110,10 @@ class RouteDefinition implements \JsonSerializable, \Serializable
return $this; return $this;
} }
public function getValidation(): array { return $this->validation; } public function getValidation(): array
{
return $this->validation;
}
public function valid(array|string $param, array|string $rules = []): self public function valid(array|string $param, array|string $rules = []): self
{ {
@ -105,7 +127,10 @@ class RouteDefinition implements \JsonSerializable, \Serializable
return $this; return $this;
} }
public function getDefaults(): array { return $this->defaults; } public function getDefaults(): array
{
return $this->defaults;
}
public function default(string $param, mixed $value): self public function default(string $param, mixed $value): self
{ {
@ -113,9 +138,15 @@ class RouteDefinition implements \JsonSerializable, \Serializable
return $this; return $this;
} }
public function getModule(): ?string { return $this->module; } public function getModule(): ?string
{
return $this->module;
}
public function getAttributes(): array { return $this->attributes; } public function getAttributes(): array
{
return $this->attributes;
}
public function attr(string $key, mixed $value): self public function attr(string $key, mixed $value): self
{ {

View file

@ -18,7 +18,8 @@ class RouteGroup
public function __construct( public function __construct(
private array $options = [], private array $options = [],
private readonly Router|null $router = null private readonly Router|null $router = null
) {} ) {
}
/** /**
* Creates a new route group with options and router. * Creates a new route group with options and router.
@ -42,7 +43,7 @@ class RouteGroup
if ($this->router) { if ($this->router) {
return $this->router->registerCustomRoute('GET', $fullPath, $handler, $name, $middleware, $validation, $defaults); return $this->router->registerCustomRoute('GET', $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
return new RouteDefinition('GET', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults); return new RouteDefinition('GET', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
@ -56,7 +57,7 @@ class RouteGroup
if ($this->router) { if ($this->router) {
return $this->router->registerCustomRoute('POST', $fullPath, $handler, $name, $middleware, $validation, $defaults); return $this->router->registerCustomRoute('POST', $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
return new RouteDefinition('POST', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults); return new RouteDefinition('POST', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
@ -70,7 +71,7 @@ class RouteGroup
if ($this->router) { if ($this->router) {
return $this->router->registerCustomRoute('PUT', $fullPath, $handler, $name, $middleware, $validation, $defaults); return $this->router->registerCustomRoute('PUT', $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
return new RouteDefinition('PUT', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults); return new RouteDefinition('PUT', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
@ -84,7 +85,7 @@ class RouteGroup
if ($this->router) { if ($this->router) {
return $this->router->registerCustomRoute('PATCH', $fullPath, $handler, $name, $middleware, $validation, $defaults); return $this->router->registerCustomRoute('PATCH', $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
return new RouteDefinition('PATCH', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults); return new RouteDefinition('PATCH', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
@ -98,7 +99,7 @@ class RouteGroup
if ($this->router) { if ($this->router) {
return $this->router->registerCustomRoute('DELETE', $fullPath, $handler, $name, $middleware, $validation, $defaults); return $this->router->registerCustomRoute('DELETE', $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
return new RouteDefinition('DELETE', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults); return new RouteDefinition('DELETE', $fullPath, $fullPath, $handler, $name, $middleware, $validation, $defaults);
} }
@ -119,10 +120,10 @@ class RouteGroup
public function fallback(mixed $handler): self public function fallback(mixed $handler): self
{ {
$this->options['fallback'] = $handler; $this->options['fallback'] = $handler;
$prefix = $this->options['prefix'] ?? '/'; $prefix = $this->options['prefix'] ?? '/';
$middleware = $this->options['middleware'] ?? []; $middleware = $this->options['middleware'] ?? [];
if ($this->router) { if ($this->router) {
$this->router->registerCustomRoute('FALLBACK', $this->joinPaths($prefix, '/_fallback'), $handler, null, $middleware) $this->router->registerCustomRoute('FALLBACK', $this->joinPaths($prefix, '/_fallback'), $handler, null, $middleware)
->attr('_fallback', $handler) ->attr('_fallback', $handler)
@ -136,7 +137,7 @@ class RouteGroup
{ {
$fullPath = $this->buildFullPath($path); $fullPath = $this->buildFullPath($path);
$mergedMiddleware = array_merge($this->options['middleware'] ?? [], $middleware); $mergedMiddleware = array_merge($this->options['middleware'] ?? [], $middleware);
$route = null; $route = null;
if ($this->router) { if ($this->router) {
$route = $this->router->registerCustomRoute($method, $fullPath, $handler, $name, $mergedMiddleware); $route = $this->router->registerCustomRoute($method, $fullPath, $handler, $name, $mergedMiddleware);
@ -179,7 +180,7 @@ class RouteGroup
$prefix = $this->options['prefix'] ?? ''; $prefix = $this->options['prefix'] ?? '';
$newPrefix = $this->joinPaths($prefix, $options['prefix'] ?? ''); $newPrefix = $this->joinPaths($prefix, $options['prefix'] ?? '');
$middleware = $this->options['middleware'] ?? []; $middleware = $this->options['middleware'] ?? [];
$newMiddleware = array_merge($middleware, $options['middleware'] ?? []); $newMiddleware = array_merge($middleware, $options['middleware'] ?? []);
@ -188,7 +189,7 @@ class RouteGroup
$defaults = $this->options['defaults'] ?? []; $defaults = $this->options['defaults'] ?? [];
$newDefaults = array_merge($defaults, $options['defaults'] ?? []); $newDefaults = array_merge($defaults, $options['defaults'] ?? []);
$mergedOptions = array_merge($this->options, $options); $mergedOptions = array_merge($this->options, $options);
$mergedOptions['prefix'] = $newPrefix; $mergedOptions['prefix'] = $newPrefix;
$mergedOptions['middleware'] = $newMiddleware; $mergedOptions['middleware'] = $newMiddleware;
@ -267,10 +268,10 @@ class RouteGroup
// But ModuleLoader uses the router directly. // But ModuleLoader uses the router directly.
// If we use $this->router->module(), it won't have the group prefix/middleware. // If we use $this->router->module(), it won't have the group prefix/middleware.
// We should probably allow ModuleLoader to take a "target" which can be a Router or RouteGroup. // We should probably allow ModuleLoader to take a "target" which can be a Router or RouteGroup.
// For now, let's just use the router but we have a problem: inheritance. // For now, let's just use the router but we have a problem: inheritance.
// A better way is to make RouteGroup have a way to load modules. // A better way is to make RouteGroup have a way to load modules.
$moduleLoader = new ModuleLoader($this->router->getConfig(), $this); $moduleLoader = new ModuleLoader($this->router->getConfig(), $this);
$moduleLoader->load($identifier, $prefix); $moduleLoader->load($identifier, $prefix);
} }
@ -289,4 +290,4 @@ class RouteGroup
{ {
return $this->router->getConfig(); return $this->router->getConfig();
} }
} }

View file

@ -34,7 +34,7 @@ class RouteMatcher
$attributes = $this->mergeDefaults($route, $attributes); $attributes = $this->mergeDefaults($route, $attributes);
return $this->applyAttributes($route, $attributes); return $this->applyAttributes($route, $attributes);
} }
// i18n support: check alternative paths // i18n support: check alternative paths
$routeAttributes = $route->getAttributes(); $routeAttributes = $route->getAttributes();
if (isset($routeAttributes['i18n']) && is_array($routeAttributes['i18n'])) { if (isset($routeAttributes['i18n']) && is_array($routeAttributes['i18n'])) {
@ -129,7 +129,7 @@ class RouteMatcher
} }
$pattern = $overridePath ? $this->compilePatternFromPath($overridePath, $route) : $this->getPatternForRoute($route); $pattern = $overridePath ? $this->compilePatternFromPath($overridePath, $route) : $this->getPatternForRoute($route);
if (preg_match($pattern, $path, $matches)) { if (preg_match($pattern, $path, $matches)) {
$attributes = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY); $attributes = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
return true; return true;
@ -179,10 +179,10 @@ class RouteMatcher
$pattern = preg_replace_callback('#/\{\{([a-zA-Z0-9_]+)(\?)?\}\}#', function ($matches) use ($validation, $defaults) { $pattern = preg_replace_callback('#/\{\{([a-zA-Z0-9_]+)(\?)?\}\}#', function ($matches) use ($validation, $defaults) {
$name = $matches[1]; $name = $matches[1];
$optional = (isset($matches[2]) && $matches[2] === '?') || array_key_exists($name, $defaults); $optional = (isset($matches[2]) && $matches[2] === '?') || array_key_exists($name, $defaults);
$rules = $validation[$name] ?? []; $rules = $validation[$name] ?? [];
$regex = '[^/]+'; $regex = '[^/]+';
// Validation rules support // Validation rules support
foreach ((array)$rules as $rule) { foreach ((array)$rules as $rule) {
if ($rule === 'numeric' || $rule === 'int') { if ($rule === 'numeric' || $rule === 'int') {
@ -199,7 +199,7 @@ class RouteMatcher
if ($optional) { if ($optional) {
return '(?:/(?P<' . $name . '>' . $regex . '))?'; return '(?:/(?P<' . $name . '>' . $regex . '))?';
} }
return '/(?P<' . $name . '>' . $regex . ')'; return '/(?P<' . $name . '>' . $regex . ')';
}, $path); }, $path);
@ -219,7 +219,7 @@ class RouteMatcher
{ {
$data = $route->toArray(); $data = $route->toArray();
$data['attributes'] = array_merge($data['attributes'], $attributes); $data['attributes'] = array_merge($data['attributes'], $attributes);
return new RouteDefinition( return new RouteDefinition(
$data['method'], $data['method'],
$data['pattern'], $data['pattern'],

View file

@ -119,7 +119,7 @@ class Router
$attributes = []; $attributes = [];
$routeMethod = strtoupper($route->getMethod()); $routeMethod = strtoupper($route->getMethod());
$routePath = $route->getPath(); $routePath = $route->getPath();
$matchStatus = 'mismatch'; $matchStatus = 'mismatch';
if ($routeMethod !== $method && $routeMethod !== 'REDIRECT') { if ($routeMethod !== $method && $routeMethod !== 'REDIRECT') {
$matchStatus = 'method_mismatch'; $matchStatus = 'method_mismatch';
@ -129,7 +129,7 @@ class Router
$matchStatus = 'matched'; $matchStatus = 'matched';
$attributes = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY); $attributes = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
$attributes = array_merge($route->getDefaults(), $attributes); $attributes = array_merge($route->getDefaults(), $attributes);
return new MatchResult(true, $route, $attributes, $diagnostics); return new MatchResult(true, $route, $attributes, $diagnostics);
} }
} }
@ -163,7 +163,7 @@ class Router
public function fallback(mixed $handler): self public function fallback(mixed $handler): self
{ {
$this->fallbackHandler = $handler; $this->fallbackHandler = $handler;
// Register a special route to carry the global fallback // Register a special route to carry the global fallback
$this->registerRoute('FALLBACK', '/_fallback', $handler) $this->registerRoute('FALLBACK', '/_fallback', $handler)
->attr('_fallback', $handler) ->attr('_fallback', $handler)
@ -203,7 +203,7 @@ class Router
foreach ($parameterNames as $index => $name) { foreach ($parameterNames as $index => $name) {
$pattern = '{{' . $name . ($isOptional[$index] === '?' ? '?' : '') . '}}'; $pattern = '{{' . $name . ($isOptional[$index] === '?' ? '?' : '') . '}}';
if (array_key_exists($name, $parameters)) { if (array_key_exists($name, $parameters)) {
$path = str_replace($pattern, (string)$parameters[$name], $path); $path = str_replace($pattern, (string)$parameters[$name], $path);
} elseif (array_key_exists($name, $defaults)) { } elseif (array_key_exists($name, $defaults)) {
@ -228,4 +228,4 @@ class Router
$this->loader->load($identifier, $prefix); $this->loader->load($identifier, $prefix);
return $this; return $this;
} }
} }