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;
/**
* Request handler
*/
-class Action extends Observer {
- /**
- * Reference paths
- * @var string
- */
- protected $refpath;
-
+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
*/
- protected function init() {
- $this->reference = new Reference(explode(PATH_SEPARATOR, $this->refpath));
+ 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
- * @param \http\Controller $ctl
* @return \stdClass
*/
- private function createPayload(\http\Controller $ctl) {
- $pld = new \stdClass;
-
- try {
- $pld->quick = function($string) {
- $md = \MarkdownDocument::createFromString($string);
- $md->compile(\MarkdownDocument::AUTOLINK);
- return $md->getHtml();
- };
-
- $pld->file = function($file) {
- $fd = fopen($file, "r");
- $md = \MarkdownDocument::createFromStream($fd);
- $md->compile(\MarkdownDocument::AUTOLINK | \MarkdownDocument::TOC);
- $html = $md->getHtml();
- fclose($fd);
- return $html;
- };
-
- $pld->ref = implode("/", $this->baseUrl->params(
- $this->baseUrl->mod($ctl->getRequest()->getRequestUrl())));
-
- $pld->refs = $this->reference;
- $pld->baseUrl = $this->baseUrl;
-
- } catch (\Exception $e) {
- $pld->exception = $e;
- }
-
+ 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 canononical url
- * @param \http\Controller $ctl
+ * Redirect to canonical url
* @param string $cnn
*/
- private function serveCanonical($ctl, $cnn) {
- $ctl->detachAll(Observer\View::class);
- $ctl->getResponse()->setHeader("Location", $this->baseUrl->mod($cnn));
- $ctl->getResponse()->setResponseCode(301);
+ 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
- * @param \http\Controller $ctl
*/
- private function serveStylesheet($ctl) {
- $ctl->detachAll(Observer\View::class);
- $ctl->getResponse()->setHeader("Content-Type", "text/css");
- $ctl->getResponse()->setBody(new \http\Message\Body(fopen(ROOT."/public/index.css", "r")));
+ 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
- * @param \http\Controller $ctl
*/
- private function serveJavascript($ctl) {
- $ctl->detachAll(Observer\View::class);
- $ctl->getResponse()->setHeader("Content-Type", "application/javascript");
- $ctl->getResponse()->setBody(new \http\Message\Body(fopen(ROOT."/public/index.js", "r")));
+ 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 \http\Controller $ctl
- * @param \stdClass $pld
- * @throws \http\Controller\Exception
+ * @param object $pld
+ * @return true to continue serving the payload
+ * @throws Exception
*/
- private function servePreset($ctl, $pld) {
+ private function servePreset(object $pld) : bool {
switch ($pld->ref) {
case "AUTHORS":
case "LICENSE":
case "VERSION":
$pld->text = file_get_contents(ROOT."/$pld->ref");
- break;
+ return true;
case "index.css":
- $this->serveStylesheet($ctl);
+ $this->serveStylesheet();
break;
case "index.js":
- $this->serveJavascript($ctl);
+ $this->serveJavascript();
+ break;
+ case "stub":
+ $this->serveStub();
break;
default:
- throw new \http\Controller\Exception(404, "$pld->ref not found");
+ throw new Exception(404, "$pld->ref not found");
}
+ return false;
}
-
+
/**
- * Implements Observer
- * @param \SplSubject $ctl \http\Controller
+ * Serve a payload
*/
- public function update(\SplSubject $ctl) {
- /* @var http\Controller $ctl */
- $pld = $this->createPayload($ctl);
- $ctl[Observer\View::class] = function() use($pld) {
- return $pld;
- };
-
- if (!isset($pld->ref) || !strlen($pld->ref)) {
- /* front page */
- return;
+ 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());
}
-
- $cnn = null;
- if (($repo = $this->reference->getRepoForEntry($pld->ref, $cnn))) {
- if (strlen($cnn)) {
- /* redirect */
- $this->serveCanonical($ctl, $cnn);
- } else {
- /* direct match */
- $pld->entry = $repo->getEntry($pld->ref);
- }
+ if (is_resource($this->output)) {
+ $this->response->send($this->output);
} else {
- $this->servePreset($ctl, $pld);
+ $this->response->send();
}
}
-}
\ No newline at end of file
+ /**
+ * Request handler
+ */
+ public function handle() : void {
+ try {
+ $pld = $this->createPayload();
+
+ 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) {
+ $pld->exception = $e;
+ }
+
+ $this->serve($pld);
+ }
+}