Show the source code of any file in a Symfony project

Published on 2019-02-08 • Modified on 2019-02-10

Well, it's in fact the Twig helper that I am using on this website to show all the snippets. You already have a native source Twig helper but it can only be used to show source of templates. This one is more generic and will allow you to show the source of any file of your project. (therefore, be sure that the parameters you pass to it are secured). At top you see the content of the _15.html.twig template dumped with the native one and below the source of the new one which is therefore used to display it's own content.
PS: You can remove the str_replace() part as it is specific to this project. Check out the code of a Symfony runnable snippet to understand why. 😉


{{ source('snippet/code/_15.html.twig')|escape }}
{{ source_part('src/Twig/Extension/SourceExtension.php', false)|escape }}
{# End of _15.html.twig Twig template #}

<?php

declare(strict_types=1);

namespace App\Twig\Extension;

use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;

use function Symfony\Component\String\u;

/**
 * Source helpers for snippets.
 */
final class SourceExtension extends AbstractExtension
{
    public function __construct(
        readonly private KernelInterface $kernel,
        readonly private TranslatorInterface $translator,
        readonly private bool $emptySnippets, // config/services.yaml
    ) {
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('source_part', $this->getSourcePart(...)),
        ];
    }

    public function getFilters(): array
    {
        return [
            new TwigFilter('post90_cleanup', $this->post90Cleanup(...)),
        ];
    }

    /**
     * Can show a exact part of a file.
     */
    public function getSourcePart(string $file, bool $replaceDocBlock = true, int $start = 1, ?int $end = null): string
    {
        if ($this->emptySnippets) {
            return '';
        }

        $filename = $this->kernel->getProjectDir().'/'.$file;
        if (!is_file($filename)) {
            throw new \InvalidArgumentException(\sprintf('File "%s" not found.', $file));
        }

        $sourceArr = file($filename);
        if (!\is_array($sourceArr)) {
            throw new \RuntimeException("Can't get file.");
        }

        // Take the last line
        if ($end === null) {
            $end = \count($sourceArr);
        }

        $source = implode('', \array_slice($sourceArr, $start - 1, $end - $start + 1));
        if ($replaceDocBlock) {
            $source = $this->replaceDocBlocks($source);
        }

        return u($source)->trimEnd()->toString();
    }

    private function replaceDocBlocks(string $source): string
    {
        $search = [
            '%docblock1%' => $this->translator->trans('docblock1', [], 'snippet'), // PHP
            '%docblock2%' => $this->translator->trans('docblock2', [], 'snippet'),
            '%docblock3%' => $this->translator->trans('docblock3', [], 'snippet'),
            '%docblock4%' => $this->translator->trans('docblock4', [], 'snippet'),

            '%jsDocblock1%' => $this->translator->trans('jsDocblock1', [], 'snippet'),
            '%jsDocblock2%' => $this->translator->trans('jsDocblock2', [], 'snippet'),
            '%jsDocblock3%' => $this->translator->trans('jsDocblock3', [], 'snippet'),
        ];

        return str_replace(array_keys($search), $search, $source);
    }

    public function post90Cleanup(string $html): string
    {
        $search = [
            '<p>',
            '<ul>',
            '<table>',
            '<img ',
            'href="LICENSE"',
        ];
        $replace = [
            '<p class="h4 justify">',
            '<ul class="h4">',
            '<table class="table">',
            '<img width="500px" ',
            'href="https://github.com/strangebuzz/cache-watcher/blob/master/LICENSE"',
        ];

        return str_replace($search, $replace, $html);
    }
}

 More on Stackoverflow  Random snippet

  Work with me!