2016-02-12 10:18:13 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* External library handling for e107 plugins/themes.
|
|
|
|
*
|
|
|
|
* TODO:
|
|
|
|
* - Provide the ability to use third-party callbacks (are defined in e_library.php files) for groups:
|
2016-02-14 13:01:36 +01:00
|
|
|
* 'info', 'pre_detect', 'post_detect', 'pre_dependencies_load', 'pre_load', 'post_load'
|
2016-02-12 10:18:13 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
// [e_LANGUAGEDIR]/[e_LANGUAGE]/lan_library_manager.php
|
|
|
|
e107::lan('core', 'library_manager');
|
|
|
|
|
2016-02-14 12:38:46 +01:00
|
|
|
|
2016-02-12 10:18:13 +01:00
|
|
|
/**
|
|
|
|
* Class e_library_manager.
|
|
|
|
*/
|
|
|
|
class e_library_manager
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
* Use {@link getInstance()}, direct instantiating is not possible for signleton objects.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
public function __construct()
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
protected function _init()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cloning is not allowed.
|
|
|
|
*/
|
|
|
|
private function __clone()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tries to detect a library and its installed version.
|
|
|
|
*
|
|
|
|
* @param $name
|
|
|
|
* The machine name of a library to return registered information for.
|
|
|
|
*
|
|
|
|
* @return array|false
|
|
|
|
* An associative array containing registered information for the library specified by $name, or FALSE if the
|
2016-02-14 11:27:34 +01:00
|
|
|
* library $name is not registered. In addition to the keys returned by info(), the following keys are
|
2016-02-12 10:18:13 +01:00
|
|
|
* contained:
|
|
|
|
* - installed: A boolean indicating whether the library is installed. Note that not only the top-level library,
|
|
|
|
* but also each variant contains this key.
|
|
|
|
* - version: If the version could be detected, the full version string.
|
|
|
|
* - error: If an error occurred during library detection, one of the following error statuses:
|
|
|
|
* "not found", "not detected", "not supported".
|
2016-02-14 13:01:36 +01:00
|
|
|
* - error_message: If an error occurred during library detection, a detailed error_message.
|
2016-02-12 10:18:13 +01:00
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
public function detect($name)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
// Re-use the statically cached value of info() to save memory.
|
|
|
|
$library = &$this->info($name);
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
// Exit early if the library was not found.
|
|
|
|
if($library === false)
|
|
|
|
{
|
|
|
|
return $library;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If 'installed' is set, library detection ran already.
|
|
|
|
if(isset($library['installed']))
|
|
|
|
{
|
|
|
|
return $library;
|
|
|
|
}
|
|
|
|
|
|
|
|
$library['installed'] = false;
|
|
|
|
|
|
|
|
// Check whether the library exists.
|
2016-02-14 13:01:36 +01:00
|
|
|
if(!isset($library['library_path']))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
$library['library_path'] = $this->getPath($library['machine_name']);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
|
2016-02-14 13:01:36 +01:00
|
|
|
$libraryPath = e107::getParser()->replaceConstants($library['library_path']);
|
|
|
|
if($library['library_path'] === false || !file_exists($libraryPath))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
$library['error'] = LAN_LIBRARY_MANAGER_09;
|
|
|
|
|
|
|
|
$replace_with = array($library['name']);
|
2016-02-14 13:01:36 +01:00
|
|
|
$library['error_message'] = e107::getParser()->lanVars(LAN_LIBRARY_MANAGER_03, $replace_with);
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
return $library;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO:
|
2016-02-14 13:01:36 +01:00
|
|
|
// Invoke callbacks in the 'pre_detect' group.
|
|
|
|
$this->invoke('pre_detect', $library);
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
// Detect library version, if not hardcoded.
|
|
|
|
if(!isset($library['version']))
|
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
// If version_callback is a method in $this class.
|
|
|
|
if(method_exists($this, $library['version_callback']))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
// We support both a single parameter, which is an associative array, and an indexed array of multiple
|
|
|
|
// parameters.
|
2016-02-14 13:01:36 +01:00
|
|
|
if(isset($library['version_arguments'][0]))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
// Add the library as the first argument.
|
2016-02-14 13:01:36 +01:00
|
|
|
$classMethod = array($this, $library['version_callback']);
|
|
|
|
$params = array_merge(array($library), $library['version_arguments']);
|
2016-02-14 13:46:10 +01:00
|
|
|
$library['version'] = call_user_func_array($classMethod, $params);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
$method = $library['version_callback'];
|
|
|
|
$library['version'] = $this->$method($library, $library['version_arguments']);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
2016-02-14 13:01:36 +01:00
|
|
|
// If version_callback is a method in e_library.php file.
|
2016-02-12 10:18:13 +01:00
|
|
|
else
|
|
|
|
{
|
2016-02-14 13:46:10 +01:00
|
|
|
$library['version'] = '';
|
2016-02-14 12:38:46 +01:00
|
|
|
$class = false;
|
|
|
|
|
2016-02-12 10:18:13 +01:00
|
|
|
if(varset($library['plugin'], false))
|
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
$class = e107::getAddon($library['plugin'], 'e_library');
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
elseif(varset($library['theme'], false))
|
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
// e107::getAddon() does not support theme folders.
|
|
|
|
e107_require_once(e_THEME . $library['theme'] . '/theme_library.php');
|
2016-02-12 10:18:13 +01:00
|
|
|
$addonClass = $library['theme'] . '_library';
|
2016-02-14 12:38:46 +01:00
|
|
|
|
|
|
|
if(isset($addonClass) && class_exists($addonClass))
|
|
|
|
{
|
|
|
|
$class = new $addonClass();
|
|
|
|
}
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// We support both a single parameter, which is an associative array, and an
|
|
|
|
// indexed array of multiple parameters.
|
2016-02-14 13:01:36 +01:00
|
|
|
if(isset($library['version_arguments'][0]))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
if($class)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
$params = array_merge(array($library), $library['version_arguments']);
|
2016-02-14 13:46:10 +01:00
|
|
|
$library['version'] = e107::callMethod($class, $library['version_callback'], $params);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
if($class)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 13:46:10 +01:00
|
|
|
$library['version'] = e107::callMethod($class, $library['version_callback'], $library, $library['version_arguments']);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(empty($library['version']))
|
|
|
|
{
|
|
|
|
$library['error'] = LAN_LIBRARY_MANAGER_10;
|
|
|
|
|
|
|
|
$replace_with = array($library['name']);
|
2016-02-14 13:01:36 +01:00
|
|
|
$library['error_message'] = e107::getParser()->lanVars(LAN_LIBRARY_MANAGER_04, $replace_with);
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
return $library;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine to which supported version the installed version maps.
|
|
|
|
if(!empty($library['versions']))
|
|
|
|
{
|
|
|
|
ksort($library['versions']);
|
|
|
|
$version = 0;
|
|
|
|
foreach($library['versions'] as $supported_version => $version_properties)
|
|
|
|
{
|
|
|
|
if(version_compare($library['version'], $supported_version, '>='))
|
|
|
|
{
|
|
|
|
$version = $supported_version;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!$version)
|
|
|
|
{
|
|
|
|
$library['error'] = LAN_LIBRARY_MANAGER_11;
|
|
|
|
|
|
|
|
$replace_with = array($library['version'], $library['name']);
|
2016-02-14 13:01:36 +01:00
|
|
|
$library['error_message'] = e107::getParser()->lanVars(LAN_LIBRARY_MANAGER_05, $replace_with);
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
return $library;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply version specific definitions and overrides.
|
|
|
|
$library = array_merge($library, $library['versions'][$version]);
|
|
|
|
unset($library['versions']);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check each variant if it is installed.
|
|
|
|
if(!empty($library['variants']))
|
|
|
|
{
|
|
|
|
foreach($library['variants'] as $variant_name => &$variant)
|
|
|
|
{
|
|
|
|
// If no variant callback has been set, assume the variant to be installed.
|
|
|
|
if(!isset($variant['variant callback']))
|
|
|
|
{
|
|
|
|
$variant['installed'] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
$variant['installed'] = false;
|
2016-02-14 12:38:46 +01:00
|
|
|
$class = false;
|
|
|
|
|
2016-02-12 10:18:13 +01:00
|
|
|
if(varset($library['plugin'], false))
|
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
$class = e107::getAddon($library['plugin'], 'e_library');
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
elseif(varset($library['theme'], false))
|
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
// e107::getAddon() does not support theme folders.
|
|
|
|
e107_require_once(e_THEME . $library['theme'] . '/theme_library.php');
|
2016-02-12 10:18:13 +01:00
|
|
|
$addonClass = $library['theme'] . '_library';
|
2016-02-14 12:38:46 +01:00
|
|
|
|
|
|
|
if(isset($addonClass) && class_exists($addonClass))
|
|
|
|
{
|
|
|
|
$class = new $addonClass();
|
|
|
|
}
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// We support both a single parameter, which is an associative array, and an indexed array of
|
|
|
|
// multiple parameters.
|
|
|
|
if(isset($variant['variant arguments'][0]))
|
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
if($class)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
$params = array_merge(array($library, $variant_name), $variant['variant arguments']);
|
|
|
|
$variant['installed'] = e107::callMethod($class, $library['variant callback'], $params);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
if($class)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
// Can't use e107::callMethod(), because it only supports 2 params.
|
2016-02-12 10:18:13 +01:00
|
|
|
if(method_exists($class, $variant['variant callback']))
|
|
|
|
{
|
|
|
|
// Call PLUGIN/THEME_library::VARIANT_CALLBACK().
|
|
|
|
$method = $variant['variant callback'];
|
|
|
|
$variant['installed'] = $class->$method($library, $variant_name, $variant['variant arguments']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-02-14 12:38:46 +01:00
|
|
|
|
2016-02-12 10:18:13 +01:00
|
|
|
if(!$variant['installed'])
|
|
|
|
{
|
|
|
|
$variant['error'] = LAN_LIBRARY_MANAGER_09;
|
|
|
|
|
|
|
|
$replace_with = array($variant_name, $library['name']);
|
2016-02-14 13:01:36 +01:00
|
|
|
$variant['error_message'] = e107::getParser()->lanVars(LAN_LIBRARY_MANAGER_06, $replace_with);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we end up here, the library should be usable.
|
|
|
|
$library['installed'] = true;
|
|
|
|
|
2016-02-14 13:01:36 +01:00
|
|
|
// Invoke callbacks in the 'post_detect' group.
|
|
|
|
$this->invoke('post_detect', $library);
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
return $library;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads a library.
|
|
|
|
*
|
|
|
|
* @param $name
|
|
|
|
* The name of the library to load.
|
|
|
|
* @param $variant
|
|
|
|
* The name of the variant to load. Note that only one variant of a library can be loaded within a single
|
|
|
|
* request. The variant that has been passed first is used; different variant names in subsequent calls are
|
|
|
|
* ignored.
|
|
|
|
*
|
|
|
|
* @return
|
2016-02-14 11:27:34 +01:00
|
|
|
* An associative array of the library information as returned from info(). The top-level properties
|
2016-02-12 10:18:13 +01:00
|
|
|
* contain the effective definition of the library (variant) that has been loaded. Additionally:
|
2016-02-14 11:27:34 +01:00
|
|
|
* - installed: Whether the library is installed, as determined by detectLibrary().
|
2016-02-12 10:18:13 +01:00
|
|
|
* - loaded: Either the amount of library files that have been loaded, or FALSE if the library could not be
|
2016-02-14 11:27:34 +01:00
|
|
|
* loaded. See MYPLUGIN_library::info() for more information.
|
2016-02-12 10:18:13 +01:00
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
public function load($name, $variant = null)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 13:16:24 +01:00
|
|
|
// Re-use the statically cached value to save memory.
|
2016-02-14 12:38:46 +01:00
|
|
|
static $loaded;
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
if(!isset($loaded[$name]))
|
|
|
|
{
|
2016-02-13 22:52:58 +01:00
|
|
|
$cache = e107::getCache();
|
|
|
|
$cacheID = 'library_manager_' . md5($name);
|
|
|
|
$cached = $cache->retrieve($cacheID, false, true, true);
|
|
|
|
|
|
|
|
if($cached)
|
|
|
|
{
|
|
|
|
$library = unserialize($cached);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!varset($library, false))
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$library = $this->detect($name);
|
2016-02-13 22:52:58 +01:00
|
|
|
$cacheData = serialize($library);
|
|
|
|
$cache->set($cacheID, $cacheData, true, false, true);
|
|
|
|
}
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
// Exit early if the library was not found.
|
|
|
|
if($library === false)
|
|
|
|
{
|
|
|
|
$loaded[$name] = $library;
|
|
|
|
return $loaded[$name];
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a variant was specified, override the top-level properties with the variant properties.
|
|
|
|
if(isset($variant))
|
|
|
|
{
|
|
|
|
// Ensure that the $variant key exists, and if it does not, set its 'installed' property to FALSE by
|
|
|
|
// default. This will prevent the loading of the library files below.
|
|
|
|
$library['variants'] += array($variant => array('installed' => false));
|
|
|
|
$library = array_merge($library, $library['variants'][$variant]);
|
|
|
|
}
|
|
|
|
// Regardless of whether a specific variant was requested or not, there can only be one variant of a
|
|
|
|
// library within a single request.
|
|
|
|
unset($library['variants']);
|
|
|
|
|
|
|
|
// TODO:
|
2016-02-14 13:01:36 +01:00
|
|
|
// Invoke callbacks in the 'pre_dependencies_load' group.
|
|
|
|
$this->invoke('pre_dependencies_load', $library);
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
// If the library (variant) is installed, load it.
|
|
|
|
$library['loaded'] = false;
|
|
|
|
if($library['installed'])
|
|
|
|
{
|
|
|
|
// Load library dependencies.
|
|
|
|
if(isset($library['dependencies']))
|
|
|
|
{
|
|
|
|
foreach($library['dependencies'] as $dependency)
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->load($dependency);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO:
|
2016-02-14 13:01:36 +01:00
|
|
|
// Invoke callbacks in the 'pre_load' group.
|
|
|
|
$this->invoke('pre_load', $library);
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
// Load all the files associated with the library.
|
2016-02-14 11:27:34 +01:00
|
|
|
$library['loaded'] = $this->loadFiles($library);
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
// TODO:
|
2016-02-14 13:01:36 +01:00
|
|
|
// Invoke callbacks in the 'post_load' group.
|
|
|
|
$this->invoke('post_load', $library);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
$loaded[$name] = $library;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $loaded[$name];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the path of a library.
|
|
|
|
*
|
|
|
|
* @param $name
|
|
|
|
* The machine name of a library to return the path for.
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
* The path to the specified library or FALSE if the library wasn't found.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function getPath($name)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
static $libraries;
|
|
|
|
|
|
|
|
if(!isset($libraries))
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$libraries = $this->getLibraries();
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
|
2016-02-14 11:27:34 +01:00
|
|
|
$path = '';
|
2016-02-12 10:18:13 +01:00
|
|
|
if(!isset($libraries[$name]))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$path .= $libraries[$name];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $path;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an array of library directories.
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
* A list of library directories.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function getLibraries()
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
$dir = e_WEB . 'lib';
|
2016-02-14 13:34:02 +01:00
|
|
|
$directories = array();
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
// Retrieve list of directories.
|
2016-02-14 13:34:02 +01:00
|
|
|
$file = e107::getFile();
|
|
|
|
$dirs = $file->get_dirs($dir);
|
|
|
|
|
|
|
|
foreach($dirs as $dirName)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 13:34:02 +01:00
|
|
|
$directories[$dirName] = "{e_WEB}lib/$dirName";
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $directories;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns information about registered libraries.
|
|
|
|
*
|
|
|
|
* The returned information is unprocessed; i.e., as registered by plugins.
|
|
|
|
*
|
|
|
|
* @param $library
|
|
|
|
* (optional) The machine name of a library to return registered information for. If omitted, information
|
|
|
|
* about all registered libraries is returned.
|
|
|
|
*
|
|
|
|
* @return array|false
|
|
|
|
* An associative array containing registered information for all libraries, the registered information for the
|
|
|
|
* library specified by $name, or FALSE if the library $name is not registered.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function &info($library = null)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
// This static cache is re-used by detect() to save memory.
|
2016-02-12 10:18:13 +01:00
|
|
|
static $libraries;
|
|
|
|
|
|
|
|
if(!isset($libraries))
|
|
|
|
{
|
|
|
|
$libraries = array();
|
|
|
|
|
|
|
|
$plugins = array();
|
|
|
|
$themes = array();
|
|
|
|
|
|
|
|
// Gather information from PLUGIN_library::config().
|
2016-02-13 15:33:23 -08:00
|
|
|
$pluginInfo = e107::getAddonConfig('e_library', 'library'); // 'config' is the default.
|
2016-02-12 10:18:13 +01:00
|
|
|
foreach($pluginInfo as $plugin => $info)
|
|
|
|
{
|
|
|
|
foreach($info as $machine_name => $properties)
|
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
$properties['info_type'] = 'plugin';
|
2016-02-12 10:18:13 +01:00
|
|
|
$properties['plugin'] = $plugin;
|
|
|
|
$libraries[$machine_name] = $properties;
|
|
|
|
$plugins[] = $plugin; // This plugin has a valid e_library implementation.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gather information from THEME_library::config().
|
|
|
|
$siteTheme = e107::getPref('sitetheme');
|
|
|
|
$adminTheme = e107::getPref('admintheme');
|
|
|
|
|
|
|
|
foreach(array($siteTheme, $adminTheme) as $theme)
|
|
|
|
{
|
2016-02-13 15:33:23 -08:00
|
|
|
if(is_readable(e_THEME . $theme . '/theme_library.php')) // we don't use e_XXXX for themes.
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-13 15:33:23 -08:00
|
|
|
e107_require_once(e_THEME . $theme . '/theme_library.php');
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
$className = $theme . '_library';
|
|
|
|
if(class_exists($className))
|
|
|
|
{
|
|
|
|
$addonClass = new $className();
|
|
|
|
|
|
|
|
if(method_exists($addonClass, 'config'))
|
|
|
|
{
|
|
|
|
$info = $addonClass->config();
|
|
|
|
if(is_array($info))
|
|
|
|
{
|
|
|
|
foreach($info as $machine_name => $properties)
|
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
$properties['info_type'] = 'theme';
|
2016-02-12 10:18:13 +01:00
|
|
|
$properties['theme'] = $theme;
|
|
|
|
$libraries[$machine_name] = $properties;
|
|
|
|
$themes[] = $theme; // This theme has a valid e_library implementation.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Provide defaults.
|
|
|
|
foreach($libraries as $machine_name => &$properties)
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->infoDefaults($properties, $machine_name);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Allow enabled plugins (with e_library.php file) to alter the registered libraries.
|
|
|
|
foreach($plugins as $plugin)
|
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
$class = e107::getAddon($plugin, 'e_library');
|
|
|
|
if($class && method_exists($class, 'config_alter'))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 12:38:46 +01:00
|
|
|
// The library definitions are passed by reference.
|
|
|
|
$class->config_alter($libraries);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-13 15:33:23 -08:00
|
|
|
// Allow enabled themes (with theme_library.php file) to alter the registered libraries.
|
2016-02-12 10:18:13 +01:00
|
|
|
foreach($themes as $theme)
|
|
|
|
{
|
2016-02-13 15:33:23 -08:00
|
|
|
e107_require_once(e_THEME . $theme . '/theme_library.php');
|
2016-02-12 10:18:13 +01:00
|
|
|
$addonClass = $theme . '_library';
|
|
|
|
|
|
|
|
if(class_exists($addonClass))
|
|
|
|
{
|
|
|
|
$class = new $addonClass();
|
|
|
|
if(method_exists($class, 'config_alter'))
|
|
|
|
{
|
|
|
|
$class->config_alter($libraries);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO:
|
|
|
|
// Invoke callbacks in the 'info' group.
|
|
|
|
foreach($libraries as &$properties)
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->invoke('info', $properties);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(isset($library))
|
|
|
|
{
|
|
|
|
if(!empty($libraries[$library]))
|
|
|
|
{
|
|
|
|
return $libraries[$library];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$false = false;
|
|
|
|
return $false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $libraries;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Applies default properties to a library definition.
|
|
|
|
*
|
|
|
|
* @param array $library
|
|
|
|
* An array of library information, passed by reference.
|
|
|
|
* @param string $name
|
|
|
|
* The machine name of the passed-in library.
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function infoDefaults(&$library, $name)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
$library += array(
|
2016-02-14 13:01:36 +01:00
|
|
|
'machine_name' => $name,
|
2016-02-12 10:18:13 +01:00
|
|
|
'name' => $name,
|
2016-02-14 13:01:36 +01:00
|
|
|
'vendor_url' => '',
|
|
|
|
'download_url' => '',
|
2016-02-12 10:18:13 +01:00
|
|
|
'path' => '',
|
2016-02-14 13:01:36 +01:00
|
|
|
'library_path' => null,
|
|
|
|
'version_callback' => 'getVersion',
|
|
|
|
'version_arguments' => array(),
|
2016-02-12 10:18:13 +01:00
|
|
|
'files' => array(),
|
|
|
|
'dependencies' => array(),
|
|
|
|
'variants' => array(),
|
|
|
|
'versions' => array(),
|
2016-02-14 13:01:36 +01:00
|
|
|
'integration_files' => array(),
|
2016-02-12 10:18:13 +01:00
|
|
|
'callbacks' => array(),
|
|
|
|
);
|
|
|
|
|
|
|
|
$library['callbacks'] += array(
|
|
|
|
'info' => array(),
|
2016-02-14 13:01:36 +01:00
|
|
|
'pre_detect' => array(),
|
|
|
|
'post_detect' => array(),
|
|
|
|
'pre_dependencies_load' => array(),
|
|
|
|
'pre_load' => array(),
|
|
|
|
'post_load' => array(),
|
2016-02-12 10:18:13 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
// Add our own callbacks before any others.
|
2016-02-14 11:27:34 +01:00
|
|
|
array_unshift($library['callbacks']['info'], 'prepareFiles');
|
2016-02-14 13:01:36 +01:00
|
|
|
array_unshift($library['callbacks']['post_detect'], 'detectDependencies');
|
2016-02-12 10:18:13 +01:00
|
|
|
|
|
|
|
return $library;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Library info callback to make all 'files' properties consistent.
|
|
|
|
*
|
|
|
|
* This turns libraries' file information declared as e.g.
|
|
|
|
* @code
|
|
|
|
* $library['files']['js'] = array('example_1.js', 'example_2.js');
|
|
|
|
* @endcode
|
|
|
|
* into
|
|
|
|
* @code
|
|
|
|
* $library['files']['js'] = array(
|
|
|
|
* 'example_1.js' => array(),
|
|
|
|
* 'example_2.js' => array(),
|
|
|
|
* );
|
|
|
|
* @endcode
|
2016-02-14 13:01:36 +01:00
|
|
|
* It does the same for the 'integration_files' property.
|
2016-02-12 10:18:13 +01:00
|
|
|
*
|
|
|
|
* @param $library
|
|
|
|
* An associative array of library information or a part of it, passed by reference.
|
|
|
|
* @param $version
|
|
|
|
* If the library information belongs to a specific version, the version string. NULL otherwise.
|
|
|
|
* @param $variant
|
|
|
|
* If the library information belongs to a specific variant, the variant name. NULL otherwise.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function prepareFiles(&$library, $version = null, $variant = null)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
// Both the 'files' property and the 'integration_files' property contain file declarations, and we want to make
|
2016-02-12 10:18:13 +01:00
|
|
|
// both consistent.
|
|
|
|
$file_types = array();
|
|
|
|
if(isset($library['files']))
|
|
|
|
{
|
|
|
|
$file_types[] = &$library['files'];
|
|
|
|
}
|
2016-02-14 13:01:36 +01:00
|
|
|
if(isset($library['integration_files']))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
// Integration files are additionally keyed by plugin.
|
2016-02-14 13:01:36 +01:00
|
|
|
foreach($library['integration_files'] as &$integration_files)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
$file_types[] = &$integration_files;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach($file_types as &$files)
|
|
|
|
{
|
|
|
|
// Go through all supported types of files.
|
|
|
|
foreach(array('js', 'css', 'php') as $type)
|
|
|
|
{
|
|
|
|
if(isset($files[$type]))
|
|
|
|
{
|
|
|
|
foreach($files[$type] as $key => $value)
|
|
|
|
{
|
|
|
|
// Unset numeric keys and turn the respective values into keys.
|
|
|
|
if(is_numeric($key))
|
|
|
|
{
|
|
|
|
$files[$type][$value] = array();
|
|
|
|
unset($files[$type][$key]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-02-14 13:01:36 +01:00
|
|
|
* Library post detect callback to process and detect dependencies.
|
2016-02-12 10:18:13 +01:00
|
|
|
*
|
|
|
|
* It checks whether each of the dependencies of a library are installed and available in a compatible version.
|
|
|
|
*
|
|
|
|
* @param $library
|
|
|
|
* An associative array of library information or a part of it, passed by reference.
|
|
|
|
* @param $version
|
|
|
|
* If the library information belongs to a specific version, the version string. NULL otherwise.
|
|
|
|
* @param $variant
|
|
|
|
* If the library information belongs to a specific variant, the variant name. NULL otherwise.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function detectDependencies(&$library, $version = null, $variant = null)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
if(isset($library['dependencies']))
|
|
|
|
{
|
|
|
|
foreach($library['dependencies'] as &$dependency_string)
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$dependency_info = $this->parseDependency($dependency_string);
|
|
|
|
$dependency = $this->detect($dependency_info['name']);
|
2016-02-12 10:18:13 +01:00
|
|
|
if(!$dependency['installed'])
|
|
|
|
{
|
|
|
|
$library['installed'] = false;
|
|
|
|
$library['error'] = LAN_LIBRARY_MANAGER_07;
|
|
|
|
|
|
|
|
$replace_with = array($dependency['name'], $library['name']);
|
2016-02-14 13:01:36 +01:00
|
|
|
$library['error_message'] = e107::getParser()->lanVars(LAN_LIBRARY_MANAGER_01, $replace_with);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
2016-02-14 11:27:34 +01:00
|
|
|
elseif($this->checkIncompatibility($dependency_info, $dependency['version']))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
$library['installed'] = false;
|
|
|
|
$library['error'] = LAN_LIBRARY_MANAGER_08;
|
|
|
|
|
|
|
|
$replace_with = array($dependency['version'], $library['name'], $library['name']);
|
2016-02-14 13:01:36 +01:00
|
|
|
$library['error_message'] = e107::getParser()->lanVars(LAN_LIBRARY_MANAGER_02, $replace_with);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
|
2016-02-14 11:27:34 +01:00
|
|
|
// Remove the version string from the dependency, so load() can load the libraries directly.
|
2016-02-12 10:18:13 +01:00
|
|
|
$dependency_string = $dependency_info['name'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invokes library callbacks.
|
|
|
|
*
|
|
|
|
* @param $group
|
2016-02-14 13:01:36 +01:00
|
|
|
* A string containing the group of callbacks that is to be applied. Should be either 'info', 'post_detect'.
|
2016-02-12 10:18:13 +01:00
|
|
|
* @param $library
|
|
|
|
* An array of library information, passed by reference.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function invoke($group, &$library)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
// When introducing new callback groups in newer versions, stale cached library information somehow reaches
|
|
|
|
// this point during the database update before clearing the library cache.
|
|
|
|
if(empty($library['callbacks'][$group]))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach($library['callbacks'][$group] as $callback)
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->traverseLibrary($library, $callback);
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper function to apply a callback to all parts of a library.
|
|
|
|
*
|
|
|
|
* Because library declarations can include variants and versions, and those version declarations can in turn
|
|
|
|
* include variants, modifying e.g. the 'files' property everywhere it is declared can be quite cumbersome, in
|
|
|
|
* which case this helper function is useful.
|
|
|
|
*
|
|
|
|
* @param $library
|
|
|
|
* An array of library information, passed by reference.
|
|
|
|
* @param $callback
|
|
|
|
* A string containing the callback to apply to all parts of a library.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function traverseLibrary(&$library, $callback)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
// If callback belongs to $this class.
|
|
|
|
if(method_exists($this, $callback))
|
|
|
|
{
|
|
|
|
// Always apply the callback to the top-level library.
|
|
|
|
// Params: $library, $version, $variant
|
|
|
|
$this->$callback($library, null, null);
|
|
|
|
|
|
|
|
// Apply the callback to versions.
|
|
|
|
if(isset($library['versions']))
|
|
|
|
{
|
|
|
|
foreach($library['versions'] as $version_string => &$version)
|
|
|
|
{
|
|
|
|
$this->$callback($version, $version_string, null);
|
|
|
|
|
|
|
|
// Versions can include variants as well.
|
|
|
|
if(isset($version['variants']))
|
|
|
|
{
|
|
|
|
foreach($version['variants'] as $version_variant_name => &$version_variant)
|
|
|
|
{
|
|
|
|
$this->$callback($version_variant, $version_string, $version_variant_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply the callback to variants.
|
|
|
|
if(isset($library['variants']))
|
|
|
|
{
|
|
|
|
foreach($library['variants'] as $variant_name => &$variant)
|
|
|
|
{
|
|
|
|
$this->$callback($variant, null, $variant_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// TODO: Provide the ability to use third-party callbacks (are defined in e_library.php files) for groups:
|
2016-02-14 13:01:36 +01:00
|
|
|
// 'info', 'pre_detect', 'post_detect', 'pre_dependencies_load', 'pre_load', 'post_load'
|
2016-02-12 10:18:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads a library's files.
|
|
|
|
*
|
|
|
|
* @param $library
|
2016-02-14 11:27:34 +01:00
|
|
|
* An array of library information as returned by info().
|
2016-02-12 10:18:13 +01:00
|
|
|
*
|
|
|
|
* @return int
|
|
|
|
* The number of loaded files.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function loadFiles($library)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
$siteTheme = e107::getPref('sitetheme');
|
|
|
|
$adminTheme = e107::getPref('admintheme');
|
|
|
|
|
2016-02-14 13:01:36 +01:00
|
|
|
// Load integration_files.
|
|
|
|
if(!$library['post_load_integration_files'] && !empty($library['integration_files']))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
foreach($library['integration_files'] as $provider => $files)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
// If provider is an installed plugin.
|
|
|
|
if(e107::isInstalled($provider))
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->loadFiles(array(
|
2016-02-12 10:18:13 +01:00
|
|
|
'files' => $files,
|
|
|
|
'path' => '',
|
2016-02-14 13:01:36 +01:00
|
|
|
'library_path' => e_PLUGIN . $provider,
|
|
|
|
'post_load_integration_files' => false,
|
2016-02-12 10:18:13 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
// If provider is the admin theme, we only allow it for admin pages.
|
|
|
|
elseif(e_ADMIN_AREA && $provider == $adminTheme)
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->loadFiles(array(
|
2016-02-12 10:18:13 +01:00
|
|
|
'files' => $files,
|
|
|
|
'path' => '',
|
2016-02-14 13:01:36 +01:00
|
|
|
'library_path' => e_THEME . $provider,
|
|
|
|
'post_load_integration_files' => false,
|
2016-02-12 10:18:13 +01:00
|
|
|
));
|
|
|
|
}
|
2016-02-14 11:27:34 +01:00
|
|
|
// If provider is the site theme, we only allow it on user areas.
|
2016-02-12 10:18:13 +01:00
|
|
|
elseif(!deftrue(e_ADMIN_AREA, false) && $provider == $siteTheme)
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->loadFiles(array(
|
2016-02-12 10:18:13 +01:00
|
|
|
'files' => $files,
|
|
|
|
'path' => '',
|
2016-02-14 13:01:36 +01:00
|
|
|
'library_path' => e_THEME . $provider,
|
|
|
|
'post_load_integration_files' => false,
|
2016-02-12 10:18:13 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct the full path to the library for later use.
|
2016-02-14 13:01:36 +01:00
|
|
|
$path = e107::getParser()->replaceConstants($library['library_path']);
|
2016-02-12 10:18:13 +01:00
|
|
|
$path = ($library['path'] !== '' ? $path . '/' . $library['path'] : $path);
|
|
|
|
|
|
|
|
// Count the number of loaded files for the return value.
|
|
|
|
$count = 0;
|
|
|
|
|
|
|
|
// Load both the JavaScript and the CSS files.
|
|
|
|
foreach(array('js', 'css') as $type)
|
|
|
|
{
|
|
|
|
if(!empty($library['files'][$type]))
|
|
|
|
{
|
|
|
|
foreach($library['files'][$type] as $data => $options)
|
|
|
|
{
|
|
|
|
// If the value is not an array, it's a filename and passed as first (and only) argument.
|
|
|
|
if(!is_array($options))
|
|
|
|
{
|
|
|
|
$data = $options;
|
|
|
|
$options = array();
|
|
|
|
}
|
|
|
|
// In some cases, the first parameter ($data) is an array. Arrays can't be passed as keys in PHP,
|
|
|
|
// so we have to get $data from the value array.
|
|
|
|
if(is_numeric($data))
|
|
|
|
{
|
|
|
|
$data = $options['data'];
|
|
|
|
unset($options['data']);
|
|
|
|
}
|
2016-02-14 13:01:36 +01:00
|
|
|
// Prepend the library_path to the file name.
|
2016-02-12 10:18:13 +01:00
|
|
|
$data = "$path/$data";
|
|
|
|
// Apply the default zone if the zone isn't explicitly given.
|
|
|
|
if(!isset($options['zone']))
|
|
|
|
{
|
|
|
|
$options['zone'] = ($type == 'js') ? 2 : 2; // TODO: default zones.
|
|
|
|
}
|
|
|
|
// Apply the default type if the type isn't explicitly given.
|
|
|
|
if(!isset($options['type']))
|
|
|
|
{
|
|
|
|
$options['type'] = 'url';
|
|
|
|
}
|
|
|
|
if($type == 'js')
|
|
|
|
{
|
|
|
|
e107::js($options['type'], $data, null, $options['zone']);
|
|
|
|
}
|
|
|
|
elseif($type == 'css')
|
|
|
|
{
|
|
|
|
e107::css($options['type'], $data, null);
|
|
|
|
}
|
|
|
|
$count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load PHP files.
|
|
|
|
if(!empty($library['files']['php']))
|
|
|
|
{
|
|
|
|
foreach($library['files']['php'] as $file => $array)
|
|
|
|
{
|
|
|
|
$file_path1 = $path . '/' . $file;
|
|
|
|
$file_path2 = e_ROOT . $path . '/' . $file;
|
|
|
|
|
|
|
|
if(file_exists($file_path1))
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->_requireOnce($file_path1);
|
2016-02-12 10:18:13 +01:00
|
|
|
$count++;
|
|
|
|
}
|
|
|
|
elseif(file_exists($file_path2))
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->_requireOnce($file_path2);
|
2016-02-12 10:18:13 +01:00
|
|
|
$count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-14 13:01:36 +01:00
|
|
|
// Load integration_files.
|
|
|
|
if($library['post_load_integration_files'] && !empty($library['integration_files']))
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
2016-02-14 13:01:36 +01:00
|
|
|
foreach($library['integration_files'] as $provider => $files)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
// If provider is an installed plugin.
|
|
|
|
if(e107::isInstalled($provider))
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->loadFiles(array(
|
2016-02-12 10:18:13 +01:00
|
|
|
'files' => $files,
|
|
|
|
'path' => '',
|
2016-02-14 13:01:36 +01:00
|
|
|
'library_path' => e_PLUGIN . $provider,
|
|
|
|
'post_load_integration_files' => false,
|
2016-02-12 10:18:13 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
// If provider is the admin theme, we only allow it for admin pages.
|
|
|
|
elseif(e_ADMIN_AREA && $provider == $adminTheme)
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->loadFiles(array(
|
2016-02-12 10:18:13 +01:00
|
|
|
'files' => $files,
|
|
|
|
'path' => '',
|
2016-02-14 13:01:36 +01:00
|
|
|
'library_path' => e_THEME . $provider,
|
|
|
|
'post_load_integration_files' => false,
|
2016-02-12 10:18:13 +01:00
|
|
|
));
|
|
|
|
}
|
2016-02-14 11:27:34 +01:00
|
|
|
// If provider is the site theme, we only allow it on user areas.
|
2016-02-12 10:18:13 +01:00
|
|
|
elseif(!deftrue(e_ADMIN_AREA, false) && $provider == $siteTheme)
|
|
|
|
{
|
2016-02-14 11:27:34 +01:00
|
|
|
$this->loadFiles(array(
|
2016-02-12 10:18:13 +01:00
|
|
|
'files' => $files,
|
|
|
|
'path' => '',
|
2016-02-14 13:01:36 +01:00
|
|
|
'library_path' => e_THEME . $provider,
|
|
|
|
'post_load_integration_files' => false,
|
2016-02-12 10:18:13 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wrapper function for require_once.
|
|
|
|
*
|
2016-02-14 11:27:34 +01:00
|
|
|
* A library file could set a $path variable in file scope. Requiring such a file directly in loadFiles()
|
2016-02-12 10:18:13 +01:00
|
|
|
* would lead to the local $path variable being overridden after the require_once statement. This would break
|
|
|
|
* loading further files. Therefore we use this trivial wrapper which has no local state that can be tampered with.
|
|
|
|
*
|
|
|
|
* @param $file_path
|
|
|
|
* The file path of the file to require.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function _requireOnce($file_path)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
// TODO: use e107_require_once() instead?
|
|
|
|
require_once $file_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the version information from an arbitrary library.
|
|
|
|
*
|
|
|
|
* @param $library
|
|
|
|
* An associative array containing all information about the library.
|
|
|
|
* @param $options
|
|
|
|
* An associative array containing with the following keys:
|
|
|
|
* - file: The filename to parse for the version, relative to the library path. For example: 'docs/changelog.txt'.
|
|
|
|
* - pattern: A string containing a regular expression (PCRE) to match the library version. For example:
|
|
|
|
* '@version\s+([0-9a-zA-Z\.-]+)@'. Note that the returned version is not the match of the entire pattern (i.e.
|
|
|
|
* '@version 1.2.3' in the above example) but the match of the first sub-pattern (i.e. '1.2.3' in the above example).
|
|
|
|
* - lines: (optional) The maximum number of lines to search the pattern in. Defaults to 20.
|
|
|
|
* - cols: (optional) The maximum number of characters per line to take into account. Defaults to 200. In case of
|
|
|
|
* minified or compressed files, this prevents reading the entire file into memory.
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
* A string containing the version of the library.
|
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function getVersion($library, $options)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
// Provide defaults.
|
|
|
|
$options += array(
|
|
|
|
'file' => '',
|
|
|
|
'pattern' => '',
|
|
|
|
'lines' => 20,
|
|
|
|
'cols' => 200,
|
|
|
|
);
|
|
|
|
|
2016-02-14 13:01:36 +01:00
|
|
|
$libraryPath = e107::getParser()->replaceConstants($library['library_path']);
|
2016-02-14 11:27:34 +01:00
|
|
|
$file = $libraryPath . '/' . $options['file'];
|
2016-02-12 10:18:13 +01:00
|
|
|
if(empty($options['file']) || !file_exists($file))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$file = fopen($file, 'r');
|
|
|
|
while($options['lines'] && $line = fgets($file, $options['cols']))
|
|
|
|
{
|
|
|
|
if(preg_match($options['pattern'], $line, $version))
|
|
|
|
{
|
|
|
|
fclose($file);
|
|
|
|
return $version[1];
|
|
|
|
}
|
|
|
|
$options['lines']--;
|
|
|
|
}
|
|
|
|
fclose($file);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-02-14 11:27:34 +01:00
|
|
|
* Parses a dependency for comparison by checkIncompatibility().
|
2016-02-12 10:18:13 +01:00
|
|
|
*
|
|
|
|
* @param $dependency
|
|
|
|
* A dependency string, which specifies a plugin dependency, and versions that are supported. Supported formats
|
|
|
|
* include:
|
|
|
|
* - 'plugin'
|
|
|
|
* - 'plugin (>=version, version)'
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
* An associative array with three keys:
|
|
|
|
* - 'name' includes the name of the thing to depend on (e.g. 'foo').
|
|
|
|
* - 'original_version' contains the original version string (which can be used in the UI for reporting
|
|
|
|
* incompatibilities).
|
|
|
|
* - 'versions' is a list of associative arrays, each containing the keys 'op' and 'version'. 'op' can be one of:
|
|
|
|
* '=', '==', '!=', '<>', '<', '<=', '>', or '>='. 'version' is one piece like '4.5-beta3'.
|
2016-02-14 11:27:34 +01:00
|
|
|
* Callers should pass this structure to checkIncompatibility().
|
2016-02-12 10:18:13 +01:00
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function parseDependency($dependency)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
$value = array();
|
|
|
|
|
|
|
|
// We use named subpatterns and support every op that version_compare supports. Also, op is optional and
|
|
|
|
// defaults to equals.
|
|
|
|
$p_op = '(?P<operation>!=|==|=|<|<=|>|>=|<>)?';
|
|
|
|
$p_major = '(?P<major>\d+)';
|
|
|
|
// By setting the minor version to x, branches can be matched.
|
|
|
|
$p_minor = '(?P<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
|
|
|
|
$parts = explode('(', $dependency, 2);
|
|
|
|
$value['name'] = trim($parts[0]);
|
|
|
|
|
|
|
|
if(isset($parts[1]))
|
|
|
|
{
|
|
|
|
$value['original_version'] = ' (' . $parts[1];
|
|
|
|
foreach(explode(',', $parts[1]) as $version)
|
|
|
|
{
|
|
|
|
if(preg_match("/^\s*$p_op\s*$p_major\.$p_minor/", $version, $matches))
|
|
|
|
{
|
|
|
|
$op = !empty($matches['operation']) ? $matches['operation'] : '=';
|
|
|
|
if($matches['minor'] == 'x')
|
|
|
|
{
|
|
|
|
// "2.x" to mean any version that begins with "2" (e.g. 2.0, 2.9 are all "2.x").
|
|
|
|
// PHP's version_compare(), on the other hand, treats "x" as a string; so to version_compare(),
|
|
|
|
// "2.x" is considered less than 2.0. This means that >=2.x and <2.x are handled by
|
|
|
|
// version_compare() as we need, but > and <= are not.
|
|
|
|
if($op == '>' || $op == '<=')
|
|
|
|
{
|
|
|
|
$matches['major']++;
|
|
|
|
}
|
|
|
|
// Equivalence can be checked by adding two restrictions.
|
|
|
|
if($op == '=' || $op == '==')
|
|
|
|
{
|
|
|
|
$value['versions'][] = array('op' => '<', 'version' => ($matches['major'] + 1) . '.x');
|
|
|
|
$op = '>=';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$value['versions'][] = array('op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether a version is compatible with a given dependency.
|
|
|
|
*
|
|
|
|
* @param $v
|
2016-02-14 11:27:34 +01:00
|
|
|
* The parsed dependency structure from parseDependency().
|
2016-02-12 10:18:13 +01:00
|
|
|
* @param $current_version
|
|
|
|
* The version to check against (like 4.2).
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* NULL if compatible, otherwise the original dependency version string that caused the incompatibility.
|
|
|
|
*
|
2016-02-14 11:27:34 +01:00
|
|
|
* @see parseDependency()
|
2016-02-12 10:18:13 +01:00
|
|
|
*/
|
2016-02-14 11:27:34 +01:00
|
|
|
private function checkIncompatibility($v, $current_version)
|
2016-02-12 10:18:13 +01:00
|
|
|
{
|
|
|
|
if(!empty($v['versions']))
|
|
|
|
{
|
|
|
|
foreach($v['versions'] as $required_version)
|
|
|
|
{
|
|
|
|
if((isset($required_version['op'])))
|
|
|
|
{
|
|
|
|
if(!version_compare($current_version, $required_version['version'], $required_version['op']))
|
|
|
|
{
|
|
|
|
return $v['original_version'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|