From bf63b7a274cfc1bff528ca46d54883639de74e65 Mon Sep 17 00:00:00 2001 From: tim Date: Thu, 6 Apr 2023 22:50:54 +0200 Subject: [PATCH] Allow code in-lining instead of everything Create snip content parser --- composer.json | 1 + composer.lock | 59 ++++++++++++++++++- src/Controller/SnipController.php | 10 +++- src/Service/SnipParser/Pipeline.php | 21 +++++++ .../SnipParser/Stages/HtmlEscapeStage.php | 13 ++++ .../SnipParser/Stages/ReplaceBlocksStage.php | 33 +++++++++++ templates/snip/single.html.twig | 2 +- 7 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 src/Service/SnipParser/Pipeline.php create mode 100644 src/Service/SnipParser/Stages/HtmlEscapeStage.php create mode 100644 src/Service/SnipParser/Stages/ReplaceBlocksStage.php diff --git a/composer.json b/composer.json index aaa01f8..c1aed9e 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "doctrine/doctrine-bundle": "^2.9", "doctrine/doctrine-migrations-bundle": "^3.2", "doctrine/orm": "^2.14", + "league/pipeline": "^1.0", "symfony/console": "6.2.*", "symfony/dotenv": "6.2.*", "symfony/flex": "^2", diff --git a/composer.lock b/composer.lock index f34c252..29c6ed6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "975714eae301e2eb9cd72cfce038b337", + "content-hash": "b0fef3f4465b9668205a6b695498c329", "packages": [ { "name": "czproject/git-php", @@ -1367,6 +1367,63 @@ }, "time": "2022-05-23T21:33:49+00:00" }, + { + "name": "league/pipeline", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/pipeline.git", + "reference": "aa14b0e3133121f8be39e9a3b6ddd011fc5bb9a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/pipeline/zipball/aa14b0e3133121f8be39e9a3b6ddd011fc5bb9a8", + "reference": "aa14b0e3133121f8be39e9a3b6ddd011fc5bb9a8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "leanphp/phpspec-code-coverage": "^4.2", + "phpspec/phpspec": "^4.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Pipeline\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net", + "role": "Author" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com", + "role": "Maintainer" + } + ], + "description": "A plug and play pipeline implementation.", + "keywords": [ + "composition", + "design pattern", + "pattern", + "pipeline", + "sequential" + ], + "support": { + "issues": "https://github.com/thephpleague/pipeline/issues", + "source": "https://github.com/thephpleague/pipeline/tree/master" + }, + "time": "2018-06-05T21:06:51+00:00" + }, { "name": "monolog/monolog", "version": "3.3.1", diff --git a/src/Controller/SnipController.php b/src/Controller/SnipController.php index 3646702..9fd1d4c 100644 --- a/src/Controller/SnipController.php +++ b/src/Controller/SnipController.php @@ -7,6 +7,7 @@ use App\Form\ConfirmationType; use App\Form\SnipType; use App\Repository\SnipRepository; use App\Security\Voter\SnipVoter; +use App\Service\SnipParser\Pipeline; use App\Service\SnipServiceFactory; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -29,7 +30,7 @@ class SnipController extends AbstractController { return $this->render('snip/index.html.twig', [ 'snips' => $this->repository->findByUser($this->getUser()), - 'title' => 'My Snips' + 'title' => 'My Snips', ]); } @@ -38,18 +39,21 @@ class SnipController extends AbstractController { return $this->render('snip/index.html.twig', [ 'snips' => $this->repository->findPublic($this->getUser()), - 'title' => 'Public Snips' + 'title' => 'Public Snips', ]); } #[Route('/single/{snip}', name: '_single')] public function single(Snip $snip): Response { + $snipParser = new Pipeline(); $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); $snipService = $this->snipServiceFactory->create($snip); + $content = $snipParser->parse(($snipService->get())); + dump($content); return $this->render('snip/single.html.twig', [ 'snip' => $snip, - 'content' => $snipService->get(), + 'content' => $content, 'branch' => $snipService->getRepo()->getCurrentBranchName(), ]); } diff --git a/src/Service/SnipParser/Pipeline.php b/src/Service/SnipParser/Pipeline.php new file mode 100644 index 0000000..f31719a --- /dev/null +++ b/src/Service/SnipParser/Pipeline.php @@ -0,0 +1,21 @@ +add(new HtmlEscapeStage()) + ->add(new ReplaceBlocksStage('
', '
', '```')) + ->build(); + + return $pipeline->process($payload); + } +} \ No newline at end of file diff --git a/src/Service/SnipParser/Stages/HtmlEscapeStage.php b/src/Service/SnipParser/Stages/HtmlEscapeStage.php new file mode 100644 index 0000000..2760c0e --- /dev/null +++ b/src/Service/SnipParser/Stages/HtmlEscapeStage.php @@ -0,0 +1,13 @@ +', + public readonly string $closeTag = '', + public readonly string $delimiter = '```' + ) {} + + public function __invoke(mixed $payload): string + { + if (!is_string($payload)) { + throw new InvalidArgumentException('The payload must be a string.'); + } + + return $this->replaceCodeBlocks($payload); + } + + private function replaceCodeBlocks(string $text): string + { + $pattern = sprintf('/%s(.+?)%s/s', preg_quote($this->delimiter), preg_quote($this->delimiter)); + + return preg_replace_callback($pattern, function ($matches) { + return $this->openTag . trim($matches[1]) . $this->closeTag; + }, $text); + } +} \ No newline at end of file diff --git a/templates/snip/single.html.twig b/templates/snip/single.html.twig index f8afa51..59abe3e 100644 --- a/templates/snip/single.html.twig +++ b/templates/snip/single.html.twig @@ -30,7 +30,7 @@

Current branch: {{ branch }}

-
{{ content }}
+ {{ content|raw }}
{% endblock %}