<?php
namespace Lia\Http;
/**
* A value-object for holding route information, with some convenience methods.
*
* Some behavior is documented in this class, but it's really all up to the calling code.
*/
class Route {
/**
* The router that returned this route.
*/
public ?Router $router = null;
/**
* Paramaters extracted from the url, based upon the route.
*
* @example `/blog/{slug}/` requested by `/blog/happy-cats/` would yield `['slug'=>'happy-cats']`
*/
public array $paramaters;
/**
* Requested URL Path
*/
public string $url;
/**
* Request method, like "GET" or "POST"
*/
public string $method;
/**
* Original route pattern, like `/blog/{slug}/`
*/
public string $originalPattern;
/**
* Full Regex used to check if the request url is valid, AFTER the testPattern has reduced the number of possibilities.
*/
public string $regexPattern;
/**
* A simplified pattern for the route-selection algorithm. After this filter-step, $regexPattern filters to the final set of pattern matches.
*
* @example For `/blog/{slug}/`, `$testPattern = `blog/?/`
*/
public string $testPattern;
/**
* Array of methods that are valid for this route. Such as GET, PUT, POST, DELETE, etc
*/
public array $allowedMethods;
/**
* Callable or absolute file path.
* The calling code is responsible for passing args.
*/
public mixed $target;
/**
* Array of arguments to pass to $target
* The calling code is responsible for passing args.
*/
public array $args;
//static public function new_route(string $pattern, string $url, string $method="GET"){
//$route = new static();
//$route->originalPattern = $pattern;
//$route->url = $url;
//$route->method = $method;
//$route->allowedMethods = [$method];
//}
/**
* All desired properties must be set explicitly one-by-one.
*/
public function __construct(){}
/**
* Get a portion of the url.
* @example for `/blog/cute-cats/`, part(1) returns `cute-cats`.
*
* @param int $index index of the url portion to return;
* @return string `$index` portion of url, or null if `$index` iss too big
*/
public function part(int $index): ?string {
return explode('/',$this->url)[1+$index] ?? null;
}
/**
* Get a named url paramater.
*
* @example for pattern `/blog/{slug}/`, requested by `/blog/cute-cats/`, `param('slug')` returns the 'cute-cats'
*
* @param $name string name of url paramater.
* @return string named paramater from URL, or null if paramater doesn't exist.
*/
public function param(string $name): ?string {
return $this->paramaters[$name] ?? null;
}
/**
* Get a named url paramater by zero-based index (instead of by name)
* @example for pattern `/post/{category}/{slug}/`, requested by `/post/blog/cute-cats/`, `var(0)` returns 'blog' and `var(1)` returns 'cute-cats'
*
* @return string `$index` of a named paramater from the url, or null if `$index` is too big
*/
public function var(int $index): ?string {
return array_values($this->paramaters)[$index] ?? null;
}
/**
* Check if target is callable, a file, or null
*
* @return string 'file', 'callable', or null if neither. Returns null if file does not exist.
*/
public function type(): ?string {
$t = $this->target;
if ($this->isFile())return 'file';
else if ($this->isCallable())return 'callable';
else return null;
}
/**
* Check if target is callable
*
* @return bool true if `is_callable($target)` is true. false otherwise.
*/
public function isCallable(): bool{
$t = $this->target;
return is_callable($t);
}
/**
* Check if target is a file
*
* @return bool true if target `is_string` AND `is_file()`. false otherwise.
*/
public function isFile(): bool{
$t = $this->target;
return is_string($t) && is_file($t);
}
/**
* Check if target is an executable file.
*
* @return bool true if target `is_string()` AND `is_file()` AND `is_executable()`. false otherwise.
*/
public function isExecutableFile(): bool{
$t = $this->target;
return is_string($t) && is_file($t) && is_executable($t);
}
/**
* Get file extension, if target is a file. null otherwise.
*
* @return string file extension of target, like 'php' or 'js' or 'jpeg', or null if target is not a file, or empty string if no extension.
*/
public function fileExt(): ?string {
if (!$this->isFile())return null;
return pathinfo($this->target, PATHINFO_EXTENSION);
}
/**
* Check if the route's originalPattern is static.
*
* @return bool true if the originalPattern has no named paramaters. false otherwise.
*/
public function isStatic(): bool {
return (count($this->paramaters)==0);
}
/**
* Check if the route's originalPattern contains named parmaters.
*
* @return bool true if the originalPattern contains named paramaters. false otherwise.
*/
public function isDynamic(): bool {
return !$this->isStatic();
}
}