diff options
author | Laria Carolin Chabowski <laria@laria.me> | 2020-09-25 21:18:18 +0200 |
---|---|---|
committer | Laria Carolin Chabowski <laria@laria.me> | 2020-09-25 21:28:55 +0200 |
commit | 378881378aab5454c84cb1fecbbcc675f64dc27f (patch) | |
tree | f8bbe239c2a87cc61bec05b987099e4401dd2693 | |
parent | 78c0350b3b7fc025ba565e19bfa195b68e95bb88 (diff) | |
download | ratatoeskr-cms-378881378aab5454c84cb1fecbbcc675f64dc27f.tar.gz ratatoeskr-cms-378881378aab5454c84cb1fecbbcc675f64dc27f.tar.bz2 ratatoeskr-cms-378881378aab5454c84cb1fecbbcc675f64dc27f.zip |
Refactor textprocessors
They are now managed by TextprocessorRepository and are instances of
Textprocessor. This replaces the global $textprocessors variable.
-rw-r--r-- | ratatoeskr/backend.php | 26 | ||||
-rw-r--r-- | ratatoeskr/frontend.php | 7 | ||||
-rw-r--r-- | ratatoeskr/sys/Env.php | 37 | ||||
-rw-r--r-- | ratatoeskr/sys/models.php | 31 | ||||
-rw-r--r-- | ratatoeskr/sys/plugin_api.php | 8 | ||||
-rw-r--r-- | ratatoeskr/sys/textprocessors.php | 75 | ||||
-rw-r--r-- | ratatoeskr/sys/textprocessors/HtmlProcessor.php | 20 | ||||
-rw-r--r-- | ratatoeskr/sys/textprocessors/LegacyTextprocessor.php | 32 | ||||
-rw-r--r-- | ratatoeskr/sys/textprocessors/MarkdownProcessor.php | 22 | ||||
-rw-r--r-- | ratatoeskr/sys/textprocessors/PlainTextProcessor.php | 22 | ||||
-rw-r--r-- | ratatoeskr/sys/textprocessors/Textprocessor.php | 19 | ||||
-rw-r--r-- | ratatoeskr/sys/textprocessors/TextprocessorRepository.php | 76 |
12 files changed, 302 insertions, 73 deletions
diff --git a/ratatoeskr/backend.php b/ratatoeskr/backend.php index df1ea5b..1b898ea 100644 --- a/ratatoeskr/backend.php +++ b/ratatoeskr/backend.php @@ -10,6 +10,7 @@ */ use r7r\cms\sys\Esc; +use r7r\cms\sys\Env; require_once(dirname(__FILE__) . "/sys/models.php"); require_once(dirname(__FILE__) . "/sys/pwhash.php"); @@ -139,12 +140,13 @@ function build_backend_subactions() /** * @var \ste\STECore $ste * @var array $translation - * @var array $textprocessors * @var Settings $ratatoeskr_settings * @var array $languages * @var array $articleeditor_plugins */ - global $ste, $translation, $textprocessors, $ratatoeskr_settings, $languages, $articleeditor_plugins; + global $ste, $translation, $ratatoeskr_settings, $languages, $articleeditor_plugins; + + $textprocessors = Env::getGlobal()->textprocessors(); list($article, $editlang) = array_slice($url_next, 0); if (!isset($editlang)) { @@ -164,9 +166,9 @@ function build_backend_subactions() $ste->vars["submenu"] = isset($article) ? "articles" : "newarticle"; $ste->vars["textprocessors"] = []; - foreach ($textprocessors as $txtproc => $properties) { - if ($properties[1]) { - $ste->vars["textprocessors"][] = $txtproc; + foreach ($textprocessors->all() as $name => $textprocessor) { + if ($textprocessor->showInBackend()) { + $ste->vars["textprocessors"][] = $name; } } @@ -190,12 +192,12 @@ function build_backend_subactions() } else { $inputs["article_status"] = (int) $_POST["article_status"]; } - if (!isset($textprocessors[@$_POST["content_txtproc"]])) { + if ($textprocessors->getTextprocessor(@$_POST["content_txtproc"]) === null) { $fail_reasons[] = $translation["unknown_txtproc"]; } else { $inputs["content_txtproc"] = $_POST["content_txtproc"]; } - if (!isset($textprocessors[@$_POST["excerpt_txtproc"]])) { + if ($textprocessors->getTextprocessor(@$_POST["excerpt_txtproc"]) === null) { $fail_reasons[] = $translation["unknown_txtproc"]; } else { $inputs["excerpt_txtproc"] = $_POST["excerpt_txtproc"]; @@ -1216,7 +1218,9 @@ function build_backend_subactions() ]), "admin" => url_action_subactions([ "settings" => function (&$data, $url_now, &$url_next) { - global $ste, $translation, $languages, $ratatoeskr_settings, $textprocessors; + global $ste, $translation, $languages, $ratatoeskr_settings; + + $textprocessors = Env::getGlobal()->textprocessors(); $url_next = []; @@ -1225,9 +1229,9 @@ function build_backend_subactions() $ste->vars["pagetitle"] = $translation["menu_settings"]; $ste->vars["textprocessors"] = []; - foreach ($textprocessors as $txtproc => $properties) { - if ($properties[1]) { - $ste->vars["textprocessors"][] = $txtproc; + foreach ($textprocessors->all() as $name => $textprocessor) { + if ($textprocessor->showInBackend()) { + $ste->vars["textprocessors"][] = $name; } } diff --git a/ratatoeskr/frontend.php b/ratatoeskr/frontend.php index eb62378..696d446 100644 --- a/ratatoeskr/frontend.php +++ b/ratatoeskr/frontend.php @@ -9,6 +9,7 @@ * See "ratatoeskr/licenses/ratatoeskr" for more information. */ +use r7r\cms\sys\Env; use r7r\cms\sys\Esc; require_once(dirname(__FILE__) . "/sys/utils.php"); @@ -103,6 +104,8 @@ function article_transform_ste($article, $lang) { global $rel_path_to_root; + $textprocessors = Env::getGlobal()->textprocessors(); + $languages = []; $a_section = $article->get_section(); foreach ($article->title as $language => $_) { @@ -114,8 +117,8 @@ function article_transform_ste($article, $lang) "urlname" => $article->urlname, "fullurl" => Esc::esc("$rel_path_to_root/$lang/{$a_section->name}/{$article->urlname}"), "title" => Esc::esc($article->title[$lang]->text), - "text" => textprocessor_apply(str_replace("%root%", $rel_path_to_root, $article->text[$lang]->text), $article->text[$lang]->texttype), - "excerpt" => textprocessor_apply(str_replace("%root%", $rel_path_to_root, $article->excerpt[$lang]->text), $article->excerpt[$lang]->texttype), + "text" => $textprocessors->mustApply(str_replace("%root%", $rel_path_to_root, $article->text[$lang]->text), $article->text[$lang]->texttype), + "excerpt" => $textprocessors->mustApply(str_replace("%root%", $rel_path_to_root, $article->excerpt[$lang]->text), $article->excerpt[$lang]->texttype), "custom" => $article->custom, "status" => $article->status, "section" => section_transform_ste($a_section, $lang), diff --git a/ratatoeskr/sys/Env.php b/ratatoeskr/sys/Env.php new file mode 100644 index 0000000..cfe1598 --- /dev/null +++ b/ratatoeskr/sys/Env.php @@ -0,0 +1,37 @@ +<?php + + +namespace r7r\cms\sys; + +use r7r\cms\sys\textprocessors\TextprocessorRepository; + +/** + * Env holds several global global objects. It's basically a DI container. + */ +class Env +{ + /** @var self|null */ + private static $globalInstance = null; + + private $lazyLoaded = []; + + private function lazy(string $ident, callable $callback) + { + if (!isset($this->lazyLoaded[$ident])) { + $this->lazyLoaded[$ident] = $callback(); + } + return $this->lazyLoaded[$ident]; + } + + public static function getGlobal(): self + { + self::$globalInstance = self::$globalInstance ?? new self(); + + return self::$globalInstance; + } + + public function textprocessors(): TextprocessorRepository + { + return $this->lazy("textprocessors", [TextprocessorRepository::class, 'buildDefault']); + } +} diff --git a/ratatoeskr/sys/models.php b/ratatoeskr/sys/models.php index 9f81fcf..caf14ad 100644 --- a/ratatoeskr/sys/models.php +++ b/ratatoeskr/sys/models.php @@ -9,6 +9,9 @@ * See "ratatoeskr/licenses/ratatoeskr" for more information. */ +use r7r\cms\sys\textprocessors\TextprocessorRepository; +use r7r\cms\sys\Env; + require_once(dirname(__FILE__) . "/db.php"); require_once(dirname(__FILE__) . "/utils.php"); require_once(dirname(__FILE__) . "/../libs/kses.php"); @@ -691,6 +694,16 @@ class Translation $this->text = $text; $this->texttype = $texttype; } + + /** + * Applies a textprocessor to the text according to texttype. + * @param TextprocessorRepository $textprocessors + * @return string + */ + public function applyTextprocessor(TextprocessorRepository $textprocessors): string + { + return $textprocessors->apply((string)$this->text, (string)$this->texttype); + } } /* @@ -1192,22 +1205,20 @@ class Comment extends BySQLRowEnabled return $rv; } - /* - * Function: htmlize_comment_text - * Creates the HTML representation of a comment text. It applys the page's comment textprocessor on it + /** + * Creates the HTML representation of a comment text. It applies the page's comment textprocessor on it * and filters some potentially harmful tags using kses. * - * Parameters: - * $text - Text to HTMLize. - * - * Returns: - * HTML code. + * @param string $text Text to HTMLize. + * @return string HTML code. */ - public static function htmlize_comment_text($text) + public static function htmlize_comment_text($text, ?TextprocessorRepository $textprocessors = null) { global $ratatoeskr_settings; - return kses(textprocessor_apply($text, $ratatoeskr_settings["comment_textprocessor"]), [ + $textprocessors = $textprocessors ?? Env::getGlobal()->textprocessors(); + + return kses($textprocessors->mustApply($text, $ratatoeskr_settings["comment_textprocessor"]), [ "a" => ["href" => 1, "hreflang" => 1, "title" => 1, "rel" => 1, "rev" => 1], "b" => [], "i" => [], diff --git a/ratatoeskr/sys/plugin_api.php b/ratatoeskr/sys/plugin_api.php index c286fdc..b85ce57 100644 --- a/ratatoeskr/sys/plugin_api.php +++ b/ratatoeskr/sys/plugin_api.php @@ -10,6 +10,8 @@ */ use r7r\ste\STECore; +use r7r\cms\sys\Env; +use r7r\cms\sys\textprocessors\LegacyTextprocessor; require_once(dirname(__FILE__) . "/models.php"); require_once(dirname(__FILE__) . "/textprocessors.php"); @@ -50,6 +52,9 @@ abstract class RatatoeskrPlugin { private $id; + /** @var Env */ + private $env; + /** @var PluginKVStorage The Key-Value-Storage for the Plugin */ protected $kvstorage; @@ -70,6 +75,7 @@ abstract class RatatoeskrPlugin global $ste, $rel_path_to_root; $this->id = $id; + $this->env = Env::getGlobal(); $this->kvstorage = new PluginKVStorage($id); $this->ste = $ste; $this->rel_path_to_root = $rel_path_to_root; @@ -151,7 +157,7 @@ abstract class RatatoeskrPlugin */ final protected function register_textprocessor($name, $fx, $visible_in_backend=true) { - textprocessor_register($name, $fx, $visible_in_backend); + $this->env->textprocessors()->register($name, new LegacyTextprocessor($fx, (bool)$visible_in_backend)); } /** diff --git a/ratatoeskr/sys/textprocessors.php b/ratatoeskr/sys/textprocessors.php index f195ef7..da52043 100644 --- a/ratatoeskr/sys/textprocessors.php +++ b/ratatoeskr/sys/textprocessors.php @@ -9,74 +9,51 @@ * See "ratatoeskr/licenses/ratatoeskr" for more information. */ -use Michelf\Markdown; +use r7r\cms\sys\Env; +use r7r\cms\sys\textprocessors\LegacyTextprocessor; +use r7r\cms\sys\textprocessors\TextprocessorRepository; require_once(dirname(__FILE__) . "/utils.php"); -/* - * Function: textprocessor_register +/** * Register a textprocessor. * - * Parameters: - * $name - The name of the textprocessor - * $fx - The textprocessor function (function($input), returns HTML) - * $visible_in_backend - Should this textprocessor be visible in the backend? Defaults to True. + * @deprecated Use {@see TextprocessorRepository::register()} of the global {@see TextprocessorRepository} as returned by {@see Env::textprocessors()}. + * + * @param string $name The name of the textprocessor + * @param callable $fx The textprocessor function (function($input), returns HTML) + * @param bool $visible_in_backend Should this textprocessor be visible in the backend? Defaults to True. */ function textprocessor_register($name, $fx, $visible_in_backend=true) { - global $textprocessors; - $textprocessors[$name] = [$fx, $visible_in_backend]; + Env::getGlobal()->textprocessors()->register($name, new LegacyTextprocessor($fx, $visible_in_backend)); } -/* - * Function: textprocessor_apply +/** * Apply a textprocessor on a text. * - * Parameters: - * $text - The input text. - * $textprocessor - The name of the textprocessor. + * @param string $text The input text. + * @param string $name The name of the textprocessor. * - * Returns: - * HTML + * @return string HTML + * @throws Exception If the textprocessor is unknown + * @deprecated Use {@see TextprocessorRepository::mustApply()} of the global {@see TextprocessorRepository} as returned by {@see Env::textprocessors()}. */ -function textprocessor_apply($text, $textprocessor) +function textprocessor_apply($text, $name) { - global $textprocessors; - if (!isset($textprocessors[$textprocessor])) { - throw new Exception("Unknown Textprocessor: $textprocessor"); - } - - $fx = @$textprocessors[$textprocessor][0]; - if (!is_callable($fx)) { - throw new Exception("Invalid Textprocessor: $textprocessor"); - } - - return call_user_func($fx, $text); + return Env::getGlobal()->textprocessors()->mustApply((string)$text, (string)$name); } -/* - * Function: textprocessor_apply_translation - * Applys a textprocessor automatically on a <Translation> object. The used textprocessor is determined by the $texttype property. +/** + * Applies a textprocessor automatically on a {@see Translation} object. * - * Parameters: - * $translationobj - The <Translation> object. + * The used textprocessor is determined by the {@see Translation::$texttype} property. * - * Returns: - * HTML + * @param Translation $translationobj + * @return string HTML + * @deprecated Use {@see Translation::applyTextprocessor()} instead */ -function textprocessor_apply_translation($translationobj) +function textprocessor_apply_translation(Translation $translationobj) { - return textprocessor_apply($translationobj->text, $translationobj->texttype); -} - -if (!isset($textprocessors)) { - $textprocessors = [ - "Markdown" => [Closure::fromCallable([Markdown::class, "defaultTransform"]), true], - "Plain Text" => [function ($text) { - return str_replace(["\r\n", "\n"], ["<br />", "<br />"], htmlesc($text)); - }, true], - "HTML" => [function ($text) { - return $text; - }, true] - ]; + return $translationobj->applyTextprocessor(Env::getGlobal()->textprocessors()); } diff --git a/ratatoeskr/sys/textprocessors/HtmlProcessor.php b/ratatoeskr/sys/textprocessors/HtmlProcessor.php new file mode 100644 index 0000000..c3f691b --- /dev/null +++ b/ratatoeskr/sys/textprocessors/HtmlProcessor.php @@ -0,0 +1,20 @@ +<?php + + +namespace r7r\cms\sys\textprocessors; + +/** + * A simple textprocessor that assumes the input already is HTML. + */ +class HtmlProcessor implements Textprocessor +{ + public function apply(string $input): string + { + return $input; + } + + public function showInBackend(): bool + { + return true; + } +} diff --git a/ratatoeskr/sys/textprocessors/LegacyTextprocessor.php b/ratatoeskr/sys/textprocessors/LegacyTextprocessor.php new file mode 100644 index 0000000..e7e5cc2 --- /dev/null +++ b/ratatoeskr/sys/textprocessors/LegacyTextprocessor.php @@ -0,0 +1,32 @@ +<?php + + +namespace r7r\cms\sys\textprocessors; + +/** + * LegacyTextprocessor is used to wrap an old-style textprocessor into an Textprocessor object. + */ +class LegacyTextprocessor implements Textprocessor +{ + /** @var callable */ + private $fx; + + /** @var bool */ + private $visible_in_backend; + + public function __construct(callable $fx, $visible_in_backend) + { + $this->fx = $fx; + $this->visible_in_backend = (bool)$visible_in_backend; + } + + public function apply(string $input): string + { + return (string)call_user_func($this->fx, $input); + } + + public function showInBackend(): bool + { + return $this->visible_in_backend; + } +} diff --git a/ratatoeskr/sys/textprocessors/MarkdownProcessor.php b/ratatoeskr/sys/textprocessors/MarkdownProcessor.php new file mode 100644 index 0000000..15f2f48 --- /dev/null +++ b/ratatoeskr/sys/textprocessors/MarkdownProcessor.php @@ -0,0 +1,22 @@ +<?php + + +namespace r7r\cms\sys\textprocessors; + +use Michelf\Markdown; + +/** + * A textprocessor that uses markdown to generate HTML. + */ +class MarkdownProcessor implements Textprocessor +{ + public function apply(string $input): string + { + return Markdown::defaultTransform($input); + } + + public function showInBackend(): bool + { + return true; + } +} diff --git a/ratatoeskr/sys/textprocessors/PlainTextProcessor.php b/ratatoeskr/sys/textprocessors/PlainTextProcessor.php new file mode 100644 index 0000000..c8f13f6 --- /dev/null +++ b/ratatoeskr/sys/textprocessors/PlainTextProcessor.php @@ -0,0 +1,22 @@ +<?php + + +namespace r7r\cms\sys\textprocessors; + +use r7r\cms\sys\Esc; + +/** + * A textprocessor that simply escapes the input string. + */ +class PlainTextProcessor implements Textprocessor +{ + public function apply(string $input): string + { + return Esc::esc($input, Esc::HTML_WITH_BR); + } + + public function showInBackend(): bool + { + return true; + } +} diff --git a/ratatoeskr/sys/textprocessors/Textprocessor.php b/ratatoeskr/sys/textprocessors/Textprocessor.php new file mode 100644 index 0000000..90c1347 --- /dev/null +++ b/ratatoeskr/sys/textprocessors/Textprocessor.php @@ -0,0 +1,19 @@ +<?php + +namespace r7r\cms\sys\textprocessors; + +/** + * Interface Textprocessor. + * + * A textprocessor turns an input into HTML. + */ +interface Textprocessor +{ + public function apply(string $input): string; + + /** + * Should this textprocessor be available to the user in the backend? + * @return bool + */ + public function showInBackend(): bool; +} diff --git a/ratatoeskr/sys/textprocessors/TextprocessorRepository.php b/ratatoeskr/sys/textprocessors/TextprocessorRepository.php new file mode 100644 index 0000000..5d918c0 --- /dev/null +++ b/ratatoeskr/sys/textprocessors/TextprocessorRepository.php @@ -0,0 +1,76 @@ +<?php + + +namespace r7r\cms\sys\textprocessors; + +use Exception; + +class TextprocessorRepository +{ + /** @var Textprocessor[] */ + private $textprocessors = []; + + + /** + * Builds a repository with the default textprocessors prepopulated. + * @return self + */ + public static function buildDefault(): self + { + $repo = new self(); + + $repo->register("Markdown", new MarkdownProcessor()); + $repo->register("Plain Text", new PlainTextProcessor()); + $repo->register("HTML", new HtmlProcessor()); + + return $repo; + } + + public function register(string $name, Textprocessor $textprocessor): void + { + $this->textprocessors[$name] = $textprocessor; + } + + public function getTextprocessor(string $name): ?Textprocessor + { + return $this->textprocessors[$name] ?? null; + } + + /** + * @return Textprocessor[] + */ + public function all(): array + { + return $this->textprocessors; + } + + /** + * Apply a textprocessor to the input text. + * + * @param string $input The input text + * @param string $name The name of the textprocessor + * @return string|null Will return null, if the textprocessor was not found + */ + public function apply(string $input, string $name): ?string + { + $textprocessor = $this->getTextprocessor($name); + return $textprocessor === null ? null : $textprocessor->apply($input); + } + + /** + * Like {@see TextprocessorRepository::apply()}, but will throw an exception instead of returning null, if the textprocessor was not found. + * + * @param string $input The input text + * @param string $name The name of the textprocessor + * @return string + * @throws Exception + */ + public function mustApply(string $input, string $name): string + { + $out = $this->apply($input, $name); + if ($out === null) { + throw new Exception("Unknown Textprocessor: $name"); + } + return $out; + } +} |