X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=mdref%2FAction.php;h=0c48dd6b403c448d5d6f9538b141e448aadc01d1;hb=a94ecb1009610a763dd74a7eebc4754b6643d832;hp=18f60691b21b0d96a1176f43ac760509355b4c70;hpb=d5aa9488b908561542745f7e2a1f6061b63b181a;p=mdref%2Fmdref diff --git a/mdref/Action.php b/mdref/Action.php index 18f6069..0c48dd6 100644 --- a/mdref/Action.php +++ b/mdref/Action.php @@ -2,55 +2,225 @@ namespace mdref; -use http\Controller\Observer; +use http\Env\Request; +use http\Env\Response; +use http\Message\Body; +use stdClass; +use function file_get_contents; +use function htmlspecialchars; +use function ob_start; +use const ROOT; /** - * The sole action controller of mdref + * Request handler */ -class Action extends Observer -{ - private function serveReference(\http\Controller $ctl) { - $payload = $ctl->getPayload(); - $finder = new Finder($this->baseUrl, REFS); - $path = $finder->find(new \http\Url($ctl->getRequest()->getRequestUrl())); - $payload->listing = new RefListing($path, - $finder->glob($path, "/[_a-zA-Z]*.md")); - $payload->title = $payload->listing->getSelf()->formatLink(); - $payload->refs = $finder; - if ($path->isFile()) { - $payload->html = new Markdown($path); - $payload->sublisting = new RefListing($path, - $finder->glob($path, "/[_a-z]*.md")); +class Action { + /** + * The reference + * @var \mdref\Reference + */ + private $reference; + + /** + * @var \http\Env\Request + */ + private $request; + + /** + * @var \http\Env\Response + */ + private $response; + + /** + * @var resource + */ + private $output; + + /** + * @var \http\Url + */ + private $baseUrl; + + /** + * Initialize the reference + */ + public function __construct(Reference $ref, Request $req, Response $res, BaseUrl $baseUrl, $output = null) { + $this->reference = $ref; + $this->request = $req; + $this->response = $res; + $this->baseUrl = $baseUrl; + $this->output = $output; + ob_start($res); + } + + /** + * Shorthand for \htmlspecialchars() + * @param $txt string + * @return string + */ + function esc(string $txt) : string { + return htmlspecialchars($txt); + } + + /** + * Create the view payload + * @return \stdClass + */ + private function createPayload() : object { + $pld = new stdClass; + + $pld->esc = "htmlspecialchars"; + $pld->anchor = [$this->reference, "formatAnchor"]; + $pld->quick = [$this->reference, "formatString"]; + $pld->file = [$this->reference, "formatFile"]; + + $pld->ref = $this->baseUrl->pathinfo( + $this->baseUrl->mod($this->request->getRequestUrl())); + + $pld->markup = function($page) use($pld) { + return $this->reference->getFormatter()->markup($page, $pld); + }; + + $pld->refs = $this->reference; + $pld->baseUrl = $this->baseUrl; + + return $pld; + } + + /** + * Redirect to canonical url + * @param string $cnn + */ + private function serveCanonical(string $cnn) : void { + $this->response->setHeader("Location", $this->baseUrl->mod(["path" => $cnn])); + $this->response->setResponseCode(301); + if (is_resource($this->output)) { + $this->response->send($this->output); + } else { + $this->response->send(); + } + } + + /** + * Serve index.css + */ + private function serveStylesheet() : void { + $this->response->setHeader("Content-Type", "text/css"); + $this->response->setBody(new Body(\fopen(ROOT."/public/index.css", "r"))); + if (is_resource($this->output)) { + $this->response->send($this->output); + } else { + $this->response->send(); + } + } + + /** + * Serve index.js + */ + private function serveJavascript() : void { + $this->response->setHeader("Content-Type", "application/javascript"); + $this->response->setBody(new Body(\fopen(ROOT."/public/index.js", "r"))); + if (is_resource($this->output)) { + $this->response->send($this->output); + } else { + $this->response->send(); + } + } + + /** + * Server a PHP stub + * @throws Exception + * + */ + private function serveStub() : void { + $name = $this->request->getQuery("ref", "s"); + $repo = $this->reference->getRepoForEntry($name); + if (!$repo->hasStub($stub)) { + throw new Exception(404, "Stub not found"); + } + $this->response->setHeader("Content-Type", "application/x-php"); + $this->response->setContentDisposition(["attachment" => ["filename" => "$name.stub.php"]]); + $this->response->setBody(new Body(\fopen($stub, "r"))); + if (is_resource($this->output)) { + $this->response->send($this->output); + } else { + $this->response->send(); + } + } + + /** + * Serve a preset + * @param object $pld + * @return true to continue serving the payload + * @throws Exception + */ + private function servePreset(object $pld) : bool { + switch ($pld->ref) { + case "AUTHORS": + case "LICENSE": + case "VERSION": + $pld->text = file_get_contents(ROOT."/$pld->ref"); return true; + case "index.css": + $this->serveStylesheet(); + break; + case "index.js": + $this->serveJavascript(); + break; + case "stub": + $this->serveStub(); + break; + default: + throw new Exception(404, "$pld->ref not found"); } + return false; } - - private function serveInternal(\http\Controller $ctl) { - $payload = $ctl->getPayload(); - $finder = new Finder($this->baseUrl, ROOT); - $url = new \http\Url($ctl->getRequest()->getRequestUrl()); - $path = $finder->find($url, ""); - if ($path->isFile("")) { - $payload->html = $path->toHtml(); - } else if (strcmp($url->path, $this->baseUrl->path)) { - throw new \http\Controller\Exception(404, "Could not find '$path'"); + + /** + * Serve a payload + */ + private function serve() : void { + extract((array) func_get_arg(0)); + include ROOT."/views/layout.phtml"; + $this->response->addHeader("Link", "<" . $this->baseUrl->path . "index.css>; rel=preload; as=style"); + $this->response->addHeader("Link", "<" . $this->baseUrl->path . "index.js>; rel=preload; as=script"); + if (isset($exception) && $exception->getCode()) { + $this->response->setResponseCode($exception->getCode()); + } + if (is_resource($this->output)) { + $this->response->send($this->output); + } else { + $this->response->send(); } } /** - * Implements \SplObserver - * @param \SplSubject $ctl + * Request handler */ - function update(\SplSubject $ctl) { - /* @var \http\Controller $ctl */ + public function handle() : void { try { - $ctl->getPayload()->baseUrl = $this->baseUrl; + $pld = $this->createPayload(); - if (!$this->serveReference($ctl)) { - $this->serveInternal($ctl); + if (isset($pld->ref) && strlen($pld->ref)) { + $cnn = null; + if (($repo = $this->reference->getRepoForEntry($pld->ref, $cnn))) { + if (isset($cnn) && strlen($cnn)) { + /* redirect */ + $this->serveCanonical($cnn); + return; + } else { + /* direct match */ + $pld->entry = $repo->getEntry($pld->ref); + } + } elseif (!$this->servePreset($pld)) { + return; + } } + } catch (\Exception $e) { - $ctl->getPayload()->exception = $e; + $pld->exception = $e; } + + $this->serve($pld); } }