发布于 2015-08-27 16:46:36 | 133 次阅读 | 评论: 0 | 来源: 网络整理
The Asset component manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files.
In the past, it was common for web applications to hardcode URLs of web assets. For example:
<link rel="stylesheet" type="text/css" href="/css/main.css">
<!-- ... -->
<a href="/"><img src="/images/logo.png"></a>
This practice is no longer recommended unless the web application is extremely simple. Hardcoding URLs can be a disadvantage because:
main.css?v=5
) to the asset URLs
is essential for some applications because it allows you to control how
the assets are cached. The Asset component allows you to define different
versioning strategies for each package;http://
) and secure (https://
).You can install the component in two different ways:
symfony/asset
on Packagist);The Asset component manages assets through packages. A package groups all the assets which share the same properties: versioning strategy, base path, CDN hosts, etc. In the following basic example, a package is created to manage assets without any versioning:
use SymfonyComponentAssetPackage;
use SymfonyComponentAssetVersionStrategyEmptyVersionStrategy;
$package = new Package(new EmptyVersionStrategy());
echo $package->getUrl('/image.png');
// result: /image.png
Packages implement PackageInterface
,
which defines the following two methods:
getVersion()
getUrl()
With a package, you can:
/css
)
for the assets;One of the main features of the Asset component is the ability to manage the versioning of the application’s assets. Asset versions are commonly used to control how these assets are cached.
Instead of relying on a simple version mechanism, the Asset component allows
you to define advanced versioning strategies via PHP classes. The two built-in
strategies are the EmptyVersionStrategy
,
which doesn’t add any version to the asset and StaticVersionStrategy
,
which allows you to set the version with a format string.
In this example, the StaticVersionStrategy
is used to append the v1
suffix to any asset path:
use SymfonyComponentAssetPackage;
use SymfonyComponentAssetVersionStrategyStaticVersionStrategy;
$package = new Package(new StaticVersionStrategy('v1'));
echo $package->getUrl('/image.png');
// result: /image.png?v1
In case you want to modify the version format, pass a sprintf-compatible format
string as the second argument of the StaticVersionStrategy
constructor:
// put the 'version' word before the version value
$package = new Package(new StaticVersionStrategy('v1', '%s?version=%s'));
echo $package->getUrl('/image.png');
// result: /image.png?version=v1
// put the asset version before its path
$package = new Package(new StaticVersionStrategy('v1', '%2$s/%1$s'));
echo $package->getUrl('/image.png');
// result: /v1/image.png
Use the VersionStrategyInterface
to define your own versioning strategy. For example, your application may need
to append the current date to all its web assets in order to bust the cache
every day:
use SymfonyComponentAssetVersionStrategyVersionStrategyInterface;
class DateVersionStrategy implements VersionStrategyInterface
{
private $version;
public function __construct()
{
$this->version = date('Ymd');
}
public function getVersion($path)
{
return $this->version;
}
public function applyVersion($path)
{
return sprintf('%s?v=%s', $path, $this->getVersion($path));
}
}
Often, many assets live under a common path (e.g. /static/images
). If
that’s your case, replace the default Package
class with PathPackage
to avoid repeating
that path over and over again:
use SymfonyComponentAssetPathPackage;
// ...
$package = new PathPackage('/static/images', new StaticVersionStrategy('v1'));
echo $package->getUrl('/logo.png');
// result: /static/images/logo.png?v1
If you are also using the HttpFoundation
component in your project (for instance, in a Symfony application), the PathPackage
class can take into account the context of the current request:
use SymfonyComponentAssetPathPackage;
use SymfonyComponentAssetContextRequestStackContext;
// ...
$package = new PathPackage(
'/static/images',
new StaticVersionStrategy('v1'),
new RequestStackContext($requestStack)
);
echo $package->getUrl('/logo.png');
// result: /somewhere/static/images/logo.png?v1
Now that the request context is set, the PathPackage
will prepend the
current request base URL. So, for example, if your entire site is hosted under
the /somewhere
directory of your web server root directory and the configured
base path is /static/images
, all paths will be prefixed with
/somewhere/static/images
.
Applications that host their assets on different domains and CDNs (Content
Delivery Networks) should use the UrlPackage
class to generate absolute URLs for their assets:
use SymfonyComponentAssetUrlPackage;
// ...
$package = new UrlPackage(
'http://static.example.com/images/',
new StaticVersionStrategy('v1')
);
echo $package->getUrl('/logo.png');
// result: http://static.example.com/images/logo.png?v1
You can also pass a schema-agnostic URL:
use SymfonyComponentAssetUrlPackage;
// ...
$package = new UrlPackage(
'//static.example.com/images/',
new StaticVersionStrategy('v1')
);
echo $package->getUrl('/logo.png');
// result: //static.example.com/images/logo.png?v1
This is useful because assets will automatically be requested via HTTPS if a visitor is viewing your site in https. Just make sure that your CDN host supports https.
In case you serve assets from more than one domain to improve application
performance, pass an array of URLs as the first argument to the UrlPackage
constructor:
use SymfonyComponentAssetUrlPackage;
// ...
$urls = array(
'//static1.example.com/images/',
'//static2.example.com/images/',
);
$package = new UrlPackage($urls, new StaticVersionStrategy('v1'));
echo $package->getUrl('/logo.png');
// result: http://static1.example.com/images/logo.png?v1
echo $package->getUrl('/icon.png');
// result: http://static2.example.com/images/icon.png?v1
For each asset, one of the URLs will be randomly used. But, the selection is deterministic, meaning that each asset will be always served by the same domain. This behavior simplifies the management of HTTP cache.
Similarly to application-relative assets, absolute assets can also take into account the context of the current request. In this case, only the request scheme is considered, in order to select the appropriate base URL (HTTPs or protocol-relative URLs for HTTPs requests, any base URL for HTTP requests):
use SymfonyComponentAssetUrlPackage;
use SymfonyComponentAssetContextRequestStackContext;
// ...
$package = new UrlPackage(
array('http://example.com/', 'https://example.com/'),
new StaticVersionStrategy('v1'),
new RequestStackContext($requestStack)
);
echo $package->getUrl('/logo.png');
// assuming the RequestStackContext says that we are on a secure host
// result: https://example.com/logo.png?v1
Applications that manage lots of different assets may need to group them in
packages with the same versioning strategy and base path. The Asset component
includes a Packages
class to simplify
management of several packages.
In the following example, all packages use the same versioning strategy, but they all have different base paths:
use SymfonyComponentAssetPackage;
use SymfonyComponentAssetPathPackage;
use SymfonyComponentAssetUrlPackage;
use SymfonyComponentAssetPackages;
// ...
$versionStrategy = new StaticVersionStrategy('v1');
$defaultPackage = new Package($versionStrategy);
$namedPackages = array(
'img' => new UrlPackage('http://img.example.com/', $versionStrategy),
'doc' => new PathPackage('/somewhere/deep/for/documents', $versionStrategy),
);
$packages = new Packages($defaultPackage, $namedPackages)
The Packages
class allows to define a default package, which will be applied
to assets that don’t define the name of package to use. In addition, this
application defines a package named img
to serve images from an external
domain and a doc
package to avoid repeating long paths when linking to a
document inside a template:
echo $packages->getUrl('/main.css');
// result: /main.css?v1
echo $packages->getUrl('/logo.png', 'img');
// result: http://img.example.com/logo.png?v1
echo $packages->getUrl('/resume.pdf', 'doc');
// result: /somewhere/deep/for/documents/resume.pdf?v1