Allow code in-lining instead of everything

Create snip content parser
This commit is contained in:
Tim 2023-04-06 22:50:54 +02:00
parent f20608082a
commit bf63b7a274
7 changed files with 134 additions and 5 deletions

View File

@ -11,6 +11,7 @@
"doctrine/doctrine-bundle": "^2.9", "doctrine/doctrine-bundle": "^2.9",
"doctrine/doctrine-migrations-bundle": "^3.2", "doctrine/doctrine-migrations-bundle": "^3.2",
"doctrine/orm": "^2.14", "doctrine/orm": "^2.14",
"league/pipeline": "^1.0",
"symfony/console": "6.2.*", "symfony/console": "6.2.*",
"symfony/dotenv": "6.2.*", "symfony/dotenv": "6.2.*",
"symfony/flex": "^2", "symfony/flex": "^2",

59
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "975714eae301e2eb9cd72cfce038b337", "content-hash": "b0fef3f4465b9668205a6b695498c329",
"packages": [ "packages": [
{ {
"name": "czproject/git-php", "name": "czproject/git-php",
@ -1367,6 +1367,63 @@
}, },
"time": "2022-05-23T21:33:49+00:00" "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", "name": "monolog/monolog",
"version": "3.3.1", "version": "3.3.1",

View File

@ -7,6 +7,7 @@ use App\Form\ConfirmationType;
use App\Form\SnipType; use App\Form\SnipType;
use App\Repository\SnipRepository; use App\Repository\SnipRepository;
use App\Security\Voter\SnipVoter; use App\Security\Voter\SnipVoter;
use App\Service\SnipParser\Pipeline;
use App\Service\SnipServiceFactory; use App\Service\SnipServiceFactory;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@ -29,7 +30,7 @@ class SnipController extends AbstractController
{ {
return $this->render('snip/index.html.twig', [ return $this->render('snip/index.html.twig', [
'snips' => $this->repository->findByUser($this->getUser()), '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', [ return $this->render('snip/index.html.twig', [
'snips' => $this->repository->findPublic($this->getUser()), 'snips' => $this->repository->findPublic($this->getUser()),
'title' => 'Public Snips' 'title' => 'Public Snips',
]); ]);
} }
#[Route('/single/{snip}', name: '_single')] #[Route('/single/{snip}', name: '_single')]
public function single(Snip $snip): Response public function single(Snip $snip): Response
{ {
$snipParser = new Pipeline();
$this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip);
$snipService = $this->snipServiceFactory->create($snip); $snipService = $this->snipServiceFactory->create($snip);
$content = $snipParser->parse(($snipService->get()));
dump($content);
return $this->render('snip/single.html.twig', [ return $this->render('snip/single.html.twig', [
'snip' => $snip, 'snip' => $snip,
'content' => $snipService->get(), 'content' => $content,
'branch' => $snipService->getRepo()->getCurrentBranchName(), 'branch' => $snipService->getRepo()->getCurrentBranchName(),
]); ]);
} }

View File

@ -0,0 +1,21 @@
<?php
namespace App\Service\SnipParser;
use App\Service\SnipParser\Stages\HtmlEscapeStage;
use App\Service\SnipParser\Stages\ReplaceBlocksStage;
use League\Pipeline\PipelineBuilder;
class Pipeline
{
public function parse(string $payload): string
{
$builder = new PipelineBuilder();
$pipeline = $builder
->add(new HtmlEscapeStage())
->add(new ReplaceBlocksStage('<pre><code>', '</code></pre>', '```'))
->build();
return $pipeline->process($payload);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Service\SnipParser\Stages;
use League\Pipeline\StageInterface;
class HtmlEscapeStage implements StageInterface
{
public function __invoke(mixed $payload): string
{
return htmlspecialchars($payload, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Service\SnipParser\Stages;
use InvalidArgumentException;
use League\Pipeline\StageInterface;
class ReplaceBlocksStage implements StageInterface
{
public function __construct(
public readonly string $openTag = '<pre><code>',
public readonly string $closeTag = '</code></pre>',
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);
}
}

View File

@ -30,7 +30,7 @@
<p class="card-text">Current branch: {{ branch }}</p> <p class="card-text">Current branch: {{ branch }}</p>
</div> </div>
<div class="card-body"> <div class="card-body">
<pre><code>{{ content }}</code></pre> {{ content|raw }}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}