Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0ec852d

Browse filesBrowse files
committed
added a relative_path Twig function
1 parent ee27ed8 commit 0ec852d
Copy full SHA for 0ec852d

File tree

Expand file treeCollapse file tree

5 files changed

+189
-3
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+189
-3
lines changed

‎src/Symfony/Bridge/Twig/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Twig/CHANGELOG.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ CHANGELOG
44
2.7.0
55
-----
66

7-
* added an HttpFoundation extension (provides the `absolute_url` function)
7+
* added an HttpFoundation extension (provides the `absolute_url` and the `relative_path` functions)
88

99
2.5.0
1010
-----

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

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php
+39-2Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace Symfony\Bridge\Twig\Extension;
1313

1414
use Symfony\Component\HttpFoundation\RequestStack;
15-
use Symfony\Component\Asset\Packages;
15+
use Symfony\Component\HttpFoundation\Request;
1616

1717
/**
1818
* Twig extension for the Symfony HttpFoundation component.
@@ -35,17 +35,20 @@ public function getFunctions()
3535
{
3636
return array(
3737
new \Twig_SimpleFunction('absolute_url', array($this, 'generateAbsoluteUrl')),
38+
new \Twig_SimpleFunction('relative_path', array($this, 'generateRelativePath')),
3839
);
3940
}
4041

4142
/**
42-
* Returns the absolute URL for the given path.
43+
* Returns the absolute URL for the given absolute or relative path.
4344
*
4445
* This method returns the path unchanged if no request is available.
4546
*
4647
* @param string $path The path
4748
*
4849
* @return string The absolute URL
50+
*
51+
* @see Request::getUriForPath()
4952
*/
5053
public function generateAbsoluteUrl($path)
5154
{
@@ -57,9 +60,43 @@ public function generateAbsoluteUrl($path)
5760
return $path;
5861
}
5962

63+
if (!$path || '/' !== $path[0]) {
64+
$prefix = $request->getPathInfo();
65+
$last = strlen($prefix) - 1;
66+
if ($last !== $pos = strrpos($prefix, '/')) {
67+
$prefix = substr($prefix, 0, $pos).'/';
68+
}
69+
70+
$path = $prefix.$path;
71+
}
72+
6073
return $request->getUriForPath($path);
6174
}
6275

76+
/**
77+
* Returns a relative path based on the current Request.
78+
*
79+
* This method returns the path unchanged if no request is available.
80+
*
81+
* @param string $path The path
82+
*
83+
* @return string The relative path
84+
*
85+
* @see Request::getRelativeUriForPath()
86+
*/
87+
public function generateRelativePath($path)
88+
{
89+
if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) {
90+
return $path;
91+
}
92+
93+
if (!$request = $this->requestStack->getMasterRequest()) {
94+
return $path;
95+
}
96+
97+
return $request->getRelativeUriForPath($path);
98+
}
99+
63100
/**
64101
* Returns the name of the extension.
65102
*
+74Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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\Bridge\Twig\Tests\Extension;
13+
14+
use Symfony\Bridge\Twig\Extension\HttpFoundationExtension;
15+
use Symfony\Component\HttpFoundation\RequestStack;
16+
use Symfony\Component\HttpFoundation\Request;
17+
18+
class HttpFoundationExtensionTest extends \PHPUnit_Framework_TestCase
19+
{
20+
/**
21+
* @dataProvider getGenerateAbsoluteUrlData()
22+
*/
23+
public function testGenerateAbsoluteUrl($expected, $path, $pathinfo)
24+
{
25+
$stack = new RequestStack();
26+
$stack->push(Request::create($pathinfo));
27+
$extension = new HttpFoundationExtension($stack);
28+
29+
$this->assertEquals($expected, $extension->generateAbsoluteUrl($path));
30+
}
31+
32+
public function getGenerateAbsoluteUrlData()
33+
{
34+
return array(
35+
array('http://localhost/foo.png', '/foo.png', '/foo/bar.html'),
36+
array('http://localhost/foo/foo.png', 'foo.png', '/foo/bar.html'),
37+
array('http://localhost/foo/foo.png', 'foo.png', '/foo/bar'),
38+
array('http://localhost/foo/bar/foo.png', 'foo.png', '/foo/bar/'),
39+
40+
array('http://example.com/baz', 'http://example.com/baz', '/'),
41+
array('https://example.com/baz', 'https://example.com/baz', '/'),
42+
array('//example.com/baz', '//example.com/baz', '/'),
43+
);
44+
}
45+
46+
/**
47+
* @dataProvider getGenerateRelativePathData()
48+
*/
49+
public function testGenerateRelativePath($expected, $path, $pathinfo)
50+
{
51+
if (!method_exists('Symfony\Component\HttpFoundation\Request', 'getRelativeUriForPath')) {
52+
$this->markTestSkipped('Your version of Symfony HttpFoundation is too old.');
53+
}
54+
55+
$stack = new RequestStack();
56+
$stack->push(Request::create($pathinfo));
57+
$extension = new HttpFoundationExtension($stack);
58+
59+
$this->assertEquals($expected, $extension->generateRelativePath($path));
60+
}
61+
62+
public function getGenerateRelativePathData()
63+
{
64+
return array(
65+
array('../foo.png', '/foo.png', '/foo/bar.html'),
66+
array('../baz/foo.png', '/baz/foo.png', '/foo/bar.html'),
67+
array('baz/foo.png', 'baz/foo.png', '/foo/bar.html'),
68+
69+
array('http://example.com/baz', 'http://example.com/baz', '/'),
70+
array('https://example.com/baz', 'https://example.com/baz', '/'),
71+
array('//example.com/baz', '//example.com/baz', '/'),
72+
);
73+
}
74+
}

‎src/Symfony/Component/HttpFoundation/Request.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Request.php
+55Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,61 @@ public function getUriForPath($path)
11371137
return $this->getSchemeAndHttpHost().$this->getBaseUrl().$path;
11381138
}
11391139

1140+
/**
1141+
* Returns the path as relative reference from the current Request path.
1142+
*
1143+
* Only the URIs path component (no schema, host etc.) is relevant and must be given.
1144+
* Both paths must be absolute and not contain relative parts.
1145+
* Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
1146+
* Furthermore, they can be used to reduce the link size in documents.
1147+
*
1148+
* Example target paths, given a base path of "/a/b/c/d":
1149+
* - "/a/b/c/d" -> ""
1150+
* - "/a/b/c/" -> "./"
1151+
* - "/a/b/" -> "../"
1152+
* - "/a/b/c/other" -> "other"
1153+
* - "/a/x/y" -> "../../x/y"
1154+
*
1155+
* @param string $path The target path
1156+
*
1157+
* @return string The relative target path
1158+
*/
1159+
public function getRelativeUriForPath($path)
1160+
{
1161+
// be sure that we are dealing with an absolute path
1162+
if (!isset($path[0]) || '/' !== $path[0]) {
1163+
return $path;
1164+
}
1165+
1166+
if ($path === $basePath = $this->getPathInfo()) {
1167+
return '';
1168+
}
1169+
1170+
$sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
1171+
$targetDirs = explode('/', isset($path[0]) && '/' === $path[0] ? substr($path, 1) : $path);
1172+
array_pop($sourceDirs);
1173+
$targetFile = array_pop($targetDirs);
1174+
1175+
foreach ($sourceDirs as $i => $dir) {
1176+
if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
1177+
unset($sourceDirs[$i], $targetDirs[$i]);
1178+
} else {
1179+
break;
1180+
}
1181+
}
1182+
1183+
$targetDirs[] = $targetFile;
1184+
$path = str_repeat('../', count($sourceDirs)).implode('/', $targetDirs);
1185+
1186+
// A reference to the same base directory or an empty subdirectory must be prefixed with "./".
1187+
// This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
1188+
// as the first segment of a relative-path reference, as it would be mistaken for a scheme name
1189+
// (see http://tools.ietf.org/html/rfc3986#section-4.2).
1190+
return !isset($path[0]) || '/' === $path[0]
1191+
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
1192+
? "./$path" : $path;
1193+
}
1194+
11401195
/**
11411196
* Generates the normalized query string for the Request.
11421197
*

‎src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,26 @@ public function testGetUriForPath()
575575
$this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path'));
576576
}
577577

578+
/**
579+
* @dataProvider getRelativeUriForPathData()
580+
*/
581+
public function testGetRelativeUriForPath($expected, $pathinfo, $path)
582+
{
583+
$this->assertEquals($expected, Request::create($pathinfo)->getRelativeUriForPath($path));
584+
}
585+
586+
public function getRelativeUriForPathData()
587+
{
588+
return array(
589+
array('me.png', '/foo', '/me.png'),
590+
array('../me.png', '/foo/bar', '/me.png'),
591+
array('me.png', '/foo/bar', '/foo/me.png'),
592+
array('../baz/me.png', '/foo/bar/b', '/foo/baz/me.png'),
593+
array('../../fooz/baz/me.png', '/foo/bar/b', '/fooz/baz/me.png'),
594+
array('baz/me.png', '/foo/bar/b', 'baz/me.png'),
595+
);
596+
}
597+
578598
/**
579599
* @covers Symfony\Component\HttpFoundation\Request::getUserInfo
580600
*/

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.