vendor/contao/core-bundle/src/Controller/ContentElement/MarkdownController.php line 35

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\Controller\ContentElement;
  11. use Contao\Config;
  12. use Contao\ContentModel;
  13. use Contao\CoreBundle\InsertTag\CommonMarkExtension;
  14. use Contao\CoreBundle\InsertTag\InsertTagParser;
  15. use Contao\FilesModel;
  16. use Contao\Input;
  17. use Contao\Template;
  18. use League\CommonMark\ConverterInterface;
  19. use League\CommonMark\Environment\Environment;
  20. use League\CommonMark\Extension\Autolink\AutolinkExtension;
  21. use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
  22. use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
  23. use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
  24. use League\CommonMark\Extension\Table\TableExtension;
  25. use League\CommonMark\Extension\TaskList\TaskListExtension;
  26. use League\CommonMark\MarkdownConverter;
  27. use Symfony\Component\Filesystem\Filesystem;
  28. use Symfony\Component\HttpFoundation\Request;
  29. use Symfony\Component\HttpFoundation\Response;
  30. class MarkdownController extends AbstractContentElementController
  31. {
  32.     public static function getSubscribedServices(): array
  33.     {
  34.         $services parent::getSubscribedServices();
  35.         $services['contao.insert_tag.parser'] = InsertTagParser::class;
  36.         return $services;
  37.     }
  38.     protected function getResponse(Template $templateContentModel $modelRequest $request): Response
  39.     {
  40.         $this->initializeContaoFramework();
  41.         if ('sourceFile' === $model->markdownSource) {
  42.             $markdown $this->getContentFromFile($model->singleSRC);
  43.         } else {
  44.             $markdown $model->code ?? '';
  45.         }
  46.         if ('' === $markdown) {
  47.             return new Response();
  48.         }
  49.         $config $this->getContaoAdapter(Config::class);
  50.         $input $this->getContaoAdapter(Input::class);
  51.         $html $this->createConverter($model$request)->convert($markdown)->getContent();
  52.         $template->content $input->stripTags($html$config->get('allowedTags'), $config->get('allowedAttributes'));
  53.         return $template->getResponse();
  54.     }
  55.     /**
  56.      * Hint: This is protected on purpose, so you can override it for your app specific requirements.
  57.      * If you want to provide an extension with additional logic, consider providing your own special
  58.      * content element for that.
  59.      */
  60.     protected function createConverter(ContentModel $modelRequest $request): ConverterInterface
  61.     {
  62.         $environment = new Environment([
  63.             'external_link' => [
  64.                 'internal_hosts' => $request->getHost(),
  65.                 'open_in_new_window' => true,
  66.                 'html_class' => 'external-link',
  67.                 'noopener' => 'external',
  68.                 'noreferrer' => 'external',
  69.             ],
  70.         ]);
  71.         $environment->addExtension(new CommonMarkExtension($this->container->get('contao.insert_tag.parser')));
  72.         $environment->addExtension(new CommonMarkCoreExtension());
  73.         // Support GitHub flavoured Markdown (using the individual extensions because we don't want the
  74.         // DisallowedRawHtmlExtension which is included by default)
  75.         $environment->addExtension(new AutolinkExtension());
  76.         $environment->addExtension(new StrikethroughExtension());
  77.         $environment->addExtension(new TableExtension());
  78.         $environment->addExtension(new TaskListExtension());
  79.         // Automatically mark external links as such if we have a request
  80.         $environment->addExtension(new ExternalLinkExtension());
  81.         return new MarkdownConverter($environment);
  82.     }
  83.     private function getContentFromFile(?string $file): string
  84.     {
  85.         if (!$file) {
  86.             return '';
  87.         }
  88.         $filesAdapter $this->getContaoAdapter(FilesModel::class);
  89.         /** @var FilesModel|null $filesModel */
  90.         $filesModel $filesAdapter->findByPk($file);
  91.         if (null === $filesModel) {
  92.             return '';
  93.         }
  94.         $path $filesModel->getAbsolutePath();
  95.         if (!(new Filesystem())->exists($path)) {
  96.             return '';
  97.         }
  98.         return (string) file_get_contents($path);
  99.     }
  100. }