Namespace and ClassPath rewrites
This commit is contained in:
157
Core/Objects/Router/AbstractRoute.class.php
Normal file
157
Core/Objects/Router/AbstractRoute.class.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Objects\Router;
|
||||
|
||||
use Core\API\Parameter\Parameter;
|
||||
|
||||
abstract class AbstractRoute {
|
||||
|
||||
const PARAMETER_PATTERN = "/^{([^:]+)(:(.*?)(\?)?)?}$/";
|
||||
|
||||
private string $pattern;
|
||||
private bool $exact;
|
||||
|
||||
public function __construct(string $pattern, bool $exact = true) {
|
||||
$this->pattern = $pattern;
|
||||
$this->exact = $exact;
|
||||
}
|
||||
|
||||
private static function parseParamType(?string $type): ?int {
|
||||
if ($type === null || trim($type) === "") {
|
||||
return null;
|
||||
}
|
||||
|
||||
$type = strtolower(trim($type));
|
||||
if (in_array($type, ["int", "integer"])) {
|
||||
return Parameter::TYPE_INT;
|
||||
} else if (in_array($type, ["float", "double"])) {
|
||||
return Parameter::TYPE_FLOAT;
|
||||
} else if (in_array($type, ["bool", "boolean"])) {
|
||||
return Parameter::TYPE_BOOLEAN;
|
||||
} else {
|
||||
return Parameter::TYPE_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
public function getPattern(): string {
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
public abstract function call(Router $router, array $params): string;
|
||||
|
||||
protected function getArgs(): array {
|
||||
return [$this->pattern, $this->exact];
|
||||
}
|
||||
|
||||
public function getClass(): \ReflectionClass {
|
||||
return new \ReflectionClass($this);
|
||||
}
|
||||
|
||||
public function generateCache(): string {
|
||||
$reflection = $this->getClass();
|
||||
$className = $reflection->getShortName();
|
||||
$args = implode(", ", array_map(function ($arg) {
|
||||
return var_export($arg, true);
|
||||
}, $this->getArgs()));
|
||||
return "new $className($args)";
|
||||
}
|
||||
|
||||
public function match(string $url) {
|
||||
|
||||
# /test/{abc}/{param:?}/{xyz:int}/{aaa:int?}
|
||||
$patternParts = explode("/", Router::cleanURL($this->pattern, false));
|
||||
$countPattern = count($patternParts);
|
||||
$patternOffset = 0;
|
||||
|
||||
# /test/param/optional/123
|
||||
$urlParts = explode("/", Router::cleanURL($url));
|
||||
$countUrl = count($urlParts);
|
||||
$urlOffset = 0;
|
||||
|
||||
$params = [];
|
||||
for (; $patternOffset < $countPattern; $patternOffset++) {
|
||||
if (!preg_match(self::PARAMETER_PATTERN, $patternParts[$patternOffset], $match)) {
|
||||
|
||||
// not a parameter? check if it matches
|
||||
if ($urlOffset >= $countUrl || $urlParts[$urlOffset] !== $patternParts[$patternOffset]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$urlOffset++;
|
||||
} else {
|
||||
|
||||
// we got a parameter here
|
||||
$paramName = $match[1];
|
||||
if (isset($match[2])) {
|
||||
$paramType = self::parseParamType($match[3]) ?? Parameter::TYPE_MIXED;
|
||||
$paramOptional = !empty($match[4] ?? null);
|
||||
} else {
|
||||
$paramType = Parameter::TYPE_MIXED;
|
||||
$paramOptional = false;
|
||||
}
|
||||
|
||||
$parameter = new Parameter($paramName, $paramType, $paramOptional);
|
||||
if ($urlOffset >= $countUrl || $urlParts[$urlOffset] === "") {
|
||||
if ($parameter->optional) {
|
||||
$value = $urlParts[$urlOffset] ?? null;
|
||||
if ($value === null || $value === "") {
|
||||
$params[$paramName] = null;
|
||||
} else {
|
||||
if (!$parameter->parseParam($value)) {
|
||||
return false;
|
||||
} else {
|
||||
$params[$paramName] = $parameter->value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($urlOffset < $countUrl) {
|
||||
$urlOffset++;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$value = $urlParts[$urlOffset];
|
||||
if (!$parameter->parseParam($value)) {
|
||||
return false;
|
||||
} else {
|
||||
$params[$paramName] = $parameter->value;
|
||||
$urlOffset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($urlOffset !== $countUrl && $this->exact) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public function getUrl(array $parameters = []): string {
|
||||
$patternParts = explode("/", Router::cleanURL($this->pattern, false));
|
||||
|
||||
foreach ($patternParts as $i => $part) {
|
||||
if (preg_match(self::PARAMETER_PATTERN, $part, $match)) {
|
||||
$paramName = $match[1];
|
||||
$patternParts[$i] = $parameters[$paramName] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
return "/" . implode("/", array_filter($patternParts));
|
||||
}
|
||||
|
||||
public function getParameterNames(): array {
|
||||
$parameterNames = [];
|
||||
$patternParts = explode("/", Router::cleanURL($this->pattern, false));
|
||||
|
||||
foreach ($patternParts as $part) {
|
||||
if (preg_match(self::PARAMETER_PATTERN, $part, $match)) {
|
||||
$parameterNames[] = $match[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $parameterNames;
|
||||
}
|
||||
}
|
||||
82
Core/Objects/Router/ApiRoute.class.php
Normal file
82
Core/Objects/Router/ApiRoute.class.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Objects\Router;
|
||||
|
||||
use Core\API\Request;
|
||||
use Core\Elements\TemplateDocument;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
|
||||
class ApiRoute extends AbstractRoute {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct("/api/{endpoint:?}/{method:?}", false);
|
||||
}
|
||||
|
||||
private static function checkClass(string $className): bool {
|
||||
$classPath = getClassPath($className);
|
||||
return file_exists($classPath) && class_exists($className);
|
||||
}
|
||||
|
||||
public function call(Router $router, array $params): string {
|
||||
if (empty($params["endpoint"])) {
|
||||
header("Content-Type: text/html");
|
||||
$document = new TemplateDocument($router, "swagger.twig");
|
||||
return $document->load();
|
||||
} else if (!preg_match("/[a-zA-Z]+/", $params["endpoint"])) {
|
||||
http_response_code(400);
|
||||
$response = createError("Invalid Method");
|
||||
} else {
|
||||
$apiEndpoint = ucfirst($params["endpoint"]);
|
||||
$isNestedAPI = !empty($params["method"]);
|
||||
if ($isNestedAPI) {
|
||||
$apiMethod = ucfirst($params["method"]);
|
||||
$parentClass = "\\API\\${apiEndpoint}API";
|
||||
$apiClass = "\\API\\${apiEndpoint}\\${apiMethod}";
|
||||
} else {
|
||||
$apiClass = "\\API\\${apiEndpoint}";
|
||||
$parentClass = $apiClass;
|
||||
}
|
||||
|
||||
try {
|
||||
$classFound = False;
|
||||
|
||||
// first: check if the parent class exists, for example:
|
||||
// /stats => Stats.class.php
|
||||
// /mail/send => MailAPI.class.php
|
||||
foreach (["Site", "Core"] as $module) {
|
||||
if ($this->checkClass("\\$module$parentClass")) {
|
||||
if (!$isNestedAPI || class_exists("\\$module$apiClass")) {
|
||||
$classFound = true;
|
||||
$apiClass = "\\$module$apiClass";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($classFound) {
|
||||
$apiClass = new ReflectionClass($apiClass);
|
||||
if (!$apiClass->isSubclassOf(Request::class) || !$apiClass->isInstantiable()) {
|
||||
http_response_code(400);
|
||||
$response = createError("Invalid Method");
|
||||
} else {
|
||||
$request = $apiClass->newInstanceArgs(array($router->getContext(), true));
|
||||
$success = $request->execute();
|
||||
$response = $request->getResult();
|
||||
$response["success"] = $success;
|
||||
$response["msg"] = $request->getLastError();
|
||||
}
|
||||
} else {
|
||||
http_response_code(404);
|
||||
$response = createError("Not found");
|
||||
}
|
||||
} catch (ReflectionException $e) {
|
||||
http_response_code(500);
|
||||
$response = createError("Error instantiating class: $e");
|
||||
}
|
||||
}
|
||||
|
||||
header("Content-Type: application/json");
|
||||
return json_encode($response);
|
||||
}
|
||||
}
|
||||
91
Core/Objects/Router/DocumentRoute.class.php
Normal file
91
Core/Objects/Router/DocumentRoute.class.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Objects\Router;
|
||||
|
||||
use Core\Elements\Document;
|
||||
use Core\Objects\Context;
|
||||
use Core\Objects\Search\Searchable;
|
||||
use Core\Objects\Search\SearchQuery;
|
||||
use ReflectionException;
|
||||
|
||||
class DocumentRoute extends AbstractRoute {
|
||||
|
||||
use Searchable;
|
||||
|
||||
private string $className;
|
||||
private array $args;
|
||||
private ?\ReflectionClass $reflectionClass;
|
||||
|
||||
public function __construct(string $pattern, bool $exact, string $className, ...$args) {
|
||||
parent::__construct($pattern, $exact);
|
||||
$this->className = $className;
|
||||
$this->args = $args;
|
||||
$this->reflectionClass = null;
|
||||
}
|
||||
|
||||
private function loadClass(): bool {
|
||||
|
||||
if ($this->reflectionClass === null) {
|
||||
try {
|
||||
$file = getClassPath($this->className);
|
||||
if (file_exists($file)) {
|
||||
$this->reflectionClass = new \ReflectionClass($this->className);
|
||||
if ($this->reflectionClass->isSubclassOf(Document::class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (ReflectionException $exception) {
|
||||
$this->reflectionClass = null;
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$this->reflectionClass = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function match(string $url) {
|
||||
$match = parent::match($url);
|
||||
if ($match === false || !$this->loadClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $match;
|
||||
}
|
||||
|
||||
protected function getArgs(): array {
|
||||
return array_merge(parent::getArgs(), [$this->className], $this->args);
|
||||
}
|
||||
|
||||
public function call(Router $router, array $params): string {
|
||||
try {
|
||||
if (!$this->loadClass()) {
|
||||
return $router->returnStatusCode(500, [ "message" => "Error loading class: $this->className"]);
|
||||
}
|
||||
|
||||
$args = array_merge([$router], $this->args, $params);
|
||||
$document = $this->reflectionClass->newInstanceArgs($args);
|
||||
return $document->load($params);
|
||||
} catch (\ReflectionException $e) {
|
||||
return $router->returnStatusCode(500, [ "message" => "Error loading class $this->className: " . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function doSearch(Context $context, SearchQuery $query): array {
|
||||
try {
|
||||
if ($this->loadClass()) {
|
||||
$args = array_merge([$context->router], $this->args);
|
||||
$document = $this->reflectionClass->newInstanceArgs($args);
|
||||
if ($document->isSearchable()) {
|
||||
return $document->doSearch($query, $this);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
} catch (\ReflectionException) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Core/Objects/Router/EmptyRoute.class.php
Normal file
14
Core/Objects/Router/EmptyRoute.class.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Objects\Router;
|
||||
|
||||
class EmptyRoute extends AbstractRoute {
|
||||
|
||||
public function __construct(string $pattern, bool $exact = true) {
|
||||
parent::__construct($pattern, $exact);
|
||||
}
|
||||
|
||||
public function call(Router $router, array $params): string {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
25
Core/Objects/Router/RedirectRoute.class.php
Normal file
25
Core/Objects/Router/RedirectRoute.class.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Objects\Router;
|
||||
|
||||
class RedirectRoute extends AbstractRoute {
|
||||
|
||||
private string $destination;
|
||||
private int $code;
|
||||
|
||||
public function __construct(string $pattern, bool $exact, string $destination, int $code = 307) {
|
||||
parent::__construct($pattern, $exact);
|
||||
$this->destination = $destination;
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
public function call(Router $router, array $params): string {
|
||||
header("Location: $this->destination");
|
||||
http_response_code($this->code);
|
||||
return "";
|
||||
}
|
||||
|
||||
protected function getArgs(): array {
|
||||
return array_merge(parent::getArgs(), [$this->destination, $this->code]);
|
||||
}
|
||||
}
|
||||
169
Core/Objects/Router/Router.class.php
Normal file
169
Core/Objects/Router/Router.class.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Objects\Router;
|
||||
|
||||
use Core\Driver\Logger\Logger;
|
||||
use Core\Objects\Context;
|
||||
|
||||
class Router {
|
||||
|
||||
private Context $context;
|
||||
private Logger $logger;
|
||||
private ?AbstractRoute $activeRoute;
|
||||
private ?string $requestedUri;
|
||||
protected array $routes;
|
||||
protected array $statusCodeRoutes;
|
||||
|
||||
public function __construct(Context $context) {
|
||||
$this->context = $context;
|
||||
$this->routes = [];
|
||||
$this->statusCodeRoutes = [];
|
||||
$this->activeRoute = null;
|
||||
$this->requestedUri = null;
|
||||
$this->context->router = $this;
|
||||
|
||||
$sql = $context->getSQL();
|
||||
if ($sql) {
|
||||
$this->addRoute(new ApiRoute());
|
||||
$this->logger = new Logger("Router", $sql);
|
||||
} else {
|
||||
$this->logger = new Logger("Router");
|
||||
}
|
||||
}
|
||||
|
||||
public function getActiveRoute(): ?AbstractRoute {
|
||||
return $this->activeRoute;
|
||||
}
|
||||
|
||||
public function getRequestedUri(): ?string {
|
||||
return $this->requestedUri;
|
||||
}
|
||||
|
||||
public function run(string $url): string {
|
||||
|
||||
// TODO: do we want a global try cache and return status page 500 on any error?
|
||||
$this->requestedUri = $url;
|
||||
|
||||
$url = strtok($url, "?");
|
||||
foreach ($this->routes as $route) {
|
||||
$pathParams = $route->match($url);
|
||||
if ($pathParams !== false) {
|
||||
$this->activeRoute = $route;
|
||||
return $route->call($this, $pathParams);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->returnStatusCode(404);
|
||||
}
|
||||
|
||||
public function returnStatusCode(int $code, array $params = []): string {
|
||||
http_response_code($code);
|
||||
$params["status_code"] = $code;
|
||||
$params["status_description"] = HTTP_STATUS_DESCRIPTIONS[$code] ?? "Unknown Error";
|
||||
$route = $this->statusCodeRoutes[strval($code)] ?? null;
|
||||
if ($route) {
|
||||
return $route->call($this, $params);
|
||||
} else {
|
||||
$req = new \Core\API\Template\Render($this->context);
|
||||
$res = $req->execute(["file" => "error_document.twig", "parameters" => $params]);
|
||||
if ($res) {
|
||||
return $req->getResult()["html"];
|
||||
} else {
|
||||
$description = htmlspecialchars($params["status_description"]);
|
||||
return "<b>$code - $description</b>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addRoute(AbstractRoute $route) {
|
||||
if (preg_match("/^\/(\d+)$/", $route->getPattern(), $re)) {
|
||||
$this->statusCodeRoutes[$re[1]] = $route;
|
||||
}
|
||||
|
||||
$this->routes[] = $route;
|
||||
}
|
||||
|
||||
public function writeCache(string $file): bool {
|
||||
|
||||
$routes = "";
|
||||
$uses = [
|
||||
"Core\Objects\Context",
|
||||
"Core\Objects\Router\Router",
|
||||
];
|
||||
|
||||
foreach ($this->routes as $route) {
|
||||
// do not generate cache for static api route
|
||||
if ($route instanceof ApiRoute) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $route->getClass();
|
||||
$constructor = $route->generateCache();
|
||||
$uses[] = $class->getName();
|
||||
$routes .= "\n \$this->addRoute($constructor);";
|
||||
}
|
||||
|
||||
$uses = implode("\n", array_map(function ($use) { return "use $use;"; }, array_unique($uses)));
|
||||
$date = (new \DateTime())->format("Y/m/d H:i:s");
|
||||
$code = "<?php
|
||||
|
||||
/**
|
||||
* DO NOT EDIT!
|
||||
* This file is automatically generated by the RoutesAPI on $date.
|
||||
*/
|
||||
|
||||
namespace Core\Cache;
|
||||
$uses
|
||||
|
||||
class RouterCache extends Router {
|
||||
|
||||
public function __construct(Context \$context) {
|
||||
parent::__construct(\$context);$routes
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
if (@file_put_contents($file, $code) === false) {
|
||||
$this->logger->severe("Could not write Router cache file: $file");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getContext(): Context {
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
public function getLogger(): Logger {
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
public static function cleanURL(string $url, bool $cleanGET = true): string {
|
||||
// strip GET parameters
|
||||
if ($cleanGET) {
|
||||
if (($index = strpos($url, "?")) !== false) {
|
||||
$url = substr($url, 0, $index);
|
||||
}
|
||||
}
|
||||
|
||||
// strip document reference part
|
||||
if (($index = strpos($url, "#")) !== false) {
|
||||
$url = substr($url, 0, $index);
|
||||
}
|
||||
|
||||
// strip leading slash
|
||||
return preg_replace("/^\/+/", "", $url);
|
||||
}
|
||||
|
||||
public function getRoutes(bool $includeStatusRoutes = false): array {
|
||||
|
||||
if (!$includeStatusRoutes && !empty($this->statusCodeRoutes)) {
|
||||
return array_filter($this->routes, function ($route) {
|
||||
return !in_array($route, $this->statusCodeRoutes);
|
||||
});
|
||||
}
|
||||
|
||||
return $this->routes;
|
||||
}
|
||||
}
|
||||
114
Core/Objects/Router/StaticFileRoute.class.php
Normal file
114
Core/Objects/Router/StaticFileRoute.class.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Objects\Router;
|
||||
|
||||
use Core\Objects\Context;
|
||||
use Core\Objects\Search\Searchable;
|
||||
use Core\Objects\Search\SearchQuery;
|
||||
use Core\Objects\Search\SearchResult;
|
||||
|
||||
class StaticFileRoute extends AbstractRoute {
|
||||
|
||||
use Searchable;
|
||||
|
||||
private string $path;
|
||||
private int $code;
|
||||
|
||||
public function __construct(string $pattern, bool $exact, string $path, int $code = 200) {
|
||||
parent::__construct($pattern, $exact);
|
||||
$this->path = $path;
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
public function call(Router $router, array $params): string {
|
||||
http_response_code($this->code);
|
||||
$this->serveStatic($this->getAbsolutePath(), $router);
|
||||
return "";
|
||||
}
|
||||
|
||||
protected function getArgs(): array {
|
||||
return array_merge(parent::getArgs(), [$this->path, $this->code]);
|
||||
}
|
||||
|
||||
public function getAbsolutePath(): string {
|
||||
return WEBROOT . DIRECTORY_SEPARATOR . $this->path;
|
||||
}
|
||||
|
||||
public static function serveStatic(string $path, ?Router $router = null) {
|
||||
if (!startsWith($path, WEBROOT . DIRECTORY_SEPARATOR)) {
|
||||
http_response_code(406);
|
||||
echo "<b>Access restricted, requested file outside web root:</b> " . htmlspecialchars($path);
|
||||
}
|
||||
|
||||
if (!file_exists($path) || !is_file($path) || !is_readable($path)) {
|
||||
http_response_code(500);
|
||||
echo "<b>Unable to read file:</b> " . htmlspecialchars($path);
|
||||
}
|
||||
|
||||
$pathInfo = pathinfo($path);
|
||||
if ($router !== null) {
|
||||
$ext = $pathInfo["extension"] ?? "";
|
||||
if (!$router->getContext()->getSettings()->isExtensionAllowed($ext)) {
|
||||
http_response_code(406);
|
||||
echo "<b>Access restricted:</b> Extension '" . htmlspecialchars($ext) . "' not allowed to serve.";
|
||||
}
|
||||
}
|
||||
|
||||
$size = filesize($path);
|
||||
$mimeType = mime_content_type($path);
|
||||
header("Content-Type: $mimeType");
|
||||
header("Content-Length: $size");
|
||||
header('Accept-Ranges: bytes');
|
||||
|
||||
if (strcasecmp($_SERVER["REQUEST_METHOD"], "HEAD") !== 0) {
|
||||
$handle = fopen($path, "rb");
|
||||
if ($handle === false) {
|
||||
http_response_code(500);
|
||||
echo "<b>Unable to read file:</b> " . htmlspecialchars($path);
|
||||
}
|
||||
|
||||
$offset = 0;
|
||||
$length = $size;
|
||||
|
||||
if (isset($_SERVER['HTTP_RANGE'])) {
|
||||
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
|
||||
$offset = intval($matches[1]);
|
||||
$length = intval($matches[2]) - $offset;
|
||||
http_response_code(206);
|
||||
header('Content-Range: bytes ' . $offset . '-' . ($offset + $length) . '/' . $size);
|
||||
}
|
||||
|
||||
downloadFile($handle, $offset, $length);
|
||||
}
|
||||
}
|
||||
|
||||
public function doSearch(Context $context, SearchQuery $query): array {
|
||||
|
||||
$results = [];
|
||||
$path = $this->getAbsolutePath();
|
||||
if (is_file($path) && is_readable($path)) {
|
||||
$pathInfo = pathinfo($path);
|
||||
$extension = $pathInfo["extension"] ?? "";
|
||||
$fileName = $pathInfo["filename"] ?? "";
|
||||
if ($context->getSettings()->isExtensionAllowed($extension)) {
|
||||
$mimeType = mime_content_type($path);
|
||||
if (startsWith($mimeType, "text/")) {
|
||||
$document = @file_get_contents($path);
|
||||
if ($document) {
|
||||
if ($mimeType === "text/html") {
|
||||
$results = Searchable::searchHtml($document, $query);
|
||||
} else {
|
||||
$results = Searchable::searchText($document, $query);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$results = array_map(function ($res) use ($fileName) {
|
||||
return new SearchResult($this->getPattern(), $fileName, $res["text"]);
|
||||
}, $results);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
24
Core/Objects/Router/StaticRoute.class.php
Normal file
24
Core/Objects/Router/StaticRoute.class.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Objects\Router;
|
||||
|
||||
class StaticRoute extends AbstractRoute {
|
||||
|
||||
private string $data;
|
||||
private int $code;
|
||||
|
||||
public function __construct(string $pattern, bool $exact, string $data, int $code = 200) {
|
||||
parent::__construct($pattern, $exact);
|
||||
$this->data = $data;
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
public function call(Router $router, array $params): string {
|
||||
http_response_code($this->code);
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
protected function getArgs(): array {
|
||||
return array_merge(parent::getArgs(), [$this->data, $this->code]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user