8000 [ErrorHandler] Move FileLinkFormatter from HttpKernel component to Er… · symfony/symfony@e79903d · GitHub
[go: up one dir, main page]

Skip to content

Commit e79903d

Browse files
committed
[ErrorHandler] Move FileLinkFormatter from HttpKernel component to ErrorHandler component
- Add tests for file link format path mapping parameters - Deprecate Symfony\Component\HttpKernel\Debug\FileLinkFormatter
1 parent 81c102d commit e79903d

File tree

3 files changed

+154
-98
lines changed

3 files changed

+154
-98
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ErrorHandler\ErrorRenderer;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\RequestStack;
16+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
17+
18+
/**
19+
* Formats debug file links.
20+
*
21+
* @author Jérémy Romey <jeremy@free-agent.fr>
22+
*/
23+
class FileLinkFormatter
24+
{
25+
private array|false $fileLinkFormat;
26+
private ?RequestStack $requestStack = null;
27+
private ?string $baseDir = null;
28+
private \Closure|string|null $urlFormat;
29+
30+
/**
31+
* @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand
32+
*/
33+
public function __construct(string|array $fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, string|\Closure $urlFormat = null)
34+
{
35+
$fileLinkFormat ??= $_ENV['SYMFONY_IDE'] ?? $_SERVER['SYMFONY_IDE'] ?? '';
36+
37+
if (!\is_array($f = $fileLinkFormat)) {
38+
$f = (ErrorRendererInterface::IDE_LINK_FORMATS[$f] ?? $f) ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l';
39+
$i = strpos($f, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f);
40+
$fileLinkFormat = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE);
41+
}
42+
43+
$this->fileLinkFormat = $fileLinkFormat;
44+
$this->requestStack = $requestStack;
45+
$this->baseDir = $baseDir;
46+
$this->urlFormat = $urlFormat;
47+
}
48+
49+
/**
50+
* @return string|false
51+
*/
52+
public function format(string $file, int $line): string|bool
53+
{
54+
if ($fmt = $this->getFileLinkFormat()) {
55+
for ($i = 1; isset($fmt[$i]); ++$i) {
56+
if (str_starts_with($file, $k = $fmt[$i++])) {
57+
$file = substr_replace($file, $fmt[$i], 0, \strlen($k));
58+
break;
59+
}
60+
}
61+
62+
return strtr($fmt[0], ['%f' => $file, '%l' => $line]);
63+
}
64+
65+
return false;
66+
}
67+
68+
/**
69+
* @internal
70+
*/
71+
public function __sleep(): array
72+
{
73+
$this->fileLinkFormat = $this->getFileLinkFormat();
74+
75+
return ['fileLinkFormat'];
76+
}
77+
78+
/**
79+
* @internal
80+
*/
81+
public static function generateUrlFormat(UrlGeneratorInterface $router, string $routeName, string $queryString): ?string
82+
{
83+
try {
84+
return $router->generate($routeName).$queryString;
85+
} catch (\Throwable) {
86+
return null;
87+
}
88+
}
89+
90+
private function getFileLinkFormat(): array|false
91+
{
92+
if ($this->fileLinkFormat) {
93+
return $this->fileLinkFormat;
94+
}
95+
96+
if ($this->requestStack && $this->baseDir && $this->urlFormat) {
97+
$request = $this->requestStack->getMainRequest();
98+
99+
if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) {
100+
return [
101+
$request->getSchemeAndHttpHost().$this->urlFormat,
102+
$this->baseDir.\DIRECTORY_SEPARATOR, '',
103+
];
104+
}
105+
}
106+
107+
return false;
108+
}
109+
}

src/Symfony/Component/HttpKernel/Tests/Debug/FileLinkFormatterTest.php renamed to src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/FileLinkFormatterTest.php

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace Symfony\Component\HttpKernel\Tests\Debug;
12+
namespace Symfony\Component\ErrorHandler\Tests\ErrorRenderer;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
1516
use Symfony\Component\HttpFoundation\Request;
1617
use Symfony\Component\HttpFoundation\RequestStack;
17-
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
1818

1919
class FileLinkFormatterTest extends TestCase
2020
{
@@ -76,8 +76,48 @@ public function testIdeFileLinkFormat()
7676
$this->assertSame("atom://core/open/file?filename=$file&line=3", $sut->format($file, 3));
7777
}
7878

79+
/**
80+
* @dataProvider providePathMappings
81+
*/
82+
public function testIdeFileLinkFormatWithPathMappingParameters($mappings)
83+
{
84+
$params = array_reduce($mappings, function ($c, $m) {
85+
return "$c&".implode('>', $m);
86+
}, '');
87+
$sut = new FileLinkFormatter("vscode://file/%f:%l$params");
88+
10000 foreach ($mappings as $mapping) {
89+
$fileGuest = $mapping['guest'].'file.php';
90+
$fileHost = $mapping['host'].'file.php';
91+
$this->assertSame("vscode://file/$fileHost:3", $sut->format($fileGuest, 3));
92+
}
93+
}
94+
7995
public function testSerialize()
8096
{
8197
$this->assertInstanceOf(FileLinkFormatter::class, unserialize(serialize(new FileLinkFormatter())));
8298
}
99+
100+
public function providePathMappings()
101+
{
102+
yield 'single path mapping' => [
103+
[
104+
[
105+
'guest' => '/var/www/app/',
106+
'host' => '/user/name/project/',
107+
],
108+
],
109+
];
110+
yield 'multiple path mapping' => [
111+
[
112+
[
113+
'guest' => '/var/www/app/',
114+
'host' => '/user/name/project/',
115+
],
116+
[
117+
'guest' => '/var/www/app2/',
118+
'host' => '/user/name/project2/',
119+
],
120+
],
121+
];
122+
}
83123
}

src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php

Lines changed: 3 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -11,102 +11,9 @@
1111

1212
namespace Symfony\Component\HttpKernel\Debug;
1313

14-
use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface;
15-
use Symfony\Component\HttpFoundation\Request< F987 /span>;
16-
use Symfony\Component\HttpFoundation\RequestStack;
17-
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
14+
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter as NewFileLinkFormatter;
1815

19-
/**
20-
* Formats debug file links.
21-
*
22-
* @author Jérémy Romey <jeremy@free-agent.fr>
23-
*
24-
* @final
25-
*/
26-
class FileLinkFormatter
16+
/** @deprecated since 6.4, use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter */
17+
class FileLinkFormatter extends NewFileLinkFormatter
2718
{
28-
private array|false $fileLinkFormat;
29-
private ?RequestStack $requestStack = null;
30-
private ?string $baseDir = null;
31-
private \Closure|string|null $urlFormat;
32-
33-
/**
34-
* @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand
35-
*/
36-
public function __construct(string|array $fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, string|\Closure $urlFormat = null)
37-
{
38-
$fileLinkFormat ??= $_ENV['SYMFONY_IDE'] ?? $_SERVER['SYMFONY_IDE'] ?? '';
39-
40-
if (!\is_array($f = $fileLinkFormat)) {
41-
$f = (ErrorRendererInterface::IDE_LINK_FORMATS[$f] ?? $f) ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l';
42-
$i = strpos($f, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f);
43-
$fileLinkFormat = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE);
44-
}
45-
46-
$this->fileLinkFormat = $fileLinkFormat;
47-
$this->requestStack = $requestStack;
48-
$this->baseDir = $baseDir;
49-
$this->urlFormat = $urlFormat;
50-
}
51-
52-
/**
53-
* @return string|false
54-
*/
55-
public function format(string $file, int $line): string|bool
56-
{
57-
if ($fmt = $this->getFileLinkFormat()) {
58-
for ($i = 1; isset($fmt[$i]); ++$i) {
59-
if (str_starts_with($file, $k = $fmt[$i++])) {
60-
$file = substr_replace($file, $fmt[$i], 0, \strlen($k));
61-
break;
62-
}
63-
}
64-
65-
return strtr($fmt[0], ['%f' => $file, '%l' => $line]);
66-
}
67-
68-
return false;
69-
}
70-
71-
/**
72-
* @internal
73-
*/
74-
public function __sleep(): array
75-
{
76-
$this->fileLinkFormat = $this->getFileLinkFormat();
77-
78-
return ['fileLinkFormat'];
79-
}
80-
81-
/**
82-
* @internal
83-
*/
84-
public static function generateUrlFormat(UrlGeneratorInterface $router, string $routeName, string $queryString): ?string
85-
{
86-
try {
87-
return $router->generate($routeName).$queryString;
88-
} catch (\Throwable) {
89-
return null;
90-
}
91-
}
92-
93-
private function getFileLinkFormat(): array|false
94-
{
95-
if ($this->fileLinkFormat) {
96-
return $this->fileLinkFormat;
97-
}
98-
99-
if ($this->requestStack && $this->baseDir && $this->urlFormat) {
100-
$request = $this->requestStack->getMainRequest();
101-
102-
if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) {
103-
return [
104-
$request->getSchemeAndHttpHost().$this->urlFormat,
105-
$this->baseDir.\DIRECTORY_SEPARATOR, '',
106-
];
107-
}
108-
}
109-
110-
return false;
111-
}
11219
}

0 commit comments

Comments
 (0)
0