forked from sebsauvage/Shaarli
-
Notifications
You must be signed in to change notification settings - Fork 296
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
I retrieved @nodiscc plugin system proposed in #164 and changed it to create PHP plugin system. It relies on hooks triggered by certain actions (only template rendering for now). **It's only a proposition, let me know what you think of it**. * I think that an 'only template' plugin system might be too restrictive, and doesn't allow a lot of extension. * I raised concerns in #44 and don't blend too well with user made templates. * @nodiscc lacks of time to finish this. * I'd like to see 0.9beta release one day. :) PluginManager class includes enabled plugin PHP files at loading and register their hook function. When we want to trigger a hook, 'PluginManager::executeHooks()' is called, eventually with rendering data. It will call every plugin function registered under the standardized name: hook_<plugin_name>_<hook_name> Rendering data can be altered and/or completed. This is exactly what @nodiscc did. Templates contain plugin display at specific location, which are populated by the plugin functions. Here is what's has been done: * hook_render_linklist: when linklist is rendered, all links data passed to plugins. It allows plugins to alter link rendering (such as Markdown parsing). They can also add a linklist icon for every link (QRCode, etc.) * hook_render_header: every page builder triggers this hook. Plugins can add specific data to header if the current page is concerned (toolbar). * hook_render_footer: : every page builder triggers this hook. Plugins can add specific data to header if the current page is concerned (JS file). * hook_render_includes: : every page builder triggers this hook. Plugins can add specific data to header if the current page is concerned (CSS file). We can easily add hooks to whatever is pertinent (link add, picwal rendering, etc.). * Strong documentation, especially for plugin developers. * Unit tests for PluginManger and Router. * Test this heavily. Later: * finish Markdown plugin. * Add a plugin page in administration.
- Loading branch information
1 parent
874f858
commit 59ed397
Showing
5 changed files
with
306 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,3 +20,6 @@ composer.lock | |
coverage | ||
tests/datastore.php | ||
phpmd.html | ||
|
||
# Ignore user plugin configuration | ||
plugins/*/config.php |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<?php | ||
|
||
/** | ||
* Class PluginManager | ||
* | ||
* Use to manage, load and execute plugins. | ||
*/ | ||
class PluginManager | ||
{ | ||
/** | ||
* @var array - list of authorized plugins from configuration file. | ||
*/ | ||
public static $AUTHORIZED_PLUGINS = array(); | ||
|
||
/** | ||
* @var array - list of loaded plugins. | ||
*/ | ||
private static $_LOADED_PLUGINS = array(); | ||
|
||
/** | ||
* @var string - plugins subdirectory. | ||
*/ | ||
public static $PLUGINS_PATH = 'plugins'; | ||
|
||
/** | ||
* Load plugins listed in $AUTHORIZED_PLUGINS. | ||
*/ | ||
public static function load() { | ||
$dirs = glob(self::$PLUGINS_PATH . '/*' , GLOB_ONLYDIR); | ||
$dirnames = array_map('basename', $dirs); | ||
foreach (self::$AUTHORIZED_PLUGINS as $plugin) { | ||
$index = array_search($plugin, $dirnames); | ||
if ($index !== false) { | ||
try { | ||
self::loadPlugin($dirs[$index], $plugin); | ||
} | ||
catch (PluginFileNotFoundException $e) { | ||
error_log($e->getMessage()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Load a single plugin from its files. | ||
* Add them in $__LOADED_PLUGINS if successful. | ||
* | ||
* @param string $dir - plugin's directory. | ||
* @param string $pluginName - plugin's name. | ||
* @throws PluginFileNotFoundException - plugin files not found. | ||
*/ | ||
private static function loadPlugin($dir, $pluginName) { | ||
if (!is_dir($dir)) { | ||
throw new PluginFileNotFoundException($pluginName); | ||
} | ||
|
||
$pluginFilePath = $dir . '/' . $pluginName . '.php'; | ||
if (!is_file($pluginFilePath)) { | ||
throw new PluginFileNotFoundException($pluginName); | ||
} | ||
|
||
include $pluginFilePath; | ||
|
||
self::$_LOADED_PLUGINS[] = $pluginName; | ||
} | ||
|
||
/** | ||
* Execute all plugins registered hook. | ||
* | ||
* @param string $hook - name of the hook to trigger. | ||
* @param array $data - list of data to manipulate passed by reference. | ||
* @param array $params - additional parameters such as page target for common templates. | ||
*/ | ||
public static function executeHooks($hook, &$data, $params = array()) { | ||
if (!empty($params['target'])) { | ||
$data['_PAGE_'] = $params['target']; | ||
} | ||
|
||
if (isset($params['loggedin'])) { | ||
$data['_LOGGEDIN_'] = $params['loggedin']; | ||
} | ||
|
||
foreach (self::$_LOADED_PLUGINS as $plugin) { | ||
$hookFunction = self::buildHookName($hook, $plugin); | ||
|
||
if (function_exists($hookFunction)) { | ||
$data = call_user_func($hookFunction, $data); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Construct normalize hook name for a specific plugin. | ||
* | ||
* Format: | ||
* hook_<plugin_name>_<hook_name> | ||
* | ||
* @param $hook - hook name. | ||
* @param $pluginName - plugin name. | ||
* | ||
* @return string - plugin's hook name. | ||
*/ | ||
public static function buildHookName($hook, $pluginName) { | ||
return 'hook_' . $pluginName . '_' . $hook; | ||
} | ||
} | ||
|
||
/** | ||
* Class PluginFileNotFoundException | ||
* | ||
* Raise when plugin files can't be found. | ||
*/ | ||
class PluginFileNotFoundException extends Exception | ||
{ | ||
public function __construct($pluginName) { | ||
$this->message = 'Plugin "'. $pluginName .'" files not found.'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
|
||
/** | ||
* Class Router | ||
* | ||
* (only displayable pages here) | ||
*/ | ||
class Router { | ||
|
||
public static $PAGE_LOGIN = 'login'; | ||
|
||
public static $PAGE_PICWALL = 'picwall'; | ||
|
||
public static $PAGE_TAGCLOUD = 'tagcloud'; | ||
|
||
public static $PAGE_TOOLS = 'tools'; | ||
|
||
public static $PAGE_CHANGEPASSWORD = 'changepasswd'; | ||
|
||
public static $PAGE_CONFIGURE = 'configure'; | ||
|
||
public static $PAGE_CHANGETAG = 'changetag'; | ||
|
||
public static $PAGE_ADDLINK = 'addlink'; | ||
|
||
public static $PAGE_EDITLINK = 'edit_link'; | ||
|
||
public static $PAGE_EXPORT = 'export'; | ||
|
||
public static $PAGE_IMPORT = 'import'; | ||
|
||
public static $PAGE_LINKLIST = 'linklist'; | ||
|
||
/** | ||
* Reproducing renderPage() if hell, to avoid regression. | ||
* | ||
* | ||
* This highlights how bad this needs to be rewrite, | ||
* but let's focus on plugins for now. | ||
* | ||
* @param string $query $_SERVER['QUERY_STRING']. | ||
* @param array $get $_SERVER['GET']. | ||
* @param bool $loggedIn true if authenticated user. | ||
* | ||
* @return self::page found. | ||
*/ | ||
public static function findPage($query, $get, $loggedIn) { | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_LOGIN)) { | ||
return self::$PAGE_LOGIN; | ||
} | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_PICWALL)) { | ||
return self::$PAGE_PICWALL; | ||
} | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_TAGCLOUD)) { | ||
return self::$PAGE_TAGCLOUD; | ||
} | ||
|
||
// At this point, only loggedin pages. | ||
if (!$loggedIn) { | ||
return self::$PAGE_LINKLIST; | ||
} | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_TOOLS)) { | ||
return self::$PAGE_TOOLS; | ||
} | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_CHANGEPASSWORD)) { | ||
return self::$PAGE_CHANGEPASSWORD; | ||
} | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_CONFIGURE)) { | ||
return self::$PAGE_CONFIGURE; | ||
} | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_CHANGETAG)) { | ||
return self::$PAGE_CHANGETAG; | ||
} | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_ADDLINK)) { | ||
return self::$PAGE_ADDLINK; | ||
} | ||
|
||
if (isset($get['edit_link']) || isset($get['post'])) { | ||
return self::$PAGE_EDITLINK; | ||
} | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_EXPORT)) { | ||
return self::$PAGE_EXPORT; | ||
} | ||
|
||
if (isset($query) && startswith($query, 'do='. self::$PAGE_IMPORT)) { | ||
return self::$PAGE_IMPORT; | ||
} | ||
|
||
return self::$PAGE_LINKLIST; | ||
} | ||
} |
Oops, something went wrong.