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. * Recursive function for copying directories.
* *

View File

@ -91,4 +91,32 @@ interface FileStorage {
* @param string $filename * @param string $filename
*/ */
public function deleteExport($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 * @return boolean
*/ */
public function isContentSlugAvailable($slug); 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 // Save library folder
$this->h5pC->fs->saveLibrary($library); $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 // Remove tmp folder
H5PCore::deleteFileTree($library['uploadDirectory']); H5PCore::deleteFileTree($library['uploadDirectory']);
@ -1680,6 +1709,8 @@ class H5PCore {
$this->exportEnabled = $export; $this->exportEnabled = $export;
$this->development_mode = $development_mode; $this->development_mode = $development_mode;
$this->aggregateAssets = FALSE; // Off by default.. for now
if ($development_mode & H5PDevelopment::MODE_LIBRARY) { if ($development_mode & H5PDevelopment::MODE_LIBRARY) {
$this->h5pD = new H5PDevelopment($this->h5pF, $path . '/', $language); $this->h5pD = new H5PDevelopment($this->h5pF, $path . '/', $language);
} }
@ -1909,9 +1940,7 @@ class H5PCore {
* @return array files. * @return array files.
*/ */
public function getDependenciesFiles($dependencies, $prefix = '') { public function getDependenciesFiles($dependencies, $prefix = '') {
$aggregateAssets = TRUE; if ($this->aggregateAssets) {
if ($aggregateAssets) {
// Get aggregated files for assets // Get aggregated files for assets
$key = self::getDependenciesHash($dependencies); $key = self::getDependenciesHash($dependencies);
@ -1938,11 +1967,12 @@ class H5PCore {
$this->getDependencyAssets($dependency, 'preloadedCss', $files['styles'], $prefix); $this->getDependencyAssets($dependency, 'preloadedCss', $files['styles'], $prefix);
} }
if ($aggregateAssets) { if ($this->aggregateAssets) {
// Aggregate and store assets // Aggregate and store assets
$this->fs->cacheAssets($files, $key); $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; return $files;