diff --git a/migrations/Version20250422222542.php b/migrations/Version20250422222542.php new file mode 100644 index 0000000..1ca3290 --- /dev/null +++ b/migrations/Version20250422222542.php @@ -0,0 +1,38 @@ +addSql(<<<'SQL' + ALTER TABLE snip ADD parser VARCHAR(255) NOT NULL + SQL); + $this->addSql(<<<'SQL' + UPDATE snip SET parser = 'generic' + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + ALTER TABLE snip DROP parser + SQL); + } +} diff --git a/src/Controller/SnipController.php b/src/Controller/SnipController.php index bd57515..bc2774a 100644 --- a/src/Controller/SnipController.php +++ b/src/Controller/SnipController.php @@ -8,7 +8,7 @@ use App\Form\SnipType; use App\Repository\SnipRepository; use App\Security\Voter\SnipVoter; use App\Service\SnipContent\SnipContentService; -use App\Service\SnipParser\Pipeline; +use App\Service\SnipParser\ParserFactory; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\HttpFoundation\Request; @@ -42,23 +42,23 @@ class SnipController extends AbstractController } #[Route('/single/{snip}', name: '_single')] - public function single(Snip $snip, Pipeline $pl): Response + public function single(Snip $snip, ParserFactory $pf): Response { $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); return $this->render('snip/single.html.twig', [ 'snip' => $snip, - 'content' => $pl->parse($this->contentService->getActiveText($snip)), + 'content' => $pf->getBySnip($snip)->parseView($this->contentService->getActiveText($snip)), ]); } #[Route('/raw/{snip}', name: '_raw')] - public function raw(Snip $snip, Pipeline $pl, Request $request): Response + public function raw(Snip $snip, ParserFactory $pf, Request $request): Response { $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); $response = new Response( - $pl->clean($this->contentService->getActiveText($snip)), + $pf->getBySnip($snip)->parseRaw($this->contentService->getActiveText($snip)), Response::HTTP_OK, ['Content-Type' => 'text/html'] ); diff --git a/src/Entity/Snip.php b/src/Entity/Snip.php index bd4e99f..d0313c3 100644 --- a/src/Entity/Snip.php +++ b/src/Entity/Snip.php @@ -30,6 +30,9 @@ class Snip #[ORM\ManyToOne] private ?SnipContent $activeVersion = null; + #[ORM\Column(length: 255)] + private ?string $parser = null; + public function __construct() { $this->snipContents = new ArrayCollection(); @@ -115,4 +118,16 @@ class Snip return $this; } + + public function getParser(): ?string + { + return $this->parser; + } + + public function setParser(string $parser): static + { + $this->parser = $parser; + + return $this; + } } diff --git a/src/Form/SnipType.php b/src/Form/SnipType.php index 28b3e65..6471132 100644 --- a/src/Form/SnipType.php +++ b/src/Form/SnipType.php @@ -3,17 +3,28 @@ namespace App\Form; use App\Entity\Snip; +use App\Service\SnipParser\ParserFactory; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class SnipType extends AbstractType { + public function __construct( + private readonly ParserFactory $parserFactory, + ) {} + public function buildForm(FormBuilderInterface $builder, array $options): void { + dump(iterator_to_array($this->parserFactory->getChoices())); $builder ->add('name') + ->add('parser', ChoiceType::class, [ + 'choice_label' => fn(string $parser) => ucfirst($parser), + 'choices' => $this->parserFactory->getChoices(), + ]) ->add('content', TextareaType::class, [ 'attr' => ['rows' => 20], 'mapped' => false, diff --git a/src/Service/SnipParser/AbstractParser.php b/src/Service/SnipParser/AbstractParser.php new file mode 100644 index 0000000..9c0c53d --- /dev/null +++ b/src/Service/SnipParser/AbstractParser.php @@ -0,0 +1,16 @@ +build() ; - return $pipeline->process($payload); + return $pipeline->process($content); } - public function clean(string $payload): string + public function parseRaw(string $content): string { return str_replace( ['```', '``'], '', - $payload + $content ); } } \ No newline at end of file diff --git a/src/Service/SnipParser/Stages/HtmlEscapeStage.php b/src/Service/SnipParser/Generic/HtmlEscapeStage.php similarity index 88% rename from src/Service/SnipParser/Stages/HtmlEscapeStage.php rename to src/Service/SnipParser/Generic/HtmlEscapeStage.php index 521b784..31c9496 100644 --- a/src/Service/SnipParser/Stages/HtmlEscapeStage.php +++ b/src/Service/SnipParser/Generic/HtmlEscapeStage.php @@ -1,6 +1,6 @@ %s', $matches[0]); } - return $this->pipeline->parse( + return $this->pipeline->parseView( $this->snipContentService->rebuildText($content) ); }, $payload); diff --git a/src/Service/SnipParser/Stages/ReplaceBlocksStage.php b/src/Service/SnipParser/Generic/ReplaceBlocksStage.php similarity index 95% rename from src/Service/SnipParser/Stages/ReplaceBlocksStage.php rename to src/Service/SnipParser/Generic/ReplaceBlocksStage.php index 2350063..cc5907c 100644 --- a/src/Service/SnipParser/Stages/ReplaceBlocksStage.php +++ b/src/Service/SnipParser/Generic/ReplaceBlocksStage.php @@ -1,6 +1,6 @@ $id + * + * @return T + * @throws ServiceNotFoundException + */ + public function get(string $id): ParserInterface + { + return $this->locator->get($id); + } + + public function getBySnip(Snip $snip): ParserInterface + { + $parser = $snip->getParser(); + if (null === $parser) { + throw new ServiceNotFoundException(sprintf('Unknown parser for snip "%s"', $snip->getParser())); + } + + return $this->get($parser); + } + + /** + * @return iterable + */ + public function getAll(): iterable + { + return $this->locator->getIterator(); + } + + public function getChoices(): iterable + { + foreach ($this->getAll() as $parser) yield $parser::getName(); + } +} \ No newline at end of file diff --git a/src/Service/SnipParser/ParserInterface.php b/src/Service/SnipParser/ParserInterface.php new file mode 100644 index 0000000..404b34b --- /dev/null +++ b/src/Service/SnipParser/ParserInterface.php @@ -0,0 +1,15 @@ +%s', htmlspecialchars($content)); + } +} \ No newline at end of file diff --git a/templates/base/navbar.html.twig b/templates/base/navbar.html.twig index af6696c..86c5593 100644 --- a/templates/base/navbar.html.twig +++ b/templates/base/navbar.html.twig @@ -35,6 +35,9 @@ Logout {% else %} +