Moved content cache control to core. Made sure updating a library invalidates caches for all content who uses it. All saving of content and filtering of parameters is now handled by core.
ContentValidator now collects a flat list of content dependencies.namespaces
parent
4a32f976e5
commit
c5b32fb621
196
h5p.classes.php
196
h5p.classes.php
|
@ -121,20 +121,20 @@ interface H5PFrameworkInterface {
|
||||||
public function saveLibraryData(&$libraryData, $new = TRUE);
|
public function saveLibraryData(&$libraryData, $new = TRUE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores contentData
|
* Insert new content.
|
||||||
*
|
*
|
||||||
* @param string $contentJson
|
* @param object $content
|
||||||
* The content data that is to be stored
|
|
||||||
* @param array $mainJsonData
|
|
||||||
* The data extracted from the h5p.json file
|
|
||||||
* @param array $mainLibraryId
|
|
||||||
* Main library identifier
|
|
||||||
* @param int $contentMainId
|
* @param int $contentMainId
|
||||||
* Any contentMainId defined by the framework, for instance to support revisioning
|
|
||||||
* @param int $contentId
|
|
||||||
* Framework specific id identifying the content
|
|
||||||
*/
|
*/
|
||||||
public function saveContentData($content, $contentMainId = NULL);
|
public function insertContent($content, $contentMainId = NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update old content.
|
||||||
|
*
|
||||||
|
* @param object $content
|
||||||
|
* @param int $contentMainId
|
||||||
|
*/
|
||||||
|
public function updateContent($content, $contentMainId = NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save what libraries a library is dependending on
|
* Save what libraries a library is dependending on
|
||||||
|
@ -262,6 +262,44 @@ interface H5PFrameworkInterface {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function loadContentDependencies($id, $type = NULL);
|
public function loadContentDependencies($id, $type = NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data from cache.
|
||||||
|
*
|
||||||
|
* @param string $group
|
||||||
|
* @param string $key
|
||||||
|
*/
|
||||||
|
public function cacheGet($group, $key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store data in cache.
|
||||||
|
*
|
||||||
|
* @param string $group
|
||||||
|
* @param string $key
|
||||||
|
* @param mixed $data
|
||||||
|
*/
|
||||||
|
public function cacheSet($group, $key, $data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete data from cache.
|
||||||
|
*
|
||||||
|
* @param string $group
|
||||||
|
* @param string $key
|
||||||
|
*/
|
||||||
|
public function cacheDel($group, $key = NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will invalidate the cache for the content that uses the specified library.
|
||||||
|
* This means that the content dependencies has to be rebuilt, and the parameters refiltered.
|
||||||
|
*
|
||||||
|
* @param int $library_id
|
||||||
|
*/
|
||||||
|
public function invalidateContentCache($library_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get content without cache.
|
||||||
|
*/
|
||||||
|
public function getNotCached();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -999,6 +1037,9 @@ class H5PStorage {
|
||||||
$this->h5pF->saveLibraryDependencies($library['libraryId'], $library['editorDependencies'], 'editor');
|
$this->h5pF->saveLibraryDependencies($library['libraryId'], $library['editorDependencies'], 'editor');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure libraries dependencies, parameter filtering and export files gets regenerated for all content who uses this library.
|
||||||
|
$this->h5pF->invalidateContentCache($library['libraryId']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$skipContent) {
|
if (!$skipContent) {
|
||||||
|
@ -1017,7 +1058,7 @@ class H5PStorage {
|
||||||
}
|
}
|
||||||
$content['library'] = $librariesInUse['preloaded-' . $this->h5pC->mainJsonData['mainLibrary']]['library'];
|
$content['library'] = $librariesInUse['preloaded-' . $this->h5pC->mainJsonData['mainLibrary']]['library'];
|
||||||
$content['params'] = file_get_contents($current_path . DIRECTORY_SEPARATOR . 'content.json');
|
$content['params'] = file_get_contents($current_path . DIRECTORY_SEPARATOR . 'content.json');
|
||||||
$contentId = $this->h5pF->saveContentData($content, $contentMainId);
|
$contentId = $this->h5pC->saveContent($content, $contentMainId);
|
||||||
$this->contentId = $contentId;
|
$this->contentId = $contentId;
|
||||||
|
|
||||||
$contents_path = $this->h5pF->getH5pPath() . DIRECTORY_SEPARATOR . 'content';
|
$contents_path = $this->h5pF->getH5pPath() . DIRECTORY_SEPARATOR . 'content';
|
||||||
|
@ -1278,6 +1319,25 @@ class H5PCore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save content and clear cache.
|
||||||
|
*
|
||||||
|
* @param array $content
|
||||||
|
* @return int Content ID
|
||||||
|
*/
|
||||||
|
public function saveContent($content, $contentMainId) {
|
||||||
|
if (isset($content['id'])) {
|
||||||
|
$this->h5pF->updateContent($content, $contentMainId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$content['id'] = $this->h5pF->insertContent($content, $contentMainId);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->h5pF->cacheDel('parameters', $content['id']);
|
||||||
|
|
||||||
|
return $content['id'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load content.
|
* Load content.
|
||||||
*
|
*
|
||||||
|
@ -1298,6 +1358,7 @@ class H5PCore {
|
||||||
);
|
);
|
||||||
unset($content['libraryId'], $content['libraryName'], $content['libraryEmbedTypes'], $content['libraryFullscreen']);
|
unset($content['libraryId'], $content['libraryName'], $content['libraryEmbedTypes'], $content['libraryFullscreen']);
|
||||||
|
|
||||||
|
// TODO: Move to filterParameters?
|
||||||
if ($this->development_mode & H5PDevelopment::MODE_CONTENT) {
|
if ($this->development_mode & H5PDevelopment::MODE_CONTENT) {
|
||||||
// TODO: Remove Drupal specific stuff
|
// TODO: Remove Drupal specific stuff
|
||||||
$json_content_path = file_create_path(file_directory_path() . '/' . variable_get('h5p_default_path', 'h5p') . '/content/' . $id . '/content.json');
|
$json_content_path = file_create_path(file_directory_path() . '/' . variable_get('h5p_default_path', 'h5p') . '/content/' . $id . '/content.json');
|
||||||
|
@ -1314,6 +1375,39 @@ class H5PCore {
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Add support for development modes.
|
||||||
|
* TODO: Should we regenerate export here as well?
|
||||||
|
*
|
||||||
|
* @param Object $content
|
||||||
|
* @return Object NULL on failure.
|
||||||
|
*/
|
||||||
|
public function filterParameters($content) {
|
||||||
|
$params = $this->h5pF->cacheGet('parameters', $content['id']);
|
||||||
|
if ($params !== NULL) {
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and filter against main library semantics.
|
||||||
|
$validator = new H5PContentValidator($this->h5pF, $this);
|
||||||
|
$params = (object) array(
|
||||||
|
'library' => H5PCore::libraryToString($content['library']),
|
||||||
|
'params' => json_decode($content['params'])
|
||||||
|
);
|
||||||
|
$validator->validateLibrary($params, (object) array('options' => array($params->library)));
|
||||||
|
|
||||||
|
$params = json_encode($params->params);
|
||||||
|
|
||||||
|
// Update content dependencies.
|
||||||
|
$dependencies = $validator->getDependencies();
|
||||||
|
$this->h5pF->deleteLibraryUsage($content['id']);
|
||||||
|
$this->h5pF->saveLibraryUsage($content['id'], $dependencies);
|
||||||
|
|
||||||
|
// Cache.
|
||||||
|
$this->h5pF->cacheSet('parameters', $content['id'], $params);
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the files required for this content to work.
|
* Find the files required for this content to work.
|
||||||
*
|
*
|
||||||
|
@ -1408,7 +1502,7 @@ class H5PCore {
|
||||||
/**
|
/**
|
||||||
* Load library semantics.
|
* Load library semantics.
|
||||||
*
|
*
|
||||||
* @return string 'div' or 'iframe'.
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function loadLibrarySemantics($name, $majorVersion, $minorVersion) {
|
public function loadLibrarySemantics($name, $majorVersion, $minorVersion) {
|
||||||
$semantics = NULL;
|
$semantics = NULL;
|
||||||
|
@ -1607,7 +1701,6 @@ class H5PCore {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the correct embed type to use.
|
* Determine the correct embed type to use.
|
||||||
* TODO: Use constants.
|
|
||||||
*
|
*
|
||||||
* @return string 'div' or 'iframe'.
|
* @return string 'div' or 'iframe'.
|
||||||
*/
|
*/
|
||||||
|
@ -1635,7 +1728,7 @@ class H5PContentValidator {
|
||||||
public $h5pF;
|
public $h5pF;
|
||||||
public $h5pC;
|
public $h5pC;
|
||||||
private $typeMap;
|
private $typeMap;
|
||||||
private $semanticsCache;
|
private $libraries, $dependencies;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the H5PContentValidator
|
* Constructor for the H5PContentValidator
|
||||||
|
@ -1661,31 +1754,22 @@ class H5PContentValidator {
|
||||||
'select' => 'validateSelect',
|
'select' => 'validateSelect',
|
||||||
'library' => 'validateLibrary',
|
'library' => 'validateLibrary',
|
||||||
);
|
);
|
||||||
// Cache for semantics used within this validation to avoid unneccessary
|
|
||||||
// json_decodes if a library is used multiple times.
|
// Keep track of the libraries we load to avoid loading it multiple times.
|
||||||
$this->semanticsCache = array();
|
$this->libraries = array();
|
||||||
|
// TODO: Should this possible be done in core's loadLibrary? This might be done multiple places.
|
||||||
|
|
||||||
|
// Keep track of all dependencies for the given content.
|
||||||
|
$this->dependencies = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the given value from content with the matching semantics
|
* Get the flat dependecy tree.
|
||||||
* object from semantics
|
|
||||||
*
|
*
|
||||||
* Function will recurse via external functions for container objects like
|
* @return array
|
||||||
* 'list', 'group' and 'library'.
|
|
||||||
*
|
|
||||||
* @param object $value
|
|
||||||
* Object to be verified. May be a string or an array. (normal or keyed)
|
|
||||||
* @param object $semantics
|
|
||||||
* Semantics object from semantics.json for main library. Further
|
|
||||||
* semantics will be loaded from H5PFramework if any libraries are
|
|
||||||
* found within the value data.
|
|
||||||
*/
|
*/
|
||||||
public function validateBySemantics(&$value, $semantics) {
|
public function getDependencies() {
|
||||||
$fakebaseobject = (object) array(
|
return $this->dependencies;
|
||||||
'type' => 'group',
|
|
||||||
'fields' => $semantics,
|
|
||||||
);
|
|
||||||
$this->validateGroup($value, $fakebaseobject, FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2028,32 +2112,48 @@ class H5PContentValidator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate given library value against library semantics.
|
* Validate given library value against library semantics.
|
||||||
|
* Check if provided library is within allowed options.
|
||||||
*
|
*
|
||||||
* Will recurse into validating the library's semantics too.
|
* Will recurse into validating the library's semantics too.
|
||||||
*/
|
*/
|
||||||
public function validateLibrary(&$value, $semantics) {
|
public function validateLibrary(&$value, $semantics) {
|
||||||
// Check if provided library is within allowed options
|
if (!isset($value->library) || !in_array($value->library, $semantics->options)) {
|
||||||
if (isset($value->library) && in_array($value->library, $semantics->options)) {
|
$this->h5pF->setErrorMessage($this->h5pF->t('Library used in content is not a valid library according to semantics'));
|
||||||
if (isset($this->semanticsCache[$value->library])) {
|
$value = new stdClass();
|
||||||
$librarySemantics = $this->semanticsCache[$value->library];
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->libraries[$value->library])) {
|
||||||
|
$libspec = $this->h5pC->libraryFromString($value->library);
|
||||||
|
$library = $this->h5pC->loadLibrary($libspec['machineName'], $libspec['majorVersion'], $libspec['minorVersion']);
|
||||||
|
$library['semantics'] = json_decode($library['semantics']);
|
||||||
|
$this->libraries[$value->library] = $library;
|
||||||
|
|
||||||
|
// Find all dependencies for this library
|
||||||
|
$depkey = 'preloaded-' . $libspec['machineName'];
|
||||||
|
if (!isset($this->dependencies[$depkey])) {
|
||||||
|
$this->dependencies[$depkey] = array(
|
||||||
|
'library' => $library,
|
||||||
|
'type' => 'preloaded'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->h5pC->findLibraryDependencies($this->dependencies, $library);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$libspec = $this->h5pC->libraryFromString($value->library);
|
$library = $this->libraries[$value->library];
|
||||||
$librarySemantics = $this->h5pC->loadLibrarySemantics($libspec['machineName'], $libspec['majorVersion'], $libspec['minorVersion']);
|
|
||||||
$this->semanticsCache[$value->library] = $librarySemantics;
|
|
||||||
}
|
}
|
||||||
$this->validateBySemantics($value->params, $librarySemantics);
|
|
||||||
|
$this->validateGroup($value->params, (object) array(
|
||||||
|
'type' => 'group',
|
||||||
|
'fields' => $library['semantics'],
|
||||||
|
), FALSE);
|
||||||
$validkeys = array('library', 'params');
|
$validkeys = array('library', 'params');
|
||||||
if (isset($semantics->extraAttributes)) {
|
if (isset($semantics->extraAttributes)) {
|
||||||
$validkeys = array_merge($validkeys, $semantics->extraAttributes);
|
$validkeys = array_merge($validkeys, $semantics->extraAttributes);
|
||||||
}
|
}
|
||||||
$this->filterParams($value, $validkeys);
|
$this->filterParams($value, $validkeys);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('Library used in content is not a valid library according to semantics'));
|
|
||||||
$value = new stdClass();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check params for a whitelist of allowed properties
|
* Check params for a whitelist of allowed properties
|
||||||
|
|
Loading…
Reference in New Issue