Skip to content
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

adds CacheBustingWorker #297

Merged
merged 6 commits into from Sep 14, 2012
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG-1.1.md
Expand Up @@ -5,6 +5,7 @@
* Added the UglifyCssFilter
* Fixed the handling of directories in the GlobAsset. #256
* Added Handlebars support
* Added the CacheBustingWorker

1.1.0-alpha1 (August 28, 2012)
------------------------------
Expand Down
30 changes: 30 additions & 0 deletions README.md
Expand Up @@ -199,6 +199,36 @@ $js->dump();
$js->dump();
```

Cache Busting
-------------

You can use the CacheBustingWorker to provide unique names.

To strategies are provided: 'content' (content based), 'modification' (modification time based)
Copy link
Collaborator

Choose a reason for hiding this comment

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

The doc is wrong here as they are now 1 and 2 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


``` php
<?php

use Assetic\Factory\AssetFactory;
use Assetic\Factory\Worker\CacheBustingWorker;

$factory = new AssetFactory('/path/to/asset/directory/');
$factory->setAssetManager($am);
$factory->setFilterManager($fm);
$factory->setDebug(true);
$factory->addWorker(new CacheBustingWorker(CacheBustingWorker::STRATEGY_CONTENT));

$css = $factory->createAsset(array(
'@reset', // load the asset manager's "reset" asset
'css/src/*.scss', // load every scss files from "/path/to/asset/directory/css/src/"
), array(
'scss', // filter through the filter manager's "scss" filter
'?yui_css', // don't use this filter in debug mode
));

echo $css->dump();
```

Static Assets
-------------

Expand Down
78 changes: 78 additions & 0 deletions src/Assetic/Factory/Worker/CacheBustingWorker.php
@@ -0,0 +1,78 @@
<?php

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

namespace Assetic\Factory\Worker;

use Assetic\Asset\AssetInterface;

/**
* Adds cache busting code
*
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
*/
class CacheBustingWorker implements WorkerInterface
{
const STRATEGY_CONTENT = 1;
const STRATEGY_MODIFICATION = 2;

private $strategy;

public function __construct($strategy = self::STRATEGY_CONTENT)
{
$this->strategy = $strategy;
}

public function process(AssetInterface $asset)
{
$hash = hash_init('sha1');

switch($this->strategy) {
case self::STRATEGY_MODIFICATION:
hash_update($hash, $asset->getLastModified());
break;
case self::STRATEGY_CONTENT:
hash_update($hash, $asset->dump());
break;
}

foreach ($asset as $i => $leaf) {
if ($sourcePath = $leaf->getSourcePath()) {
hash_update($hash, $sourcePath);
} else {
hash_update($hash, $i);
}
}

$hash = substr(hash_final($hash), 0, 7);
$url = $asset->getTargetPath();

$oldExt = pathinfo($url, PATHINFO_EXTENSION);
$newExt = '-'.$hash.'.'.$oldExt;

if (!$oldExt || 0 < preg_match('/'.preg_quote($newExt, '/').'$/', $url)) {
return;
}

$asset->setTargetPath(substr($url, 0, (strlen($oldExt) + 1) * -1).$newExt);
}

public function getStrategy()
{
return $this->strategy;
}

public function setStrategy($strategy)
{
$this->strategy = $strategy;

return $this;
}
}
4 changes: 2 additions & 2 deletions tests/Assetic/Test/Factory/AssetFactoryTest.php
Expand Up @@ -103,15 +103,15 @@ public function testCreateGlobAssetAndLoadFiles()
$assets = $this->factory->createAsset(array('*/Fixtures/*/*'));
$assets->load();

$this->assertEquals(4, count(iterator_to_array($assets)), '->createAsset() adds files');
$this->assertEquals(5, count(iterator_to_array($assets)), '->createAsset() adds files');
}

public function testCreateGlobAssetAndExcludeDirectories()
{
$assets = $this->factory->createAsset(array('*/Fixtures/*', '*/Fixtures/*/*'));
$assets->load();

$this->assertEquals(4, count(iterator_to_array($assets)), '->createAsset() excludes directories and add files');
$this->assertEquals(5, count(iterator_to_array($assets)), '->createAsset() excludes directories and add files');
}

public function testCreateAssetCollection()
Expand Down
Expand Up @@ -120,7 +120,7 @@ public function testFollowSymlinks()
++$count;
}

$this->assertEquals(6, $count);
$this->assertEquals(7, $count);
}

public function tearDown()
Expand Down
1 change: 1 addition & 0 deletions tests/Assetic/Test/Factory/Resource/Fixtures/css/style.css
@@ -0,0 +1 @@
body{color:#222;background:#fff;}
76 changes: 76 additions & 0 deletions tests/Assetic/Test/Factory/Worker/CacheBustingWorkerTest.php
@@ -0,0 +1,76 @@
<?php

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

namespace Assetic\Test\Factory\Worker;

use Assetic\Factory\AssetFactory;
use Assetic\Factory\Worker\CacheBustingWorker;

class CacheBustingWorkerTest extends \PHPUnit_Framework_TestCase
{
private $worker;
private $factory;

protected function setUp()
{
$am = $this->getMock('Assetic\\AssetManager');
$fm = $this->getMock('Assetic\\FilterManager');

$this->worker = new CacheBustingWorker();

$this->factory = new AssetFactory(__DIR__ . DIRECTORY_SEPARATOR . '..');
$this->factory->setAssetManager($am);
$this->factory->setFilterManager($fm);
$this->factory->addWorker($this->worker);
}


public function testGenerateUniqueAssetNameByContent()
{
$this->worker->setStrategy(CacheBustingWorker::STRATEGY_CONTENT);

$filename = 'Resource/Fixtures/css/style.css';
$filepath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . $filename;
Copy link
Collaborator

Choose a reason for hiding this comment

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

You don't need to use DIRECTORY_SEPARATOR when building a path for file_get_contents. As of PHP 5.3, / is accepted on Windows too, and it makes things more readable. Using DIRECTORY_SEPARATOR is needed only when you need to compare paths as strings.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


$originalContent = file_get_contents($filepath);

file_put_contents($filepath, 'body{color:#444;background:#eee;}');
$asset = $this->factory->createAsset(array($filename));
$targetPath1 = $asset->getTargetPath();

file_put_contents($filepath, $originalContent);
$asset = $this->factory->createAsset(array($filename));
$targetPath2 = $asset->getTargetPath();

$this->assertNotEquals($targetPath2, $targetPath1);
}

public function testGenerateUniqueAssetNameByModificationTime()
{
$this->worker->setStrategy(CacheBustingWorker::STRATEGY_MODIFICATION);

$filename = 'Resource/Fixtures/css/style.css';
$filepath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . $filename;

$asset = $this->factory->createAsset(array($filename));
$this->factory->addWorker(new CacheBustingWorker('modification'));
$targetPath1 = $asset->getTargetPath();

sleep(1);
touch($filepath);
clearstatcache();

$asset = $this->factory->createAsset(array($filename));
$targetPath2 = $asset->getTargetPath();

$this->assertNotEquals($targetPath2, $targetPath1);
}
}