Created
March 3, 2013 00:42
-
-
Save jasonhancock/5073938 to your computer and use it in GitHub Desktop.
An asset manager for the Yii PHP framework to publish static assets with a hash that's load-balancer and development environment friendly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* CAssetManager class file. | |
* | |
* @author Jason Hancock <[email protected]> | |
* @copyright Copyright © 2013 Jason Hancock | |
* @license http://www.yiiframework.com/license/ | |
*/ | |
/** | |
* The goal of the VersionAssetManager is to publish all assets under a version | |
* numbered url. This assumes you're incrementing the version number every time | |
* you release. For development, we want to emulate the CAssetManager and force | |
* the asset publishes and use CRC hashes (like normal), however instead of using | |
* the directory's mtime, we're using the current unix time. This means that every | |
* pageview when in development mode is copying over all of the assets, so it's | |
* expensive, but nothing is more frustrating that trying to solve cache busting | |
* issues when you're writing code. In production mode, we use the file's path + | |
* the current version number for the hash, so files should only get published | |
* once. | |
*/ | |
class VersionAssetManager extends CAssetManager { | |
private $_basePath; | |
private $_baseUrl; | |
private $_published=array(); | |
protected $_time; | |
public function publish($path,$hashByName=false,$level=-1,$forceCopy=false) { | |
if(isset($this->_published[$path])) | |
return $this->_published[$path]; | |
else if(($src=realpath($path))!==false) { | |
if(is_file($src)) { | |
$dir=$this->hash($hashByName | |
? basename($src) | |
: Yii::app()->params['version'] == 'Development' | |
? dirname($src).$this->getTime() | |
: dirname($src).Yii::app()->params['version'] | |
); | |
$fileName=basename($src); | |
$dstDir=$this->getBasePath().DIRECTORY_SEPARATOR.$dir; | |
$dstFile=$dstDir.DIRECTORY_SEPARATOR.$fileName; | |
if($this->linkAssets) { | |
if(!is_file($dstFile)) { | |
if(!is_dir($dstDir)) { | |
mkdir($dstDir); | |
@chmod($dstDir, $this->newDirMode); | |
} | |
symlink($src,$dstFile); | |
} | |
} | |
else if(@filemtime($dstFile)<@filemtime($src)) { | |
if(!is_dir($dstDir)) { | |
mkdir($dstDir); | |
@chmod($dstDir, $this->newDirMode); | |
} | |
copy($src,$dstFile); | |
@chmod($dstFile, $this->newFileMode); | |
} | |
return $this->_published[$path]=$this->getBaseUrl()."/$dir/$fileName"; | |
} else if(is_dir($src)) { | |
$dir=$this->hash($hashByName | |
? basename($src) | |
: Yii::app()->params['version'] == 'Development' | |
? $src.$this->getTime() | |
: $src.Yii::app()->params['version'] | |
); | |
$dstDir=$this->getBasePath().DIRECTORY_SEPARATOR.$dir; | |
if($this->linkAssets) { | |
if(!is_dir($dstDir)) | |
symlink($src,$dstDir); | |
} | |
else if(!is_dir($dstDir) || $forceCopy) { | |
CFileHelper::copyDirectory($src,$dstDir,array( | |
'exclude'=>$this->excludeFiles, | |
'level'=>$level, | |
'newDirMode'=>$this->newDirMode, | |
'newFileMode'=>$this->newFileMode, | |
)); | |
} | |
return $this->_published[$path]=$this->getBaseUrl().'/'.$dir; | |
} | |
} | |
throw new CException(Yii::t('yii','The asset "{asset}" to be published does not exist.', | |
array('{asset}'=>$path))); | |
} | |
/** | |
* Returns the published path of a file path. | |
* This method does not perform any publishing. It merely tells you | |
* if the file or directory is published, where it will go. | |
* @param string $path directory or file path being published | |
* @param boolean $hashByName whether the published directory should be named as the hashed basename. | |
* If false, the name will be the hash taken from dirname of the path being published and path mtime. | |
* Defaults to false. Set true if the path being published is shared among | |
* different extensions. | |
* @return string the published file path. False if the file or directory does not exist | |
*/ | |
public function getPublishedPath($path,$hashByName=false) { | |
if(($path=realpath($path))!==false) { | |
$base=$this->getBasePath().DIRECTORY_SEPARATOR; | |
if(is_file($path)) { | |
return $base . $this->hash($hashByName | |
? basename($path) | |
: Yii::app()->params['version'] == 'Development' | |
? dirname($path).$this->getTime() | |
: dirname($path).Yii::app()->params['version'] | |
) . DIRECTORY_SEPARATOR . basename($path); | |
} else { | |
return $base . $this->hash($hashByName | |
? basename($path) | |
: Yii::app()->params['version'] == 'Development' | |
? $path.$this->getTime() | |
: $path.Yii::app()->params['version'] | |
); | |
} | |
} | |
else | |
return false; | |
} | |
/** | |
* Returns the URL of a published file path. | |
* This method does not perform any publishing. It merely tells you | |
* if the file path is published, what the URL will be to access it. | |
* @param string $path directory or file path being published | |
* @param boolean $hashByName whether the published directory should be named as the hashed basename. | |
* If false, the name will be the hash taken from dirname of the path being published and path mtime. | |
* Defaults to false. Set true if the path being published is shared among | |
* different extensions. | |
* @return string the published URL for the file or directory. False if the file or directory does not exist. | |
*/ | |
public function getPublishedUrl($path,$hashByName=false) { | |
if(isset($this->_published[$path])) | |
return $this->_published[$path]; | |
if(($path=realpath($path))!==false) { | |
if(is_file($path)) { | |
return $this->getBaseUrl().'/'.$this->hash($hashByName | |
? basename($path) | |
: Yii::app()->params['version'] == 'Development' | |
? dirname($path).$this->getTime() | |
: dirname($path).Yii::app()->params['version'] | |
).'/'.basename($path); | |
} else { | |
return $this->getBaseUrl().'/'.$this->hash($hashByName | |
? basename($path) | |
: Yii::app()->params['version'] == 'Development' | |
? $path.$this->getTime() | |
: $path.Yii::app()->params['version'] | |
); | |
} | |
} | |
else | |
return false; | |
} | |
/** | |
* Protect against publishing multiple assets for a page view spanning multiple | |
* seconds. | |
*/ | |
protected function getTime() { | |
if(!isset($this->_time)) | |
$this->_time = time(); | |
return $this->_time; | |
} | |
} |
We are using this asset manager in our Yii 1.1 project and are currently upgrading to PHP 8.0.0, the asset manager breaks in PHP 8.0.0 therefor I've patched the asset manager to work with PHP 8.0.0. The tarnary operations needed to be patched in order to be compatible with PHP 8 https://gist.github.com/benderni/b8f7e324d7767a6f1df1a79079e0cc84
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This has been updated for Yii2. https://github.com/jasonhancock/yii2-version-assetmgr