From 378881378aab5454c84cb1fecbbcc675f64dc27f Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Fri, 25 Sep 2020 21:18:18 +0200 Subject: Refactor textprocessors They are now managed by TextprocessorRepository and are instances of Textprocessor. This replaces the global $textprocessors variable. --- ratatoeskr/backend.php | 26 ++++---- ratatoeskr/frontend.php | 7 +- ratatoeskr/sys/Env.php | 37 +++++++++++ ratatoeskr/sys/models.php | 31 ++++++--- ratatoeskr/sys/plugin_api.php | 8 ++- ratatoeskr/sys/textprocessors.php | 75 ++++++++------------- ratatoeskr/sys/textprocessors/HtmlProcessor.php | 20 ++++++ .../sys/textprocessors/LegacyTextprocessor.php | 32 +++++++++ .../sys/textprocessors/MarkdownProcessor.php | 22 +++++++ .../sys/textprocessors/PlainTextProcessor.php | 22 +++++++ ratatoeskr/sys/textprocessors/Textprocessor.php | 19 ++++++ .../sys/textprocessors/TextprocessorRepository.php | 76 ++++++++++++++++++++++ 12 files changed, 302 insertions(+), 73 deletions(-) create mode 100644 ratatoeskr/sys/Env.php create mode 100644 ratatoeskr/sys/textprocessors/HtmlProcessor.php create mode 100644 ratatoeskr/sys/textprocessors/LegacyTextprocessor.php create mode 100644 ratatoeskr/sys/textprocessors/MarkdownProcessor.php create mode 100644 ratatoeskr/sys/textprocessors/PlainTextProcessor.php create mode 100644 ratatoeskr/sys/textprocessors/Textprocessor.php create mode 100644 ratatoeskr/sys/textprocessors/TextprocessorRepository.php 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 @@ +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 object. The used textprocessor is determined by the $texttype property. +/** + * Applies a textprocessor automatically on a {@see Translation} object. * - * Parameters: - * $translationobj - The 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"], ["
", "
"], 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 @@ +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 @@ +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; + } +} -- cgit v1.2.3-54-g00ecf