Skip to content

Commit

Permalink
[TwigBundle] Add possibility to generate absolute assets urls
Browse files Browse the repository at this point in the history
  • Loading branch information
romainneutron committed Mar 14, 2014
1 parent b7c158a commit 76b8851
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 6 deletions.
49 changes: 44 additions & 5 deletions src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Bundle\TwigBundle\Extension;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\RequestContext;

/**
* Twig extension for Symfony assets helper
Expand All @@ -21,10 +22,12 @@
class AssetsExtension extends \Twig_Extension
{
private $container;
private $context;

public function __construct(ContainerInterface $container)
public function __construct(ContainerInterface $container, RequestContext $requestContext)
{
$this->container = $container;
$this->context = $requestContext;
}

/**
Expand All @@ -45,14 +48,21 @@ public function getFunctions()
*
* Absolute paths (i.e. http://...) are returned unmodified.
*
* @param string $path A public path
* @param string $packageName The name of the asset package to use
* @param string $path A public path
* @param string $packageName The name of the asset package to use
* @param Boolean $absolute Whether to return an absolute URL or a relative one
*
* @return string A public path which takes into account the base path and URL path
*/
public function getAssetUrl($path, $packageName = null)
public function getAssetUrl($path, $packageName = null, $absolute = false)
{
return $this->container->get('templating.helper.assets')->getUrl($path, $packageName);
$url = $this->container->get('templating.helper.assets')->getUrl($path, $packageName);

if (!$absolute) {
return $url;
}

return $this->ensureUrlIsAbsolute($url);
}

/**
Expand All @@ -76,4 +86,33 @@ public function getName()
{
return 'assets';
}

/**
* Ensures an URL is absolute, if possible.
*
* @param string $url The URL that has to be absolute
*
* @return string The absolute URL
*/
private function ensureUrlIsAbsolute($url)
{
if (false !== strpos($url, '://') || 0 === strpos($url, '//')) {
return $url;
}

if ('' === $host = $this->context->getHost()) {
return $url;
}

$scheme = $this->context->getScheme();
$port = '';

if ('http' === $scheme && 80 != $this->context->getHttpPort()) {
$port = ':'.$this->context->getHttpPort();
} elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) {
$port = ':'.$this->context->getHttpsPort();
}

return $scheme.'://'.$host.$port.$url;
}
}
1 change: 1 addition & 0 deletions src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml
Expand Up @@ -66,6 +66,7 @@
<service id="twig.extension.assets" class="%twig.extension.assets.class%" public="false">
<tag name="twig.extension" />
<argument type="service" id="service_container" />
<argument type="service" id="router.request_context" />
</service>

<service id="twig.extension.actions" class="%twig.extension.actions.class%" public="false">
Expand Down
106 changes: 106 additions & 0 deletions src/Symfony/Bundle/TwigBundle/Tests/Extension/AssetsExtensionTest.php
@@ -0,0 +1,106 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\TwigBundle\Tests\Extension;

use Symfony\Bundle\TwigBundle\Extension\AssetsExtension;
use Symfony\Bundle\TwigBundle\Tests\TestCase;
use Symfony\Component\Routing\RequestContext;

class AssetsExtensionTest extends TestCase
{
/**
* @dataProvider provideGetGetAssetUrlArguments
*/
public function testGetAssetUrl($path, $packageName, $absolute, $relativeUrl, $expectedUrl, $scheme, $host, $httpPort, $httpsPort)
{
$helper = $this->createHelperMock($path, $packageName, $relativeUrl);
$container = $this->createContainerMock($helper);

$context = $this->createRequestContextMock($scheme, $host, $httpPort, $httpsPort);

$extension = new AssetsExtension($container, $context);
$this->assertEquals($expectedUrl, $extension->getAssetUrl($path, $packageName, $absolute));
}

public function testGetAssetWithtoutHost()
{
$path = '/path/to/asset';
$packageName = null;
$relativeUrl = '/bundle-name/path/to/asset';

$helper = $this->createHelperMock($path, $packageName, $relativeUrl);
$container = $this->createContainerMock($helper);

$context = $this->createRequestContextMock('http', '', 80, 443);

$extension = new AssetsExtension($container, $context);
$this->assertEquals($relativeUrl, $extension->getAssetUrl($path, $packageName, true));
}

public function provideGetGetAssetUrlArguments()
{
return array(
array('/path/to/asset', 'package-name', false, '/bundle-name/path/to/asset', '/bundle-name/path/to/asset', 'http', 'symfony.com', 80, null),
array('/path/to/asset', 'package-name', false, 'http://subdomain.symfony.com/bundle-name/path/to/asset', 'http://subdomain.symfony.com/bundle-name/path/to/asset', 'http', 'symfony.com', 80, null),
array('/path/to/asset', null, false, '/bundle-name/path/to/asset', '/bundle-name/path/to/asset', 'http', 'symfony.com', 80, null),
array('/path/to/asset', 'package-name', true, '/bundle-name/path/to/asset', 'http://symfony.com/bundle-name/path/to/asset', 'http', 'symfony.com', 80, null),
array('/path/to/asset', 'package-name', true, 'http://subdomain.symfony.com/bundle-name/path/to/asset', 'http://subdomain.symfony.com/bundle-name/path/to/asset', 'http', 'symfony.com', 80, null),
array('/path/to/asset', null, true, '/bundle-name/path/to/asset', 'https://symfony.com:92/bundle-name/path/to/asset', 'https', 'symfony.com', null, 92),
array('/path/to/asset', null, true, '/bundle-name/path/to/asset', 'http://symfony.com:660/bundle-name/path/to/asset', 'http', 'symfony.com', 660, null),
);
}

private function createRequestContextMock($scheme, $host, $httpPort, $httpsPort)
{
$context = $this->getMockBuilder('Symfony\Component\Routing\RequestContext')
->disableOriginalConstructor()
->getMock();
$context->expects($this->any())
->method('getScheme')
->will($this->returnValue($scheme));
$context->expects($this->any())
->method('getHost')
->will($this->returnValue($host));
$context->expects($this->any())
->method('getHttpPort')
->will($this->returnValue($httpPort));
$context->expects($this->any())
->method('getHttpsPort')
->will($this->returnValue($httpsPort));

return $context;
}

private function createContainerMock($helper)
{
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$container->expects($this->any())
->method('get')
->with('templating.helper.assets')
->will($this->returnValue($helper));

return $container;
}

private function createHelperMock($path, $packageName, $returnValue)
{
$helper = $this->getMockBuilder('Symfony\Component\Templating\Helper\CoreAssetsHelper')
->disableOriginalConstructor()
->getMock();
$helper->expects($this->any())
->method('getUrl')
->with($path, $packageName)
->will($this->returnValue($returnValue));

return $helper;
}
}
4 changes: 3 additions & 1 deletion src/Symfony/Bundle/TwigBundle/composer.json
Expand Up @@ -23,7 +23,9 @@
"require-dev": {
"symfony/stopwatch": "~2.2",
"symfony/dependency-injection": "~2.0",
"symfony/config": "~2.2"
"symfony/config": "~2.2",
"symfony/routing": "~2.1",
"symfony/templating": "~2.1"
},
"autoload": {
"psr-0": { "Symfony\\Bundle\\TwigBundle\\": "" }
Expand Down

0 comments on commit 76b8851

Please sign in to comment.