Skip to content
This repository has been archived by the owner on Jan 1, 2023. It is now read-only.

Commit

Permalink
bug #332 Use the etag in the internal AssetCache cache key (EvanPurkh…
Browse files Browse the repository at this point in the history
…iser)

This PR was merged into the 2.6-dev branch.

Discussion
----------

Use the etag in the internal AssetCache cache key

When using the AsseticController to serve assets that have a filter applied to them implementing the [`DependencyExtractorInterface`](https://github.com/kriswallsmith/assetic/blob/master/src/Assetic/Filter/DependencyExtractorInterface.php) the etag will be correctly computed using `AssetFactory::getLastModified`, which properly takes into account filters marked with this interface.

However. The asset is then cached using the `AssetCache`, which only takes into consideration the modification time of the asset itself, and _does not_ take into account the modification time of dependencies. The effect is that when a dependency of an asset is changed (for example a SCSS file that imports another SCSS file) the etag will correctly differ and the response will be considered modified, but the `AssetCache` will incorrectly assume that the asset has not changed. The root cause is that assets derive their last modified independently from any other asset, so `AssetCache` can only do the same.

After spending some time understanding the problem we came up with what we think is an appropriate solution. This doesn't alter any APIs so I think it may be merged in as a patch.

The AssetCache will compute the cache key based upon metadata about the asset, among these things are the filters that were applied to the asset. In particular, [the serialization of the filter](https://github.com/kriswallsmith/assetic/blob/50a30b23ce4229b408d99d580d1f056908dfb64f/src/Assetic/Asset/AssetCache.php#L159-L165). If the filter also implements the `HashableInterface` then the `hash` method will be used to add to the cache key. Originally this was simply meant for [when a filter can't be serialized](kriswallsmith/assetic#228), but we can take advantage of this and use it to add additional metadata to the cache key.

In this implementation we create a custom filter implementing `HashableInterface` that is simply used to add an additional component to the cache key and not modify the content in load or dump. This then instantiated with the etag as the cache key (since this includes the proper modified time) and is passed along to the AssetCache.

Commits
-------

5067a03 Use the etag in the internal AssetCache cache key
  • Loading branch information
stof committed Aug 31, 2015
2 parents 95e96af + 5067a03 commit d6b3a6b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 1 deletion.
50 changes: 50 additions & 0 deletions Controller/AssetCacheKeyFilter.php
@@ -0,0 +1,50 @@
<?php

/*
* This file is part of the Assetic package, an OpenSky project.
*
* (c) 2010-2014 OpenSky Project Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\AsseticBundle\Controller;

use Assetic\Asset\AssetInterface;
use Assetic\Filter\FilterInterface;
use Assetic\Filter\HashableInterface;

/**
* This is a special filter that has a noop on its load and dump methods, but
* implements the HashableInterface, allowing it to be used with the AssetCache
* to include an additional cache key component.
*/
class AssetCacheKeyFilter implements HashableInterface, FilterInterface
{
private $cacheKey;

/**
* @param string $cacheKey A string to use as a cache key component
*/
public function __construct($cacheKey)
{
$this->cacheKey = $cacheKey;
}

/**
* {@inheritdoc}
*/
public function hash()
{
return $this->cacheKey;
}

public function filterLoad(AssetInterface $asset)
{
}

public function filterDump(AssetInterface $asset)
{
}
}
4 changes: 3 additions & 1 deletion Controller/AsseticController.php
Expand Up @@ -85,7 +85,9 @@ public function render(Request $request, $name, $pos = null)
return $response;
}

$response->setContent($this->cachifyAsset($asset)->dump());
$etagCacheKeyFilter = new AssetCacheKeyFilter($response->getEtag());

$response->setContent($this->cachifyAsset($asset)->dump($etagCacheKeyFilter));

return $response;
}
Expand Down

0 comments on commit d6b3a6b

Please sign in to comment.