Skip to content

Commit bb346b6

Browse files
committed
Added UrlHelper
1 parent 9793522 commit bb346b6

File tree

7 files changed

+286
-66
lines changed

7 files changed

+286
-66
lines changed

src/Symfony/Bridge/Twig/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ CHANGELOG
44
4.3.0
55
-----
66

7-
* added the `form_parent()` function that allows to reliably retrieve the parent form in Twig templates
7+
* added the `form_parent()` function that allows to reliably retrieve the parent form in Twig templates
8+
* deprecated `HttpFoundationExtension::generateAbsoluteUrl()` and
9+
`HttpFoundationExtension::generateRelativePath`
810

911
4.2.0
1012
-----

src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php

Lines changed: 30 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\HttpFoundation\Request;
1515
use Symfony\Component\HttpFoundation\RequestStack;
1616
use Symfony\Component\Routing\RequestContext;
17+
use Symfony\Component\Routing\UrlHelper;
1718
use Twig\Extension\AbstractExtension;
1819
use Twig\TwigFunction;
1920

@@ -24,13 +25,27 @@
2425
*/
2526
class HttpFoundationExtension extends AbstractExtension
2627
{
27-
private $requestStack;
28-
private $requestContext;
28+
private $urlHelper;
2929

30-
public function __construct(RequestStack $requestStack, RequestContext $requestContext = null)
30+
public function __construct($urlHelper, RequestContext $requestContext = null)
3131
{
32-
$this->requestStack = $requestStack;
33-
$this->requestContext = $requestContext;
32+
if ($urlHelper instanceof UrlHelper) {
33+
$this->urlHelper = $urlHelper;
34+
35+
return;
36+
}
37+
38+
if (!$urlHelper instanceof RequestStack) {
39+
throw new \InvalidArgumentException(sprintf('The first argument must be an instance of "%s" or an instance of "%s".', UrlHelper::class, RequestStack::class));
40+
}
41+
42+
@trigger_error(sprintf('Passing an instance of "%s" as the first constructor argument is deprecated since Symfony 4.3, pass an instance of "%s" instead.', RequestStack::class, UrlHelper::class), E_USER_DEPRECATED);
43+
44+
if (2 === func_num_args()) {
45+
@trigger_error(sprintf('Passing the second argument to the constructor is deprecated since Symfony 4.3, pass an instance of "%s" as the first argument instead.', UrlHelper::class), E_USER_DEPRECATED);
46+
}
47+
48+
$this->urlHelper = new UrlHelper($urlHelper, $requestContext);
3449
}
3550

3651
/**
@@ -39,8 +54,8 @@ public function __construct(RequestStack $requestStack, RequestContext $requestC
3954
public function getFunctions()
4055
{
4156
return [
42-
new TwigFunction('absolute_url', [$this, 'generateAbsoluteUrl']),
43-
new TwigFunction('relative_path', [$this, 'generateRelativePath']),
57+
new TwigFunction('absolute_url', [$this->urlHelper, 'getAbsoluteUrl']),
58+
new TwigFunction('relative_path', [$this->urlHelper, 'getRelativePath']),
4459
];
4560
}
4661

@@ -54,58 +69,14 @@ public function getFunctions()
5469
* @return string The absolute URL
5570
*
5671
* @see Request::getUriForPath()
72+
*
73+
* @deprecated since Symfony 4.3, use Symfony\Component\Routing\UrlHelper::getAbsoluteUrl() instead
5774
*/
5875
public function generateAbsoluteUrl($path)
5976
{
60-
if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) {
61-
return $path;
62-
}
63-
64-
if (!$request = $this->requestStack->getMasterRequest()) {
65-
if (null !== $this->requestContext && '' !== $host = $this->requestContext->getHost()) {
66-
$scheme = $this->requestContext->getScheme();
67-
$port = '';
68-
69-
if ('http' === $scheme && 80 != $this->requestContext->getHttpPort()) {
70-
$port = ':'.$this->requestContext->getHttpPort();
71-
} elseif ('https' === $scheme && 443 != $this->requestContext->getHttpsPort()) {
72-
$port = ':'.$this->requestContext->getHttpsPort();
73-
}
74-
75-
if ('#' === $path[0]) {
76-
$queryString = $this->requestContext->getQueryString();
77-
$path = $this->requestContext->getPathInfo().($queryString ? '?'.$queryString : '').$path;
78-
} elseif ('?' === $path[0]) {
79-
$path = $this->requestContext->getPathInfo().$path;
80-
}
77+
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.3, use "%s::getAbsoluteUrl()" instead.', __METHOD__, UrlHelper::class), E_USER_DEPRECATED);
8178

82-
if ('/' !== $path[0]) {
83-
$path = rtrim($this->requestContext->getBaseUrl(), '/').'/'.$path;
84-
}
85-
86-
return $scheme.'://'.$host.$port.$path;
87-
}
88-
89-
return $path;
90-
}
91-
92-
if ('#' === $path[0]) {
93-
$path = $request->getRequestUri().$path;
94-
} elseif ('?' === $path[0]) {
95-
$path = $request->getPathInfo().$path;
96-
}
97-
98-
if (!$path || '/' !== $path[0]) {
99-
$prefix = $request->getPathInfo();
100-
$last = \strlen($prefix) - 1;
101-
if ($last !== $pos = strrpos($prefix, '/')) {
102-
$prefix = substr($prefix, 0, $pos).'/';
103-
}
104-
105-
return $request->getUriForPath($prefix.$path);
106-
}
107-
108-
return $request->getSchemeAndHttpHost().$path;
79+
return $this->urlHelper->getAbsoluteUrl($path);
10980
}
11081

11182
/**
@@ -118,18 +89,14 @@ public function generateAbsoluteUrl($path)
11889
* @return string The relative path
11990
*
12091
* @see Request::getRelativeUriForPath()
92+
*
93+
* @deprecated since Symfony 4.3, use Symfony\Component\Routing\UrlHelper::getRelativePath() instead
12194
*/
12295
public function generateRelativePath($path)
12396
{
124-
if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) {
125-
return $path;
126-
}
127-
128-
if (!$request = $this->requestStack->getMasterRequest()) {
129-
return $path;
130-
}
97+
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.3, use "%s::getRelativePath()" instead.', __METHOD__, UrlHelper::class), E_USER_DEPRECATED);
13198

132-
return $request->getRelativeUriForPath($path);
99+
return $this->urlHelper->getRelativePath($path);
133100
}
134101

135102
/**

src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@
8888
</service>
8989
<service id="Symfony\Component\Routing\RequestContext" alias="router.request_context" />
9090

91+
<service id="router.url_helper" class="Symfony\Component\Routing\UrlHelper">
92+
<argument type="service" id="request_stack" />
93+
<argument type="service" id="router.request_context" />
94+
</service>
95+
<service id="Symfony\Component\Routing\UrlHelper" alias="router.url_helper" />
96+
9197
<service id="router.cache_warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\RouterCacheWarmer">
9298
<tag name="container.service_subscriber" id="router" />
9399
<tag name="kernel.cache_warmer" />

src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,7 @@
108108
</service>
109109

110110
<service id="twig.extension.httpfoundation" class="Symfony\Bridge\Twig\Extension\HttpFoundationExtension">
111-
<argument type="service" id="request_stack" />
112-
<argument type="service" id="router.request_context" on-invalid="ignore" />
111+
<argument type="service" id="router.url_helper" />
113112
</service>
114113

115114
<service id="twig.extension.debug" class="Twig\Extension\DebugExtension" />

src/Symfony/Component/Routing/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ CHANGELOG
1111
* deprecated implementing `Serializable` for `Route` and `CompiledRoute`; if you serialize them, please
1212
ensure your unserialization logic can recover from a failure related to an updated serialization format
1313
* exposed `utf8` Route option, defaults "locale" and "format" in configuration loaders and configurators
14+
* added `UrlHelper` that allows to get an absolute URL and a relative path for a given path
1415

1516
4.2.0
1617
-----
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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\Routing\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\RequestStack;
17+
use Symfony\Component\Routing\RequestContext;
18+
use Symfony\Component\Routing\UrlHelper;
19+
20+
class UrlHelperTest extends TestCase
21+
{
22+
/**
23+
* @dataProvider getGenerateAbsoluteUrlData()
24+
*/
25+
public function testGenerateAbsoluteUrl($expected, $path, $pathinfo)
26+
{
27+
$stack = new RequestStack();
28+
$stack->push(Request::create($pathinfo));
29+
$helper = new UrlHelper($stack);
30+
31+
$this->assertEquals($expected, $helper->getAbsoluteUrl($path));
32+
}
33+
34+
public function getGenerateAbsoluteUrlData()
35+
{
36+
return [
37+
['http://localhost/foo.png', '/foo.png', '/foo/bar.html'],
38+
['http://localhost/foo/foo.png', 'foo.png', '/foo/bar.html'],
39+
['http://localhost/foo/foo.png', 'foo.png', '/foo/bar'],
40+
['http://localhost/foo/bar/foo.png', 'foo.png', '/foo/bar/'],
41+
42+
['http://example.com/baz', 'http://example.com/baz', '/'],
43+
['https://example.com/baz', 'https://example.com/baz', '/'],
44+
['//example.com/baz', '//example.com/baz', '/'],
45+
46+
['http://localhost/foo/bar?baz', '?baz', '/foo/bar'],
47+
['http://localhost/foo/bar?baz=1', '?baz=1', '/foo/bar?foo=1'],
48+
['http://localhost/foo/baz?baz=1', 'baz?baz=1', '/foo/bar?foo=1'],
49+
50+
['http://localhost/foo/bar#baz', '#baz', '/foo/bar'],
51+
['http://localhost/foo/bar?0#baz', '#baz', '/foo/bar?0'],
52+
['http://localhost/foo/bar?baz=1#baz', '?baz=1#baz', '/foo/bar?foo=1'],
53+
['http://localhost/foo/baz?baz=1#baz', 'baz?baz=1#baz', '/foo/bar?foo=1'],
54+
];
55+
}
56+
57+
/**
58+
* @dataProvider getGenerateAbsoluteUrlRequestContextData
59+
*/
60+
public function testGenerateAbsoluteUrlWithRequestContext($path, $baseUrl, $host, $scheme, $httpPort, $httpsPort, $expected)
61+
{
62+
if (!class_exists('Symfony\Component\Routing\RequestContext')) {
63+
$this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.');
64+
}
65+
66+
$requestContext = new RequestContext($baseUrl, 'GET', $host, $scheme, $httpPort, $httpsPort, $path);
67+
$helper = new UrlHelper(new RequestStack(), $requestContext);
68+
69+
$this->assertEquals($expected, $helper->getAbsoluteUrl($path));
70+
}
71+
72+
/**
73+
* @dataProvider getGenerateAbsoluteUrlRequestContextData
74+
*/
75+
public function testGenerateAbsoluteUrlWithoutRequestAndRequestContext($path)
76+
{
77+
if (!class_exists('Symfony\Component\Routing\RequestContext')) {
78+
$this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.');
79+
}
80+
81+
$helper = new UrlHelper(new RequestStack());
82+
83+
$this->assertEquals($path, $helper->getAbsoluteUrl($path));
84+
}
85+
86+
public function getGenerateAbsoluteUrlRequestContextData()
87+
{
88+
return [
89+
['/foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo.png'],
90+
['foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo/foo.png'],
91+
['foo.png', '/foo/bar/', 'localhost', 'http', 80, 443, 'http://localhost/foo/bar/foo.png'],
92+
['/foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo.png'],
93+
['foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo/foo.png'],
94+
['foo.png', '/foo/bar/', 'localhost', 'https', 80, 443, 'https://localhost/foo/bar/foo.png'],
95+
['/foo.png', '/foo', 'localhost', 'http', 443, 80, 'http://localhost:443/foo.png'],
96+
['/foo.png', '/foo', 'localhost', 'https', 443, 80, 'https://localhost:80/foo.png'],
97+
];
98+
}
99+
100+
public function testGenerateAbsoluteUrlWithScriptFileName()
101+
{
102+
$request = Request::create('http://localhost/app/web/app_dev.php');
103+
$request->server->set('SCRIPT_FILENAME', '/var/www/app/web/app_dev.php');
104+
105+
$stack = new RequestStack();
106+
$stack->push($request);
107+
$helper = new UrlHelper($stack);
108+
109+
$this->assertEquals(
110+
'http://localhost/app/web/bundles/framework/css/structure.css',
111+
$helper->getAbsoluteUrl('/app/web/bundles/framework/css/structure.css')
112+
);
113+
}
114+
115+
/**
116+
* @dataProvider getGenerateRelativePathData()
117+
*/
118+
public function testGenerateRelativePath($expected, $path, $pathinfo)
119+
{
120+
if (!method_exists('Symfony\Component\HttpFoundation\Request', 'getRelativeUriForPath')) {
121+
$this->markTestSkipped('Your version of Symfony HttpFoundation is too old.');
122+
}
123+
124+
$stack = new RequestStack();
125+
$stack->push(Request::create($pathinfo));
126+
$urlHelper = new UrlHelper($stack);
127+
128+
$this->assertEquals($expected, $urlHelper->getRelativePath($path));
129+
}
130+
131+
public function getGenerateRelativePathData()
132+
{
133+
return [
134+
['../foo.png', '/foo.png', '/foo/bar.html'],
135+
['../baz/foo.png', '/baz/foo.png', '/foo/bar.html'],
136+
['baz/foo.png', 'baz/foo.png', '/foo/bar.html'],
137+
138+
['http://example.com/baz', 'http://example.com/baz', '/'],
139+
['https://example.com/baz', 'https://example.com/baz', '/'],
140+
['//example.com/baz', '//example.com/baz', '/'],
141+
];
142+
}
143+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy