Add upstream plugins

Signed-off-by: Adrian Nöthlich <git@promasu.tech>
This commit is contained in:
2019-10-25 22:42:20 +02:00
parent 5d3c2ec184
commit 290736650a
1186 changed files with 302577 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
<?php
/**
* The base class which simply sets the registry object.
*
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Bootstrap
*/
abstract class Ai1ec_Base {
/**
* @var Ai1ec_Registry_Object
*/
protected $_registry;
/**
* The contructor method.
*
* Stores in object injected registry object.
*
* @param Ai1ec_Registry_Object $registry Injected registry object.
*/
public function __construct( Ai1ec_Registry_Object $registry ) {
$this->_registry = $registry;
}
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Exceptions occuring during bootstrap
*
* @author Time.ly Network Inc.
* @since 2.0
*
* @package AI1EC
* @subpackage AI1EC.Exception
*/
class Ai1ec_Bootstrap_Exception extends Ai1ec_Exception {
public function get_html_message() {
return '<p>Failure in All-in-One Event Calendar core:<br />' .
$this->getMessage() . '</p>';
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,525 @@
<?php
/**
* Autoloader Class
*
* This class is responsible for loading all the requested class of the
* system
*
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Loader
*/
class Ai1ec_Loader {
/**
* @var string Used to specify new instances every time.
*/
CONST NEWINST = 'n';
/**
* @var string Used to specify to treat as singleton.
*/
CONST GLOBALINST = 'g';
/**
* @var array Map of files to be included
*/
protected $_paths = array();
/**
* @var bool Set to true when internal state is changed
*/
protected $_modified = false;
/**
* @var array Map of files already included
*/
protected $_included_files = array();
/**
* @var string The prefix used for the classes
*/
protected $_prefix = null;
/**
* @var string Base path to plugins core directory
*/
protected $_base_path = null;
/**
* @var array Registered folders.
*/
protected $_registered = array();
/**
* load method
*
* Load given class, via `require`, into memory
*
* @param string $class Name of class, which needs to be loaded
*
* @return Ai1ec_Loader Instance of self for chaining
*/
public function load( $class ) {
if ( isset( $this->_paths[$class] ) ) {
$this->include_file( $this->_paths[$class]['f'] );
}
return $this;
}
/**
* Method which actually includes required file.
*
* The PHP language construct used is `require` and not a `require_once`,
* as this is internal method, which shall guard itself against incidents
* that may occur during loading classes more than once.
* During include additional callbacks may be fired to include related
* files, i.e. speed-up further requires.
*
* @param string $file Name of file to include
*
* @return Ai1ec_Loader Instance of self for chaining
*/
public function include_file( $file ) {
if ( ! isset( $this->_included_files[$file] ) ) {
$this->_included_files[$file] = true;
require $file;
}
return $this->_included_files[$file];
}
/**
* collect_classes method
*
* Method to extract classes list from filesystem.
* Returned array contains names of class, as keys, and file entites as
* value, where *entities* means either a file name
* - {@see self::match_file()} for more.
*
* @return array Map of classes and corresponding file entites
*/
public function collect_classes( $path = null, $folder_name = AI1EC_PLUGIN_NAME ) {
// extension inject theit own base path
$path = ( null === $path ) ? $this->_base_path : $path;
$names = $this->_locate_all_files( $path, $folder_name );
$names = $this->_process_reflections( $names );
$this->_cache( $path, $names );
$this->_paths = array_merge( $this->_paths, $names );
return $names;
}
/**
* Read/write cached classes map.
*
* If no entries are provided - acts as cache reader.
*
* @param array $entries Entries to write [optional=null]
*
* @return bool|array False on failure, true on success in writer
* mode, cached entry in reader mode on success
*/
protected function _cache( $path, array $entries = null ) {
$cache_file = $this->_get_cache_file_path( $path );
if ( $entries ) {
if (
is_file( $cache_file ) &&
! is_writable( $cache_file ) ||
! is_writable( dirname( $cache_file ) )
) {
return false;
}
ksort( $entries, SORT_STRING );
$content = array(
'0registered' => $this->_registered,
'1class_map' => $entries,
);
$content = var_export( $content, true );
$content = $this->_sanitize_paths( $content, $path );
$content = '<?php return ' . $content . ';';
$this->_modified = false;
if (
false === file_put_contents( $cache_file, $content, LOCK_EX )
) { // LOCK_EX is not supported on all hosts (streams)
return (bool)file_put_contents( $cache_file, $content );
}
return true;
}
if ( ! is_file( $cache_file ) ) {
return false;
}
$cached = ( require $cache_file );
$this->_registered[$cache_file] = true;
return $cached['1class_map'];
}
/**
* Gets the way classes must be instanciated.
*
* Retrieves from annotations the way classes must be retrieved.
* Possible values are
* - new: a new instance is instantiated every time
* - global: treat as singleton
* - classname.method: a factory is used, specify it in that order
* The default if nothing is specified is global.
*
* @param ReflectionClass $class
*
* @return string
*/
protected function _get_instantiator( ReflectionClass $class ) {
$doc = $class->getDocComment();
preg_match_all(
'#^\s\*\s@instantiator\s+(.*)$#im',
$doc,
$annotations
);
$instantiator = '';
if ( isset( $annotations[1][0] ) ) {
$instantiator = rtrim( $annotations[1][0] );
}
return $this->_convert_instantiator_for_map( $instantiator );
}
/**
* Check if the registry must be injected in the constructor.
* By convention the registry will always be the first parameter.
*
* @param ReflectionClass $class The class to check
*
* @return boolean true if the registry must be injected, false if not.
*/
protected function _inject_registry( ReflectionClass $class ) {
$contructor = $class->getConstructor();
if ( null !== $contructor ) {
foreach ( $contructor->getParameters() as $param ) {
$param_class = $param->getClass();
if ( $param_class instanceof ReflectionClass ) {
$name = $param_class->getName();
if ( 'Ai1ec_Registry_Object' === $name ) {
return true;
}
}
}
}
return false;
}
/**
* Update the classmap with Reflection informations.
*
* @param array $names The class map.
*
* @return array The classmap with instantiator.
*/
protected function _process_reflections( array $names ) {
$this->_paths = array_merge( $this->_paths, $names );
spl_autoload_register( array( $this, 'load' ) );
foreach ( $names as $classname => &$data ) {
try {
$class = new ReflectionClass( $data['c'] );
$data['i'] = $this->_get_instantiator( $class );
if ( $this->_inject_registry( $class ) ) {
$data['r'] = 'y';
}
} catch ( ReflectionException $excpt ) { // unreachable class
$data['i'] = self::NEWINST;
}
}
return $names;
}
/**
* Converts the long form to the short form where applicable.
*
* @param string $instantiator
*
* @return string
*/
protected function _convert_instantiator_for_map( $instantiator ) {
if ( empty( $instantiator ) || 'global' === $instantiator ) {
return self::GLOBALINST;
}
if ( 'new' === $instantiator ) {
return self::NEWINST;
}
return $instantiator;
}
/**
* _locate_all_files method
*
* Scan file system, given path, recursively, to search for files and
* extract `class` names from them.
*
* @param string $path File system path to scan
*
* @return array Map of classes and corresponding files
*/
protected function _locate_all_files( $path, $folder_name ) {
$class_list = array();
$directory = opendir( $path );
while ( false !== ( $entry = readdir( $directory ) ) ) {
if ( is_null( $entry ) || '.' === $entry{0} || 'tests' === $entry || strpos( strtolower( $entry ), 'icalcreator' ) !== false ) {
continue;
}
$local_path = $path . DIRECTORY_SEPARATOR . $entry;
$base_path = substr( $local_path, strlen( $this->_base_path ) );
if ( is_dir( $local_path ) ) {
$class_list += $this->_locate_all_files( $local_path, $folder_name );
} else {
$class_list += $this->_extract_classes( $local_path, $folder_name );
}
}
closedir( $directory );
return $class_list;
}
/**
* _extract_classes method
*
* Extract names of classes from given file.
* So far only files ending in `.php` are processed and regular expression
* is used instead of `token_get_all` to increase parsing speed.
*
* @param string $file Name of file to scan
*
* @return array List of classes in file
*/
protected function _extract_classes( $file, $folder_name ) {
$class_list = array();
if ( '.php' === strrchr( $file, '.' ) ) {
$tokens = token_get_all( file_get_contents( $file ) );
for ( $i = 2, $count = count( $tokens ); $i < $count; $i++ ) {
if (
T_CLASS === $tokens[$i - 2][0] ||
T_INTERFACE === $tokens[$i - 2][0] &&
T_WHITESPACE === $tokens[$i - 1][0] &&
T_STRING === $tokens[$i][0]
) {
$names = $this->_generate_loader_names(
$tokens[$i][1],
$file,
$folder_name
);
foreach ( $names as $name ) {
$class_list[$name] = array(
'f' => $file,
'c' => $tokens[$i][1],
);
}
}
}
}
return $class_list;
}
/**
* Generate path name abbreviation.
*
* @param string $name Path name particle.
*
* @return string Abbreviated path name.
*/
public function path_name_shortening( $name ) {
return strtoupper( $name[0] );
}
/**
* _sanitize_paths method
*
* Sanitize paths before writing to cache file.
* Make sure, that constants and absolute paths are used independently
* of system used, thus making file cross-platform generatable.
*
* @param string $content Output to be written to cache file.
* @param string $base_path Base path to use if not default.
*
* @return string Modified content, with paths replaced
*/
protected function _sanitize_paths(
$content,
$base_path = null
) {
$local_ds = '/';
$ai1ec_path = $this->_base_path;
$const_name = 'AI1EC_PATH';
if ( null !== $base_path ) {
$ai1ec_path = $base_path;
$const_name = implode( array_map(
array( $this, 'path_name_shortening' ),
explode( '-', basename( $base_path ) )
) ) . '_PATH';
$const_name = str_replace( 'AIOEC', 'AI1EC', $const_name );
}
if ( '\\' === DIRECTORY_SEPARATOR ) {
$local_ds = '\\\\';
$ai1ec_path = str_replace( '\\', '\\\\', $ai1ec_path );
}
$content = str_replace(
'\'' . $ai1ec_path . $local_ds,
$const_name . ' . DIRECTORY_SEPARATOR . \'',
$content
);
$content = str_replace(
$local_ds,
'\' . DIRECTORY_SEPARATOR . \'',
$content
);
return $content;
}
/**
* Generate all the alternatives name that the loaded recognize.
*
* For example:
* The class Ai1ec_Html_Helper can be loaded as
* - html.helper ( the path to the file )
* - Ai1ec_Html_Helper ( needed by Autoload )
*
* @param $class string the original name of the class.
* @param $file string the file
*
* @return array An array of strings with the availables names.
*/
protected function _generate_loader_names( $class, $file, $folder_name ) {
$names = array( $class );
// Remove the extension.
$file = substr( $file, 0, strrpos( $file , '.' ) );
$file = strtr( $file, array( '//' => '/' ) );
// Get just the meaningful data.
$relative_path_position = strrpos( // offset of base directory
$file,
DIRECTORY_SEPARATOR . $folder_name . DIRECTORY_SEPARATOR
);
$file = substr(
$file,
strpos( // cut to app|lib|vendor|...
$file,
DIRECTORY_SEPARATOR,
$relative_path_position + strlen( $folder_name ) + 2
)
);
$names[] = str_replace(
DIRECTORY_SEPARATOR,
'.',
trim( $file, DIRECTORY_SEPARATOR )
);
return $names;
}
/**
* Translate the key to the actual class name if any
*
* @param $key string Key requested to initialize
*
* @return array|null Array of the class, or null if none is found
*/
public function resolve_class_name( $key ) {
if ( ! isset( $this->_paths[$key] ) ) {
return null;
}
return $this->_paths[$key];
}
/**
* Update cache if object was modified
*
* @return void Destructor does not return
*/
public function __destruct() {
if ( $this->_modified ) {
$this->_cache( $this->_paths );
}
}
/**
* Convenience wrapper to detect internal extension file path.
*
* @param string $path Absolute path to extension base directory.
*
* @return bool Success loading extension classes.
*/
public function register_extension_map( $path ) {
return $this->register_map( $this->_get_cache_file_path( $path ) );
}
/**
* Register external class map to use in loading sequence
*
* @param string $file Path to class map
*
* @return bool Success loading it
*/
public function register_map( $file ) {
if (
isset( $this->_registered[$file] ) && (
! defined( 'AI1EC_DEBUG' ) ||
! AI1EC_DEBUG
)
) {
return true;
}
if ( ! is_file( $file ) ) {
return false;
}
$entries = ( require $file );
foreach ( $entries['1class_map'] as $class_name => $properties ) {
$this->_paths[$class_name] = $properties;
}
$this->_registered[$file] = true;
return true;
}
/**
* Constructor
*
* Initialize the loader creating the map of available classes, if the
* AI1EC_DEBUG constants is true the list is regenerated
*
* @throws Exception if the map is invalid
*
* @return void Constructor does not return
*/
public function __construct( $base_path ) {
$this->_base_path = $base_path;
$this->_prefix = explode( '_', __CLASS__ );
$this->_prefix = $this->_prefix[0];
$class_map = $this->_cache( $base_path );
if (
! is_array( $class_map ) ||
defined( 'AI1EC_DEBUG' ) && AI1EC_DEBUG
) {
if ( ! defined( 'AI1EC_DEBUG' ) || ! AI1EC_DEBUG ) {
// using generic `Ai1ec_Exception` as others are, potentially,
// not resolved at this time.
throw new Ai1ec_Exception(
'Generated class map is invalid: ' .
var_export( $class_map, true ) .
'. Please delete lib/bootstrap/loader-map.php (if it exists), make ' .
'sure lib/bootstrap/ is writable by the web server, and enable ' .
'debug mode by setting AI1EC_DEBUG to true (then back to false ' .
'when done).'
);
}
$class_map = $this->collect_classes();
}
$this->_paths = $class_map;
}
/**
* Method to get cache file path given path to plugin.
*
* @param string $path Path to plugin directory.
*
* @return string Absolute path to loader cache file.
*/
protected function _get_cache_file_path( $path ) {
return $path . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR .
'bootstrap' . DIRECTORY_SEPARATOR . 'loader-map.php';
}
}

View File

@@ -0,0 +1,48 @@
<?php
/**
* Application Registry: handles application wide variables.
*
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Object
*/
class Ai1ec_Registry_Application implements Ai1ec_Registry {
/**
* @var Ai1ec_Registry_Object
*/
protected $_registry;
/**
* @var array
*/
protected $_environment = array();
/**
* The contructor method.
*
* @param Ai1ec_Registry_Object $registry
*/
function __construct( Ai1ec_Registry_Object $registry ) {
$this->_registry = $registry;
}
/* (non-PHPdoc)
* @see Ai1ec_Registry::get()
*/
public function get( $key ) {
if ( ! isset ( $this->_environment[$key] ) ) {
return false;
}
return $this->_environment[$key];
}
/* (non-PHPdoc)
* @see Ai1ec_Registry::set()
*/
public function set( $key, $value ) {
$this->_environment[$key] = $value;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* The basic registry interface.
*
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Object
*/
interface Ai1ec_Registry {
/**
* Retrieves the key from the registry
*
* @param string $key
*
* @return mixed the value associated to the key.
*/
public function get( $key );
/**
* Set the key into the registry.
*
* @param string $key
* @param mixed $value
*/
public function set( $key, $value );
}

View File

@@ -0,0 +1,236 @@
<?php
/**
* Object Registry: get instance of requested and optionally registered object.
*
* Object (instance of a class) is generater, or returned from internal cache
* if it was requested and instantiated before.
*
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Object
*/
class Ai1ec_Registry_Object implements Ai1ec_Registry {
/**
* @var array The internal objects cache
*/
private $_objects = array();
/**
* @var Ai1ec_Loader The Ai1ec_Loader instance used by the registry
*/
private $_loader = null;
/**
* Get the loader ( used by extensions )
*
* @return Ai1ec_Loader
*/
public function get_loader() {
return $this->_loader;
}
/**
* Method prepares environment for easier extension integration.
*
* NOTICE: only extensions, that follow internal guideliness for
* files and methods organization must call this hook.
*
* Absolute path to extensions directory is autodetected, if not
* provided, appending plugins name to path to plugins dir.
*
* @param string $name Name of the extension.
* @param string $path Absolute path to extension directory.
*
* @return Ai1ec_Registry_Object Instance of self for chaining.
*/
public function extension_acknowledge( $name, $path = null ) {
if ( null === $path ) {
$path = AI1EC_EXTENSIONS_BASEDIR . $name;
}
if ( AI1EC_DEBUG ) {
$this->_loader->collect_classes( $path, $name );
}
$this->get( 'theme.loader' )->register_extension(
$path,
plugins_url( $name )
);
$this->_loader->register_extension_map( $path );
do_action( 'ai1ec_extension_loaded', $path, $name );
return $this;
}
/**
* Get class instance.
*
* Return an instance for the requested key, this method has an internal
* cache.
*
* @param string $key Name of previously registered object or parseable
* class name
*
* @return object Instance of the requested class
*/
public function get( $key ) {
$class_data = $this->_loader->resolve_class_name( $key );
if ( ! $class_data ) {
throw new Ai1ec_Bootstrap_Exception(
'Unable to resolve class for "' . $key . '"'
);
}
$class_name = $class_data['c'];
if (
'Ai1ec_Event' === $class_name &&
$this->get( 'compatibility.check' )->use_backward_compatibility()
) {
$class_name = 'Ai1ec_Event_Compatibility';
}
$instantiator = $class_data['i'];
$args = array_slice( func_get_args(), 1 );
if ( isset ( $class_data['r'] ) ) {
array_unshift( $args, $this );
}
if ( Ai1ec_Loader::NEWINST === $instantiator ) {
return $this->initiate(
$class_name,
$args
);
}
if ( Ai1ec_Loader::GLOBALINST === $instantiator ) {
if ( ! isset( $this->_objects[$class_name] ) ) {
// Ask the loader to load the required files to avoid autoloader
$this->_loader->load( $class_name );
$this->_objects[$class_name] = $this->initiate(
$class_name,
$args
);
}
return $this->_objects[$class_name];
}
// Ok it's a factory.
$factory = explode( '.', $instantiator );
return $this->dispatch(
$factory[0],
$factory[1],
$args
);
}
/**
* Allow to set previously created globally accessible class instance.
*
* @param string $name Class name to be used.
* @param object $object Actual instance of class above.
*
* @return void
*/
public function inject_object( $name, $object ) {
if ( ! is_object( $object ) || ! ( $object instanceof $name ) ) {
throw new Ai1ec_Bootstrap_Exception(
'Attempt to inject not an object / invalid object.'
);
}
$this->_objects[$name] = $object;
}
/* (non-PHPdoc)
* @see Ai1ec_Registry::set()
*/
public function set( $key, $value ) {
// The set method allows to inject classes from extensions into the registry.
new Ai1ec_Bootstrap_Exception( 'Not implemented' );
}
/**
* Instanciate the class given the class names and arguments.
*
* @param string $class_name The name of the class to instanciate.
* @param array $argv An array of aguments for construction.
*
* @return object A new instance of the requested class
*/
public function initiate( $class_name, array $argv = array() ) {
switch ( count( $argv ) ) {
case 0:
return new $class_name();
case 1:
return new $class_name( $argv[0] );
case 2:
return new $class_name( $argv[0], $argv[1] );
case 3:
return new $class_name( $argv[0], $argv[1], $argv[2] );
case 4:
return new $class_name( $argv[0], $argv[1], $argv[2], $argv[3] );
case 5:
return new $class_name( $argv[0], $argv[1], $argv[2], $argv[3], $argv[4] );
}
$reflected = new ReflectionClass( $class_name );
return $reflected->newInstanceArgs( $argv );
}
/**
* A call_user_func_array alternative.
*
* @param string $class
* @param string $method
* @param array $params
*
* @return mixed
*/
public function dispatch( $class, $method, $params = array() ) {
if ( empty( $class ) ) {
switch ( count( $params) ) {
case 0:
return $method();
case 1:
return $method( $params[0] );
case 2:
return $method( $params[0], $params[1] );
case 3:
return $method( $params[0], $params[1], $params[2] );
default:
return call_user_func_array( $method, $params );
}
} else {
// get an instance of the class
$class = $this->get( $class );
switch ( count( $params) ) {
case 0:
return $class->{$method}();
case 1:
return $class->{$method}( $params[0] );
case 2:
return $class->{$method}( $params[0], $params[1] );
case 3:
return $class->{$method}( $params[0], $params[1], $params[2] );
default:
return call_user_func_array(
array( $class, $method ),
$params
);
}
}
}
/**
* Constructor
*
* Initialize the Registry
*
* @param Ai1ec_Loader $ai1ec_loader Instance of Ai1EC classes loader
*
* @return void Constructor does not return
*/
public function __construct( $ai1ec_loader ) {
$this->_loader = $ai1ec_loader;
}
}