Skip to content

[Asset] added the component #13234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 10, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"psr/log": "~1.0"
},
"replace": {
"symfony/asset": "self.version",
"symfony/browser-kit": "self.version",
"symfony/class-loader": "self.version",
"symfony/config": "self.version",
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bridge/Twig/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CHANGELOG

* added LogoutUrlExtension (provides `logout_url` and `logout_path`)
* added an HttpFoundation extension (provides the `absolute_url` and the `relative_path` functions)
* added AssetExtension (provides the `asset` and `asset_version` functions)

2.5.0
-----
Expand Down
144 changes: 144 additions & 0 deletions src/Symfony/Bridge/Twig/Extension/AssetExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?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\Bridge\Twig\Extension;

use Symfony\Component\Asset\Packages;
use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy;

/**
* Twig extension for the Symfony Asset component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AssetExtension extends \Twig_Extension
{
private $packages;
private $foundationExtension;

/**
* Passing an HttpFoundationExtension instance as a second argument must not be relied on
* as it's only there to maintain BC with older Symfony version. It will be removed in 3.0.
*/
public function __construct(Packages $packages, HttpFoundationExtension $foundationExtension = null)
{
$this->packages = $packages;
$this->foundationExtension = $foundationExtension;
}

/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new \Twig_SimpleFunction('asset', array($this, 'getAssetUrl')),
new \Twig_SimpleFunction('asset_version', array($this, 'getAssetVersion')),
new \Twig_SimpleFunction('assets_version', array($this, 'getAssetsVersion')),
);
}

/**
* Returns the public url/path of an asset.
*
* If the package used to generate the path is an instance of
* UrlPackage, you will always get a URL and not a path.
*
* @param string $path A public path
* @param string $packageName The name of the asset package to use
*
* @return string The public path of the asset
*/
public function getAssetUrl($path, $packageName = null, $absolute = false, $version = null)
{
// BC layer to be removed in 3.0
if (2 < $count = func_num_args()) {
trigger_error('Generating absolute URLs with the Twig asset() function was deprecated in 2.7 and will be removed in 3.0. Please use absolute_url() instead.', E_USER_DEPRECATED);
if (4 === $count) {
trigger_error('Forcing a version with the Twig asset() function was deprecated in 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);
}

$args = func_get_args();

return $this->getLegacyAssetUrl($path, $packageName, $args[2], isset($args[3]) ? $args[3] : null);
}

return $this->packages->getUrl($path, $packageName);
}

/**
* Returns the version of an asset.
*
* @param string $path A public path
* @param string $packageName The name of the asset package to use
*
* @return string The asset version
*/
public function getAssetVersion($path, $packageName = null)
{
return $this->packages->getVersion($path, $packageName);
}

public function getAssetsVersion($packageName = null)
{
trigger_error('The Twig assets_version() function was deprecated in 2.7 and will be removed in 3.0. Please use asset_version() instead.', E_USER_DEPRECATED);

return $this->packages->getVersion('/', $packageName);
}

private function getLegacyAssetUrl($path, $packageName = null, $absolute = false, $version = null)
{
if ($version) {
$package = $this->packages->getPackage($packageName);

$v = new \ReflectionProperty($package, 'versionStrategy');
$v->setAccessible(true);

$currentVersionStrategy = $v->getValue($package);

$f = new \ReflectionProperty($currentVersionStrategy, 'format');
$f->setAccessible(true);
$format = $f->getValue($currentVersionStrategy);

$v->setValue($package, new StaticVersionStrategy($version, $format));
}

try {
$url = $this->packages->getUrl($path, $packageName);
} catch (\Exception $e) {
if ($version) {
$v->setValue($package, $currentVersionStrategy);
}

throw $e;
}

if ($version) {
$v->setValue($package, $currentVersionStrategy);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if getting the url of the package throws an exception for some reason ? Resetting the internal state needs to be done in this case too, to avoid leaving it in a bad state

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


if ($absolute) {
return $this->foundationExtension->generateAbsoluteUrl($url);
}

return $url;
}

/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'asset';
}
}
40 changes: 40 additions & 0 deletions src/Symfony/Bridge/Twig/Tests/Extension/AssetExtensionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?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\Bridge\Twig\Tests\Extension;

use Symfony\Bridge\Twig\Extension\AssetExtension;
use Symfony\Component\Asset\Package;
use Symfony\Component\Asset\Packages;
use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy;

class AssetExtensionTest extends \PHPUnit_Framework_TestCase
{
public function testLegacyGetAssetUrl()
{
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);

$foundationExtension = $this->getMockBuilder('Symfony\Bridge\Twig\Extension\HttpFoundationExtension')->disableOriginalConstructor()->getMock();
$foundationExtension
->expects($this->any())
->method('generateAbsoluteUrl')
->will($this->returnCallback(function ($arg) { return 'http://localhost/'.$arg; }))
;

$package = new Package(new StaticVersionStrategy('22', '%s?version=%s'));
$packages = new Packages($package);
$extension = new AssetExtension($packages, $foundationExtension);

$this->assertEquals('me.png?version=42', $extension->getAssetUrl('me.png', null, false, '42'));
$this->assertEquals('http://localhost/me.png?version=22', $extension->getAssetUrl('me.png', null, true));
$this->assertEquals('http://localhost/me.png?version=42', $extension->getAssetUrl('me.png', null, true, '42'));
}
}
1 change: 1 addition & 0 deletions src/Symfony/Bridge/Twig/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
},
"suggest": {
"symfony/finder": "",
"symfony/asset": "For using the AssetExtension",
"symfony/form": "For using the FormExtension",
"symfony/http-kernel": "For using the HttpKernelExtension",
"symfony/routing": "For using the RoutingExtension",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

trigger_error('The '.__NAMESPACE__.'\TemplatingAssetHelperPass class is deprecated since version 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);

/**
* @deprecated since 2.7, will be removed in 3.0
*/
class TemplatingAssetHelperPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,44 @@ public function getConfigTreeBuilder()
return $v;
})
->end()
->validate()
->ifTrue(function ($v) { return isset($v['templating']); })
->then(function ($v) {
if ($v['templating']['assets_version']
|| count($v['templating']['assets_base_urls']['http'])
|| count($v['templating']['assets_base_urls']['ssl'])
|| count($v['templating']['packages'])
) {
trigger_error('The assets settings under framework.templating are deprecated since version 2.7 and will be removed in 3.0. Use the framework.assets configuration key instead', E_USER_DEPRECATED);

// convert the old configuration to the new one
if (isset($v['assets'])) {
throw new LogicException('You cannot use assets settings under "templating.templating" and "assets" configurations in the same project.');
}

$v['assets'] = array(
'version' => $v['templating']['assets_version'],
'version_format' => $v['templating']['assets_version_format'],
'base_path' => '',
'base_urls' => array_values(array_unique(array_merge($v['templating']['assets_base_urls']['http'], $v['templating']['assets_base_urls']['ssl']))),
'packages' => array(),
);

foreach ($v['templating']['packages'] as $name => $config) {
$v['assets']['packages'][$name] = array(
'version' => (string) $config['version'],
'version_format' => $config['version_format'],
'base_path' => '',
'base_urls' => array_values(array_unique(array_merge($config['base_urls']['http'], $config['base_urls']['ssl']))),
);
}
}

unset($v['templating']['assets_version'], $v['templating']['assets_version_format'], $v['templating']['assets_base_urls'], $v['templating']['packages']);

return $v;
})
->end()
->children()
->scalarNode('secret')->end()
->scalarNode('http_method_override')
Expand Down Expand Up @@ -108,6 +146,7 @@ public function getConfigTreeBuilder()
$this->addSessionSection($rootNode);
$this->addRequestSection($rootNode);
$this->addTemplatingSection($rootNode);
$this->addAssetsSection($rootNode);
$this->addTranslatorSection($rootNode);
$this->addValidationSection($rootNode);
$this->addAnnotationsSection($rootNode);
Expand Down Expand Up @@ -347,8 +386,8 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode)
->info('templating configuration')
->canBeUnset()
->children()
->scalarNode('assets_version')->defaultValue(null)->end()
->scalarNode('assets_version_format')->defaultValue('%%s?%%s')->end()
->scalarNode('assets_version')->defaultNull()->info('Deprecated since 2.7, will be removed in 3.0. Use the new assets entry instead.')->end()
->scalarNode('assets_version_format')->defaultValue('%%s?%%s')->info('Deprecated since 2.7, will be removed in 3.0. Use the new assets entry instead.')->end()
->scalarNode('hinclude_default_template')->defaultNull()->end()
->arrayNode('form')
->addDefaultsIfNotSet()
Expand All @@ -370,6 +409,7 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode)
->fixXmlConfig('assets_base_url')
->children()
->arrayNode('assets_base_urls')
->info('Deprecated since 2.7, will be removed in 3.0. Use the new assets entry instead.')
->performNoDeepMerging()
->addDefaultsIfNotSet()
->beforeNormalization()
Expand Down Expand Up @@ -417,6 +457,7 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode)
->fixXmlConfig('package')
->children()
->arrayNode('packages')
->info('Deprecated since 2.7, will be removed in 3.0. Use the new assets entry instead.')
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('base_url')
Expand Down Expand Up @@ -452,6 +493,54 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode)
;
}

private function addAssetsSection(ArrayNodeDefinition $rootNode)
{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$rootNode
->children()
->arrayNode('assets')
->info('assets configuration')
->canBeUnset()
->fixXmlConfig('base_url')
->children()
->scalarNode('version')->defaultNull()->end()
->scalarNode('version_format')->defaultValue('%%s?%%s')->end()
->scalarNode('base_path')->defaultValue('')->end()
->arrayNode('base_urls')
->requiresAtLeastOneElement()
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return array($v); })
->end()
->prototype('scalar')->end()
->end()
->end()
->fixXmlConfig('package')
->children()
->arrayNode('packages')
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('base_url')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could all this config below share the same code as the one before? extract it as a function maybe?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could indeed use a private method returning an array node, and then using ->append() in both places

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it would bring us a lot.

->children()
->scalarNode('version')->defaultNull()->end()
->scalarNode('version_format')->defaultNull()->end()
->scalarNode('base_path')->defaultValue('')->end()
->arrayNode('base_urls')
->requiresAtLeastOneElement()
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return array($v); })
->end()
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
;
}

private function addTranslatorSection(ArrayNodeDefinition $rootNode)
{
$rootNode
Expand Down
Loading