Skip to content

Commit

Permalink
feature #19807 [FrameworkBundle] Add %debug.file_link_format% with re…
Browse files Browse the repository at this point in the history
…mapping for IDE links (nicolas-grekas)

This PR was merged into the 3.2-dev branch.

Discussion
----------

[FrameworkBundle] Add %debug.file_link_format% with remapping for IDE links

| Q             | A
| ------------- | ---
| Branch?       | master
| New feature?  | yes
| Tests pass?   | yes
| Fixed tickets | #14340
| License       | MIT
| Doc PR        | symfony/symfony-docs#6944

`templating.helper.code.file_link_format` is a parameter that requires templating to be defined, but holds a concept that is used beyond templating borders.
Let's make it a general parameter that can be injected easily when required.

Commits
-------

1c4ca8c [FrameworkBundle] Add %debug.file_link_format% with remapping for IDE links
  • Loading branch information
fabpot committed Sep 14, 2016
2 parents 277c7fa + 1c4ca8c commit 059b436
Show file tree
Hide file tree
Showing 20 changed files with 143 additions and 76 deletions.
26 changes: 20 additions & 6 deletions src/Symfony/Bridge/Twig/Extension/CodeExtension.php
Expand Up @@ -25,13 +25,20 @@ class CodeExtension extends \Twig_Extension
/**
* Constructor.
*
* @param string $fileLinkFormat The format for links to source files
* @param string $rootDir The project root directory
* @param string $charset The charset
* @param string|array $fileLinkFormat The format for links to source files
* @param string $rootDir The project root directory
* @param string $charset The charset
*/
public function __construct($fileLinkFormat, $rootDir, $charset)
{
$this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
if ($fileLinkFormat && !is_array($fileLinkFormat)) {
$i = max(strpos($fileLinkFormat, '%f'), strpos($fileLinkFormat, '%l'));
$i = strpos($fileLinkFormat, '#', $i) ?: strlen($fileLinkFormat);
$fileLinkFormat = array(substr($fileLinkFormat, 0, $i), substr($fileLinkFormat, $i + 1));
parse_str($fileLinkFormat[1], $fileLinkFormat[1]);
}
$this->fileLinkFormat = $fileLinkFormat;
$this->rootDir = str_replace('/', DIRECTORY_SEPARATOR, dirname($rootDir)).DIRECTORY_SEPARATOR;
$this->charset = $charset;
}
Expand Down Expand Up @@ -190,8 +197,15 @@ public function formatFile($file, $line, $text = null)
*/
public function getFileLink($file, $line)
{
if ($this->fileLinkFormat && is_file($file)) {
return strtr($this->fileLinkFormat, array('%f' => $file, '%l' => $line));
if ($this->fileLinkFormat && file_exists($file)) {
foreach ($this->fileLinkFormat[1] as $k => $v) {
if (0 === strpos($file, $k)) {
$file = substr_replace($file, $v, 0, strlen($k));
break;
}
}

return strtr($this->fileLinkFormat[0], array('%f' => $file, '%l' => $line));
}

return false;
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php
Expand Up @@ -19,7 +19,7 @@ class CodeExtensionTest extends \PHPUnit_Framework_TestCase

public function testFormatFile()
{
$expected = sprintf('<a href="txmt://open?url=file://%s&amp;line=25" title="Click to open this file" class="file_link">%s at line 25</a>', __FILE__, __FILE__);
$expected = sprintf('<a href="proto://foobar%s#&amp;line=25" title="Click to open this file" class="file_link">%s at line 25</a>', substr(__FILE__, 5), __FILE__);
$this->assertEquals($expected, $this->getExtension()->formatFile(__FILE__, 25));
}

Expand Down Expand Up @@ -64,6 +64,6 @@ public function testGetName()

protected function getExtension()
{
return new CodeExtension('txmt://open?url=file://%f&line=%l', '/root', 'UTF-8');
return new CodeExtension('proto://%f#&line=%l#'.substr(__FILE__, 0, 5).'=foobar', '/root', 'UTF-8');
}
}
Expand Up @@ -33,10 +33,6 @@ public function process(ContainerBuilder $container)

$definition = $container->getDefinition('data_collector.dump');

if ($container->hasParameter('templating.helper.code.file_link_format')) {
$definition->replaceArgument(1, $container->getParameter('templating.helper.code.file_link_format'));
}

if (!$container->hasParameter('web_profiler.debug_toolbar.mode') || WebDebugToolbarListener::DISABLED === $container->getParameter('web_profiler.debug_toolbar.mode')) {
$definition->replaceArgument(3, null);
}
Expand Down
14 changes: 13 additions & 1 deletion src/Symfony/Bundle/DebugBundle/Resources/config/services.xml
Expand Up @@ -8,12 +8,13 @@
<service id="twig.extension.dump" class="Symfony\Bridge\Twig\Extension\DumpExtension" public="false">
<tag name="twig.extension" />
<argument type="service" id="var_dumper.cloner" />
<argument type="service" id="var_dumper.html_dumper" />
</service>

<service id="data_collector.dump" class="Symfony\Component\HttpKernel\DataCollector\DumpDataCollector">
<tag name="data_collector" id="dump" template="@Debug/Profiler/dump.html.twig" priority="240" />
<argument type="service" id="debug.stopwatch" on-invalid="ignore" />
<argument>null</argument><!-- %templating.helper.code.file_link_format% -->
<argument>%debug.file_link_format%</argument>
<argument>%kernel.charset%</argument>
<argument type="service" id="request_stack" />
<argument>null</argument><!-- var_dumper.cli_dumper when debug.dump_destination is set -->
Expand All @@ -29,6 +30,17 @@
<service id="var_dumper.cli_dumper" class="Symfony\Component\VarDumper\Dumper\CliDumper">
<argument>null</argument><!-- debug.dump_destination -->
<argument>%kernel.charset%</argument>
<argument>0</argument> <!-- flags -->
</service>
<service id="var_dumper.html_dumper" class="Symfony\Component\VarDumper\Dumper\HtmlDumper" public="false">
<argument>null</argument>
<argument>%kernel.charset%</argument>
<argument>0</argument> <!-- flags -->
<call method="setDisplayOptions">
<argument type="collection">
<argument key="fileLinkFormat">%debug.file_link_format%</argument>
</argument>
</call>
</service>
</services>

Expand Down
Expand Up @@ -19,20 +19,6 @@

class DumpDataCollectorPassTest extends \PHPUnit_Framework_TestCase
{
public function testProcessWithFileLinkFormatParameter()
{
$container = new ContainerBuilder();
$container->addCompilerPass(new DumpDataCollectorPass());
$container->setParameter('templating.helper.code.file_link_format', 'file-link-format');

$definition = new Definition('Symfony\Component\HttpKernel\DataCollector\DumpDataCollector', array(null, null, null, null));
$container->setDefinition('data_collector.dump', $definition);

$container->compile();

$this->assertSame('file-link-format', $definition->getArgument(1));
}

public function testProcessWithoutFileLinkFormatParameter()
{
$container = new ContainerBuilder();
Expand Down
Expand Up @@ -90,6 +90,21 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter('kernel.trusted_proxies', $config['trusted_proxies']);
$container->setParameter('kernel.default_locale', $config['default_locale']);

if (!$container->hasParameter('debug.file_link_format')) {
if (!$container->hasParameter('templating.helper.code.file_link_format')) {
$links = array(
'textmate' => 'txmt://open?url=file://%%f&line=%%l',
'macvim' => 'mvim://open?url=file://%%f&line=%%l',
'emacs' => 'emacs://open?url=file://%%f&line=%%l',
'sublime' => 'subl://open?url=file://%%f&line=%%l',
);
$ide = $config['ide'];

$container->setParameter('templating.helper.code.file_link_format', str_replace('%', '%%', ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format')) ?: (isset($links[$ide]) ? $links[$ide] : $ide));
}
$container->setParameter('debug.file_link_format', '%templating.helper.code.file_link_format%');
}

if (!empty($config['test'])) {
$loader->load('test.xml');
}
Expand Down Expand Up @@ -120,7 +135,7 @@ public function load(array $configs, ContainerBuilder $container)
}

if ($this->isConfigEnabled($container, $config['templating'])) {
$this->registerTemplatingConfiguration($config['templating'], $config['ide'], $container, $loader);
$this->registerTemplatingConfiguration($config['templating'], $container, $loader);
}

$this->registerValidationConfiguration($config['validation'], $container, $loader);
Expand Down Expand Up @@ -431,11 +446,6 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con
}

$definition->replaceArgument(4, $debug);

if ($container->hasParameter('templating.helper.code.file_link_format')) {
$definition->replaceArgument(5, '%templating.helper.code.file_link_format%');
}

$definition->replaceArgument(6, $debug);
}

Expand Down Expand Up @@ -553,25 +563,13 @@ private function registerRequestConfiguration(array $config, ContainerBuilder $c
* Loads the templating configuration.
*
* @param array $config A templating configuration array
* @param string $ide
* @param ContainerBuilder $container A ContainerBuilder instance
* @param XmlFileLoader $loader An XmlFileLoader instance
*/
private function registerTemplatingConfiguration(array $config, $ide, ContainerBuilder $container, XmlFileLoader $loader)
private function registerTemplatingConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
$loader->load('templating.xml');

if (!$container->hasParameter('templating.helper.code.file_link_format')) {
$links = array(
'textmate' => 'txmt://open?url=file://%%f&line=%%l',
'macvim' => 'mvim://open?url=file://%%f&line=%%l',
'emacs' => 'emacs://open?url=file://%%f&line=%%l',
'sublime' => 'subl://open?url=file://%%f&line=%%l',
);

$container->setParameter('templating.helper.code.file_link_format', str_replace('%', '%%', ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format')) ?: (isset($links[$ide]) ? $links[$ide] : $ide));
}

$container->setParameter('fragment.renderer.hinclude.global_template', $config['hinclude_default_template']);

if ($container->getParameter('kernel.debug')) {
Expand Down
Expand Up @@ -17,7 +17,7 @@
<argument>-1</argument><!-- Log levels map for enabled error levels -->
<argument>%debug.error_handler.throw_at%</argument>
<argument>true</argument>
<argument>null</argument><!-- %templating.helper.code.file_link_format% -->
<argument>%debug.file_link_format%</argument>
<argument>true</argument>
</service>

Expand Down
Expand Up @@ -44,7 +44,7 @@

<service id="templating.helper.code" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\CodeHelper">
<tag name="templating.helper" alias="code" />
<argument>%templating.helper.code.file_link_format%</argument>
<argument>%debug.file_link_format%</argument>
<argument>%kernel.root_dir%</argument>
<argument>%kernel.charset%</argument>
</service>
Expand Down
Expand Up @@ -27,13 +27,20 @@ class CodeHelper extends Helper
/**
* Constructor.
*
* @param string $fileLinkFormat The format for links to source files
* @param string $rootDir The project root directory
* @param string $charset The charset
* @param string|array $fileLinkFormat The format for links to source files
* @param string $rootDir The project root directory
* @param string $charset The charset
*/
public function __construct($fileLinkFormat, $rootDir, $charset)
{
$this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
if ($fileLinkFormat && !is_array($fileLinkFormat)) {
$i = max(strpos($fileLinkFormat, '%f'), strpos($fileLinkFormat, '%l'));
$i = strpos($fileLinkFormat, '#', $i) ?: strlen($fileLinkFormat);
$fileLinkFormat = array(substr($fileLinkFormat, 0, $i), substr($fileLinkFormat, $i + 1));
parse_str($fileLinkFormat[1], $fileLinkFormat[1]);
}
$this->fileLinkFormat = $fileLinkFormat;
$this->rootDir = str_replace('\\', '/', $rootDir).'/';
$this->charset = $charset;
}
Expand Down Expand Up @@ -186,7 +193,14 @@ public function formatFile($file, $line, $text = null)
public function getFileLink($file, $line)
{
if ($this->fileLinkFormat && is_file($file)) {
return strtr($this->fileLinkFormat, array('%f' => $file, '%l' => $line));
foreach ($this->fileLinkFormat[1] as $k => $v) {
if (0 === strpos($file, $k)) {
$file = substr_replace($file, $v, 0, strlen($k));
break;
}
}

return strtr($this->fileLinkFormat[0], array('%f' => $file, '%l' => $line));
}

return false;
Expand Down
Expand Up @@ -359,7 +359,7 @@ public function testFileLinkFormat()
{
$container = $this->createContainerFromFile('full');

$this->assertEquals('file%link%format', $container->getParameter('templating.helper.code.file_link_format'));
$this->assertEquals('file%link%format', $container->getParameter('debug.file_link_format'));
}

public function testValidationAnnotations()
Expand Down
Expand Up @@ -55,10 +55,6 @@ public function process(ContainerBuilder $container)
$container->getDefinition('twig.extension.httpfoundation')->addTag('twig.extension');
}

if ($container->hasParameter('templating.helper.code.file_link_format')) {
$container->getDefinition('twig.extension.code')->replaceArgument(0, $container->getParameter('templating.helper.code.file_link_format'));
}

if ($container->getParameter('kernel.debug')) {
$container->getDefinition('twig.extension.profiler')->addTag('twig.extension');
$container->getDefinition('twig.extension.debug')->addTag('twig.extension');
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml
Expand Up @@ -83,7 +83,7 @@

<service id="twig.extension.code" class="Symfony\Bridge\Twig\Extension\CodeExtension" public="false">
<tag name="twig.extension" />
<argument /> <!-- %templating.helper.code.file_link_format% -->
<argument>%debug.file_link_format%</argument>
<argument>%kernel.root_dir%</argument>
<argument>%kernel.charset%</argument>
</service>
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bundle/TwigBundle/composer.json
Expand Up @@ -31,7 +31,7 @@
"symfony/routing": "~2.8|~3.0",
"symfony/templating": "~2.8|~3.0",
"symfony/yaml": "~2.8|~3.0",
"symfony/framework-bundle": "~2.8|~3.0"
"symfony/framework-bundle": "~3.2"
},
"autoload": {
"psr-4": { "Symfony\\Bundle\\TwigBundle\\": "" },
Expand Down
12 changes: 12 additions & 0 deletions src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml
Expand Up @@ -34,6 +34,18 @@

<service id="twig.extension.webprofiler" class="Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension" public="false">
<tag name="twig.extension" />
<argument type="service">
<service class="Symfony\Component\VarDumper\Dumper\HtmlDumper">
<argument>null</argument>
<argument>%kernel.charset%</argument>
<argument type="constant">Symfony\Component\VarDumper\Dumper\HtmlDumper::DUMP_LIGHT_ARRAY</argument>
<call method="setDisplayOptions">
<argument type="collection">
<argument key="fileLinkFormat">%debug.file_link_format%</argument>
</argument>
</call>
</service>
</argument>
</service>
</services>
</container>
Expand Up @@ -56,6 +56,8 @@ protected function setUp()
$this->container->setParameter('kernel.cache_dir', __DIR__);
$this->container->setParameter('kernel.debug', false);
$this->container->setParameter('kernel.root_dir', __DIR__);
$this->container->setParameter('kernel.charset', 'UTF-8');
$this->container->setParameter('debug.file_link_format', null);
$this->container->setParameter('profiler.class', array('Symfony\\Component\\HttpKernel\\Profiler\\Profiler'));
$this->container->register('profiler', $this->getMockClass('Symfony\\Component\\HttpKernel\\Profiler\\Profiler'))
->addArgument(new Definition($this->getMockClass('Symfony\\Component\\HttpKernel\\Profiler\\ProfilerStorageInterface')));
Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Bundle/WebProfilerBundle/composer.json
Expand Up @@ -20,7 +20,8 @@
"symfony/http-kernel": "~3.1",
"symfony/polyfill-php70": "~1.0",
"symfony/routing": "~2.8|~3.0",
"symfony/twig-bridge": "~2.8|~3.0"
"symfony/twig-bridge": "~2.8|~3.0",
"symfony/var-dumper": "~3.2"
},
"require-dev": {
"symfony/config": "~2.8|~3.0",
Expand Down

0 comments on commit 059b436

Please sign in to comment.