Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

362 lines (336 sloc) 11.457 kb
<?php
/**
* @package Habari
*
*/
/**
* Pluggable class
* Implements methods that allow descendant classes to register functions to plugin hooks
*
* @version $Id$
* @copyright 2008
*/
abstract class Pluggable
{
private $_class_name = null;
public $info;
public $plugin_id;
private $_new_rules = array();
protected $_added_templates = array();
/**
* Pluggable constructor.
* This function creates some internal structures that are required for plugin processing
* Plugins should not define their own constructors, because they are instantiated
* to extract plugin info. Instead, include a sink for a "init" hook
* which is executed immediately after the plugin is loaded during normal execution.
*/
public function __construct()
{
$this->info = $this->info();
$this->plugin_id = $this->plugin_id();
}
/**
* Gets the filename that contains this pluggable class
* @return string The filename of the file that contains the pluggable class.
*/
final public function get_file()
{
if ( empty( $this->_class_name ) ) {
$class = new ReflectionClass( get_class( $this ) );
$this->_class_name = $class->getFileName();
}
return $this->_class_name;
}
/**
* Gets a database schema associated with this pluggable
* @return string The database schema
*/
final public function get_db_schema()
{
$db = DB::get_driver_name();
$schema = dirname( $this->get_file() ) . '/schema/' . $db . '.sql';
return file_get_contents( $schema );
}
/**
* Get a fully-qualified URL directory that contains this pluggable class
*
* @param bool whether to include a trailing slash. Default: No
* @return string URL
*/
public function get_url( $trail = false )
{
return URL::get_from_filesystem( $this->get_file(), $trail );
}
/**
* Returns a unique id for this pluggable
* @return string A plugin id
*/
final public function plugin_id()
{
static $id;
if ( !isset( $id ) ) {
$id = Plugins::id_from_file( str_replace( '\\', '/', $this->get_file() ) );
}
return $id;
}
/**
* Load a translation domain/file for this pluggable
* @return boolean true if data was successfully loaded, false otherwise
*/
public function load_text_domain( $domain )
{
$base_dir = realpath( dirname( $this->get_file() ) );
return HabariLocale::load_pluggable_domain( $domain, $base_dir );
}
/**
* Registers all of this class' action_ and filter_ functions with the Plugins dispatcher
* Registers xmlrpc_ functions with the Plugins dispatcher, and turns '__' into '.'
* for the purposes of matching dotted XMLRPC requests.
* If the class is an instance of Pluggable, registers the hooks with a plugin id also.
* @param mixed $object The object or class name to register the hooks of
**/
public static function load_hooks($object)
{
static $registered = array();
if(is_object($object)) {
$hash = spl_object_hash($object);
if(isset($registered[$hash])) {
return;
}
else {
$registered[$hash] = true;
}
}
else {
$registered[$object] = true;
}
// combine the array so we can have hooks => function
$methods = get_class_methods( $object );
$methods = array_combine( $methods, $methods );
// get the specific priority values for functions, as needed
if ( method_exists( $object, 'set_priorities' ) ) {
$priorities = $object->set_priorities();
}
// get the aliases.
if ( method_exists( $object, 'alias' ) ) {
$methods = array_merge_recursive( $methods, $object->alias() );
}
// loop over all the methods in this class
foreach ( $methods as $fn => $hooks ) {
// loop hooks and register callback for each
foreach ( (array) $hooks as $hook ) {
// make sure the method name is of the form
// action_foo or filter_foo of xmlrpc_foo or theme_foo
if ( preg_match( '#^(action|filter|xmlrpc|theme)_#i', $hook ) ) {
$priority = 8;
if(isset($priorities[$hook])) {
$priority = $priorities[$hook];
}
elseif(preg_match('#^(.+)_(\d+)$#', $hook, $priority_match)) {
$hook = $priority_match[1];
$priority = intval($priority_match[2]);
}
elseif(isset( $priorities[$fn])) {
$priority = $priorities[$fn];
}
list( $type, $hook ) = explode( '_', $hook, 2 );
if ( $type === 'xmlrpc' ) {
$hook = str_replace( '__', '.', $hook );
}
Plugins::register( array( $object, $fn ), $type, $hook, $priority );
if($object instanceof Pluggable) {
Plugins::register( array( $object, $fn ), $type, $hook . ':' . $object->plugin_id(), $priority );
}
}
}
}
}
/**
* Called when a pluggable is loaded to register its actions and filters.
*/
public function load()
{
self::load_hooks($this);
// look for help with this
if ( method_exists( $this, 'help' ) ) {
Plugins::register( array( $this, '_help_plugin_config' ), 'filter', 'plugin_config:' . $this->plugin_id(), 8 );
Plugins::register( array( $this, '_help_plugin_ui' ), 'action', 'plugin_ui:' . $this->plugin_id(), 8 );
}
// look for a basic configure method
if ( method_exists( $this, 'configure' ) ) {
Plugins::register( array( $this, '_configure_plugin_config' ), 'filter', 'plugin_config:' . $this->plugin_id(), 8 );
Plugins::register( array( $this, '_configure_plugin_ui' ), 'action', 'plugin_ui:' . $this->plugin_id(), 8 );
}
}
/**
* Registered to the plugin_config hook to supply help via a plugin's help() method
*
* @param array $actions An array of actions applicable to this plugin
* @param string $plugin_id The plugin id to which the actions belong
* @return array The modified array of actions
*/
public function _help_plugin_config( $actions, $plugin_id )
{
if ( $plugin_id == $this->plugin_id() ) {
$actions['_help'] = _t( '?' );
}
return $actions;
}
/**
* Registered to the plugin_ui hook to supply help via a plugin's help() method
*
* @param string $plugin_id The id of the plugin whose action was triggered
* @param string $action The action triggered
*/
public function _help_plugin_ui( $plugin_id, $action )
{
if ( $plugin_id == $this->plugin_id() && $action == '_help' ) {
$output = $this->help();
if ( $output instanceof FormUI ) {
$output->out();
}
else {
echo "<div class=\"help\">{$output}</div>";
}
}
}
/**
* Registered to the plugin_config hook to supply a config via a plugin's configure() method
*
* @param array $actions An array of actions applicable to this plugin
* @param string $plugin_id The plugin id to which the actions belong
* @return array The modified array of actions
*/
public function _configure_plugin_config( $actions, $plugin_id )
{
if ( $plugin_id == $this->plugin_id() ) {
$actions['_configure'] = _t( 'Configure' );
}
return $actions;
}
/**
* Registered to the plugin_ui hook to supply a config via a plugin's configure() method
*
* @param string $plugin_id The id of the plugin whose action was triggered
* @param string $action The action triggered
*/
public function _configure_plugin_ui( $plugin_id, $action )
{
if ( $plugin_id == $this->plugin_id() && $action == '_configure' ) {
$output = $this->configure();
if ( $output instanceof FormUI ) {
$output->out();
}
else {
echo $output;
}
}
}
/**
* Add a rewrite rule that dispatches entirely to a plugin hook
*
* @param mixed $rule An old-style rewrite rule string, where quoted segments are literals and unquoted segments are variable names, OR a RewriteRule object
* @param string $hook The suffix of the hook function: action_plugin_act_{$suffix}
* #param Callback $fn A potential function/method to register directly to the newly created hook
*/
public function add_rule( $rule, $hook, $fn = null )
{
if ( count( $this->_new_rules ) == 0 ) {
Plugins::register( array( $this, '_filter_rewrite_rules' ), 'filter', 'rewrite_rules', 7 );
}
if ( $rule instanceof RewriteRule ) {
$this->_new_rules[] = $rule;
}
else {
$this->_new_rules[] = RewriteRule::create_url_rule( $rule, 'PluginHandler', $hook );
}
if(!is_null($fn)) {
Plugins::register($fn, 'theme', 'route_' . $hook);
}
}
/**
* Add the rewrite rules queued by add_rule() to the full rule set
*
* @param array $rules The array of current RewriteRules
* @return array The appended array of RewriteRules
*/
public function _filter_rewrite_rules( $rules )
{
$rules = array_merge( $rules, $this->_new_rules );
return $rules;
}
/**
* Adds a template to the default theme that is stored in a specified path.
* Use this function as a shortcut to make available additional templates to a theme
* from within the plugin directory.
*
* @param string $name The name of the template that will be displayed, sans extension
* @param string $filename The full path of the template file used for the specified name
* @param boolean $override If false, allow a template with the same name in the active theme directory to override this one.
* If true, always override the active theme's template with this one.
*/
protected function add_template( $name, $filename, $override = false )
{
if ( count( $this->_added_templates ) == 0 ) {
Plugins::register( array( &$this, '_plugin_available_templates' ), 'filter', 'available_templates' );
Plugins::register( array( &$this, '_plugin_include_template_file' ), 'filter', 'include_template_file' );
}
$this->_added_templates[$name] = array( $filename, $override );
}
/**
* Add plugin templates to the list of templates that are present in the current theme
*
* @param array $list List of template names in the current theme
* @return array The modified list of template names
*/
public function _plugin_available_templates( $list )
{
$list = array_merge( $list, array_keys( $this->_added_templates ) );
return $list;
}
/**
* Potentially serve a different file for the requested template name
*
* @param string $file The filename of the template the theme will display
* @param string $name The name of the template requested
* @return string The potentially modified filename to use for the requested template.
*/
public function _plugin_include_template_file( $file, $name )
{
if ( isset( $this->_added_templates[$name] ) ) {
if ( $this->_added_templates[$name][1] || !file_exists( $file ) ) {
$file = $this->_added_templates[$name][0];
}
}
return $file;
}
/**
* Provide a method to return the version number from a pluggable's info
* @return string The version of the pluggable
**/
public abstract function get_version();
/**
* Execute the upgrade action on any pluggable that has a version number change
* Update the version number of the pluggable in the database to what is installed
*/
public function upgrade()
{
if(DB::is_connected() && @ Options::get( 'installed' )) {
$pluggable_class = get_class($this);
$versions = Options::get( 'pluggable_versions' );
if(isset($versions[$pluggable_class])) {
$old_version = $versions[$pluggable_class];
if($old_version != $this->get_version()) {
Plugins::act_id('upgrade', $this->plugin_id(), $old_version);
$versions[$pluggable_class] = $this->get_version();
Options::set( 'pluggable_versions', $versions );
}
}
else {
$versions[$pluggable_class] = $this->get_version();
Options::set( 'pluggable_versions', $versions );
}
}
}
}
?>
Jump to Line
Something went wrong with that request. Please try again.