8000 [Asset] added the component by fabpot · Pull Request #13234 · symfony/symfony · GitHub
[go: up one dir, main page]

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 1 commit
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
Next Next commit
[Asset] added the component
  • Loading branch information
fabpot committed Feb 10, 2015
commit d33c41d43663f1f638ec083fa2b8c3bddec5ad1a
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_path` function)

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

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

public function __construct(Packages $packages)
{
$this->packages = $packages;
}

/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new \Twig_SimpleFunction('asset_path', array($this, 'getAssetPath')),
Copy link
Contributor

Choose a reason for hiding this comment

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

would it be possible to keep the old function name? and IMHO the possibility to pass a specific version for the asset was useful, could we restore that functionality back?

Copy link
Member Author

Choose a reason for hiding this comment

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

Keeping the old name would not allow us to keep both layers as explained in the description of this PR. Passing a specific version is a non-sense and using a custom version strategy is the best way to achieve that feature (also explained in the description of the PR).

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

The thing with the new name it is that it's a little bit misleading because it can indeed generate absolute url's (not only paths) if you are using an UrlPackage, it just can't generate an absolute url if you are using a PathPackage.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree with you. Any ideas for another name?

Copy link
Contributor

Choose a reason for hiding this comment

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

I still think that we sould keep the old name, it's the best one. And it's a pitty that we have to struggle to find a new name just for BC reasons. I would prefer to have a ""harder"" approach like the one had before (only one layer at a time possible) and keep the same name.

Besides, keeping the old name makes it easier to upgrade, as the removed "absolute" and "version" params were mostly unused, and the asset name and package name remain in the new function, so there is almost full BC in the twig files if you choose to use the new layer, no need to rename anything.

Copy link
Member

Choose a reason for hiding this comment

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

@acasademont only one layer at a time means forcing all the open-source ecosystem to update at the same time to stay compatible (and then projects depending on them need to migrate when updating the dependencies).

The other solution is to find a way to implement a BC layer for the old API in the new system, to be able to reuse the names in a BC way.

Copy link
Contributor

Choose a reason for hiding this comment

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

Even with what you propose I don't see a clear update path. OS bundles will keep using the asset function because they won't know if in your project you have enabled the new component and can start using asset_path. So when Symfony 3 comes they'll have to update to the new function name to stay compatible.

Besides, I'm pretty sure that in 99.9% of the asset function calls out there in external bundles there are no packages and no use of the absolute or version params (or like the WebProfilerBundle, they removed all asset calls and changed them for inline base64-encoded images). So keeping the same name is the best option for them, they probably won't even have to bother about the change, the simple asset('/path/to/my/bundle/foo.jpg') call has the exact same syntax and result in the new layer if we keep the name.

Made a quick search here https://github.com/search?p=6&q=asset+NOT+url+extension%3Atwig&ref=searchresults&type=Code&utf8=%E2%9C%93 (unfortunately you can't search the parentheses symbol, which would narrow down the search a lot)

Copy link
Member

Choose a reason for hiding this comment

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

@fabpot any idea whether it would be possible to build the previous API as a BC layer on top of the new one, to avoid having to change all templates everywhere when migrating to the new API (making the upgrade path much better) ?

new \Twig_SimpleFunction('asset_version', array($this, 'getAssetVersion')),
);
}

/**
* Returns the public 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 getAssetPath($path, $packageName = 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);
}

/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'asset';
}
}
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,9 @@
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

/**
* @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 @@ -108,6 +108,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 +348,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 +371,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 +419,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 +455,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
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ public function load(array $configs, ContainerBuilder $container)

$this->registerSecurityCsrfConfiguration($config['csrf_protection'], $container, $loader);

if (isset($config['assets'])) {
$this->registerAssetsConfiguration($config['assets'], $container, $loader);
}

if (isset($config['templating'])) {
$this->registerTemplatingConfiguration($config['templating'], $config['ide'], $container, $loader);
}
Expand Down Expand Up @@ -632,6 +636,86 @@ private function createTemplatingPackageDefinition(ContainerBuilder $container,
return $package;
}

/**
* Loads the assets configuration.
*
* @param array $config A assets configuration array
* @param ContainerBuilder $container A ContainerBuilder instance
* @param XmlFileLoader $loader An XmlFileLoader instance
*/
private function registerAssetsConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
$loader->load('assets.xml');

$defaultVersion = $this->createVersion($container, $config['version'], $config['version_format']);

$defaultPackage = $this->createPackageDefinition($config['base_path'], $config['base_urls'], $defaultVersion);
$container->setDefinition('assets._default_package', $defaultPackage);

$namedPackages = array();
foreach ($config['packages'] as $name => $package) {
if (null === $package['version']) {
$version = $defaultVersion;
} else {
$format = $package['version_format'] ?: $config['version_format'];

$version = $this->createVersion($container, $package['version'], $format, $name);
}

$container->setDefinition('assets._package_'.$name, $this->createPackageDefinition($package['base_path'], $package['base_urls'], $version));
$namedPackages[$name] = new Reference('assets._package_'.$name);
}

$container->getDefinition('assets.packages')
->replaceArgument(0, new Reference('assets._default_package'))
->replaceArgument(1, $namedPackages)
;
}

/**
* Returns a definition for an asset package.
*/
private function createPackageDefinition($basePath, array $baseUrls, Reference $version)
{
if ($basePath && $baseUrls) {
throw new \LogicException('An asset package cannot have base URLs and base paths.');
}

if (!$baseUrls) {
$package = new DefinitionDecorator('assets.path_package');

return $package
->setPublic(false)
->replaceArgument(0, $basePath)
->replaceArgument(1, $version)
;
}

$package = new DefinitionDecorator('assets.url_package');

return $package
->setPublic(false)
->replaceArgument(0, $baseUrls)
->replaceArgument(1, $version)
;
}

private function createVersion(ContainerBuilder $container, $version, $format, $name = null)
{
if (!$version) {
return new Reference('assets.empty_version_strategy');
}

$def = new DefinitionDecorator('assets.static_version_strategy');
$def
->replaceArgument(0, $version)
->replaceArgument(1, $format)
;
$container->setDefinition('assets._version_'.$name, $def);

return new Reference('assets._version_'.$name);
}

/**
* Loads the translator configuration.
*
Expand Down
42 changes: 42 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>

<service id="assets.packages" class="Symfony\Component\Asset\Packages">
<argument /> <!-- default package -->
<argument type="collection" /> <!-- named packages -->
</service>

<service id="assets.context" class="Symfony\Component\Asset\Context\RequestStackContext">
<argument type="service" id="request_stack" />
</service>

<service id="assets.path_package" class="Symfony\Component\Asset\PathPackage" abstract="true">
<argument /> <!-- base path -->
<argument type="service" /> <!-- version strategy -->
<call method="setContext">
<argument type="service" id="assets.context" />
</call>
</service>

<service id="assets.url_package" class="Symfony\Component\Asset\UrlPackage" abstract="true">
<argument /> <!-- base URLs -->
<argument type="service" /> <!-- version strategy -->
<call method="setContext">
<argument type="service" id="assets.context" />
</call>
</service>

<service id="assets.static_version_strategy" class="Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy" abstract="true">
<argument /> <!-- version -->
<argument /> <!-- format -->
</service>

<service id="assets.empty_version_strategy" class="Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy" public="false" />

</services>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Bundle\FrameworkBundle\Templating\Asset;

trigger_error('The Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageFactory is deprecated since version 2.7 and will be removed in 3.0. Use the Asset component instead.', E_USER_DEPRECATED);

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Templating\Asset\PackageInterface;
Expand All @@ -19,6 +21,8 @@
* Creates packages based on whether the current request is secure.
*
* @author Kris Wallsmith <kris@symfony.com>
*
* @deprecated since 2.7, will be removed in 3.0. Use the Asset component instead.
*/
class PackageFactory
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Templating\Asset\PathPackage as BasePathPackage;

trigger_error('The Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage is deprecated since version 2.7 and will be removed in 3.0. Use the Asset component instead.', E_USER_DEPRECATED);

/**
* The path packages adds a version and a base path to asset URLs.
*
* @author Kris Wallsmith <kris@symfony.com>
*
* @deprecated since 2.7, will be removed in 3.0. Use the Asset component instead.
*/
class PathPackage extends BasePathPackage
{
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bundle/FrameworkBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"doctrine/annotations": "~1.0"
},
"require-dev": {
"symfony/asset": "~2.7|~3.0.0",
"symfony/browser-kit": "~2.4|~3.0.0",
"symfony/console": "~2.6|~3.0.0",
"symfony/css-selector": "~2.0,>=2.0.5|~3.0.0",
Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Bundle/TwigBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
CHANGELOG
=========

2.7.0
-----

* added support for the new Asset component (from Twig bridge)
* deprecated the assets extension (use the one from the Twig bridge instead)

2.6.0
-----

Expand Down
Loading
0