Added support for aggregating and caching library assets

pull/17/head
Frode Petterson 2016-01-13 14:23:34 +01:00
parent 1bf393a9af
commit 00686b733d
3 changed files with 161 additions and 5 deletions

View File

@ -148,6 +148,104 @@ class DefaultStorage implements \H5P\FileStorage {
}
}
/**
* Will concatenate all JavaScrips and Stylesheets into two files in order
* to improve page performance.
*
* @param array $files
* A set of all the assets required for content to display
* @param string $key
* Hashed key for cached asset
*/
public function cacheAssets(&$files, $key) {
foreach ($files as $type => $assets) {
$content = '';
foreach ($assets as $asset) {
// Get content from asset file
$assetContent = file_get_contents($this->path . $asset->path);
$cssRelPath = preg_replace('/[^\/]+$/', '', $asset->path);
// Get file content and concatenate
if ($type === 'scripts') {
$content .= $assetContent . ";\n";
}
else {
// Rewrite relative URLs used inside stylesheets
$content .= preg_replace_callback(
'/url\([\'"]?([^"\')]+)[\'"]?\)/i',
function ($matches) use ($cssRelPath) {
return substr($matches[1], 0, 3) !== '../' ? $matches[0] : 'url("../' . $cssRelPath . $matches[1] . '")';
},
$assetContent
) . "\n";
}
}
self::dirReady("{$this->path}/cachedassets");
$ext = ($type === 'scripts' ? 'js' : 'css');
file_put_contents("{$this->path}/cachedassets/{$key}.{$ext}", $content);
}
// Use the newly created cache
$files = self::formatCachedAssets($key);
}
/**
* Will check if there are cache assets available for content.
*
* @param string $key
* Hashed key for cached asset
* @return array
*/
public function getCachedAssets($key) {
if (!file_exists("{$this->path}/cachedassets/{$key}.js") ||
!file_exists("{$this->path}/cachedassets/{$key}.css") {
return NULL;
}
return self::formatCachedAssets($key);
}
/**
* Remove the aggregated cache files.
*
* @param array $keys
* The hash keys of removed files
*/
public function deleteCachedAssets($keys) {
$context = \context_system::instance();
$fs = get_file_storage();
foreach ($keys as $hash) {
foreach (array('js', 'css') as $ext) {
$path = "{$this->path}/cachedassets/{$key}.{$ext}";
if (file_exists($path)) {
unlink($path);
}
}
}
}
/**
* Format the cached assets data the way it's supposed to be.
*
* @param string $key
* Hashed key for cached asset
* @return array
*/
private static function formatCachedAssets($key) {
return array(
'scripts' => array((object) array(
'path' => "/cachedassets/{$key}.js",
'version' => ''
)),
'styles' => array((object) array(
'path' => "/cachedassets/{$key}.css",
'version' => ''
))
);
}
/**
* Recursive function for copying directories.
*

View File

@ -91,4 +91,32 @@ interface FileStorage {
* @param string $filename
*/
public function deleteExport($filename);
/**
* Will concatenate all JavaScrips and Stylesheets into two files in order
* to improve page performance.
*
* @param array $files
* A set of all the assets required for content to display
* @param string $key
* Hashed key for cached asset
*/
public function cacheAssets(&$files, $key);
/**
* Will check if there are cache assets available for content.
*
* @param string $key
* Hashed key for cached asset
* @return array
*/
public function getCachedAssets($key);
/**
* Remove the aggregated cache files.
*
* @param array $keys
* The hash keys of removed files
*/
public function deleteCachedAssets($keys);
}

View File

@ -536,6 +536,29 @@ interface H5PFrameworkInterface {
* @return boolean
*/
public function isContentSlugAvailable($slug);
/**
* Stores hash keys for cached assets, aggregated JavaScripts and
* stylesheets, and connects it to libraries so that we know which cache file
* to delete when a library is updated.
*
* @param string $key
* Hash key for the given libraries
* @param array $libraries
* List of dependencies(libraries) used to create the key
*/
public function saveCachedAssets($key, $libraries);
/**
* Locate hash keys for given library and delete them.
* Used when cache file are deleted.
*
* @param int $library_id
* Library identifier
* @return array
* List of hash keys removed
*/
public function deleteCachedAssets($library_id);
}
/**
@ -1345,6 +1368,12 @@ class H5PStorage {
// Save library folder
$this->h5pC->fs->saveLibrary($library);
// Remove cachedassets that uses this library
if ($this->h5pC->aggregateAssets && isset($library['libraryId'])) {
$removedKeys = $this->h5pF->deleteCachedAssets($library['libraryId']);
$this->h5pC->fs->deleteCachedAssets($removedKeys);
}
// Remove tmp folder
H5PCore::deleteFileTree($library['uploadDirectory']);
@ -1680,6 +1709,8 @@ class H5PCore {
$this->exportEnabled = $export;
$this->development_mode = $development_mode;
$this->aggregateAssets = FALSE; // Off by default.. for now
if ($development_mode & H5PDevelopment::MODE_LIBRARY) {
$this->h5pD = new H5PDevelopment($this->h5pF, $path . '/', $language);
}
@ -1909,9 +1940,7 @@ class H5PCore {
* @return array files.
*/
public function getDependenciesFiles($dependencies, $prefix = '') {
$aggregateAssets = TRUE;
if ($aggregateAssets) {
if ($this->aggregateAssets) {
// Get aggregated files for assets
$key = self::getDependenciesHash($dependencies);
@ -1938,11 +1967,12 @@ class H5PCore {
$this->getDependencyAssets($dependency, 'preloadedCss', $files['styles'], $prefix);
}
if ($aggregateAssets) {
if ($this->aggregateAssets) {
// Aggregate and store assets
$this->fs->cacheAssets($files, $key);
// TODO: Update cache table
// Keep track of which libraries have been cached in case they are updated
$this->h5pF->saveCachedAssets($key, $dependencies);
}
return $files;