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_php('src/Twig/Extension/SourceExtension.php', false)|escape }}
{# End of _15.html.twig Twig template #}

<?php

namespace App\Twig\Extension;

use Symfony\Component\HttpKernel\KernelInterface;

/**
 * Source helpers for snippets.
 */
class SourceExtension extends \Twig_Extension
{
    protected $kernel;

    public $traitDocblock = <<<EOD
 * I am using a PHP trait in order to isolate each snippet in a file.
 * This code should be called from a Symfony controller extending AbstractController (as of Sf 4.2)
 * or Symfony\Bundle\FrameworkBundle\Controller\Controller (Sf <= 4.1)
 * Services are injected in the controller constructor.
EOD;

    public function __construct(KernelInterface $kernel)
    {
        $this->kernel = $kernel;
    }

    public function getFunctions(): array
    {
        return [
            new \Twig_SimpleFunction('source_php', [$this, 'getSource']),
        ];
    }

    public function getSource(string $file, bool $replaceDocBlock = true, int $linesLimit = null): string
    {
        $filename = $this->kernel->getProjectDir().'/'.$file;
        if (!file_exists($filename)) {
            throw new \InvalidArgumentException(sprintf('File "%s" not found.', $file));
        }

        // Only get x first lines only
        if (is_int($linesLimit)) {
            $lines = file($filename);
            $source = implode('', array_slice(is_array($lines) ? $lines : [], 0, $linesLimit));
        } else {
            $source = file_get_contents($filename);
        }

        if ($source && $replaceDocBlock) {
            return str_replace('%docblock%', $this->traitDocblock, $source);
        }

        return (string) $source;
    }
}

 More on Stackoverflow