------------------------------------------------------------
revno: 896
committer: Roger Martin <[email protected]>
branch nick: aikiframework
timestamp: Wed 2011-09-21 22:56:48 +0200
message:
plugins core added
added:
src/libs/plugins.php
modified:
src/bootstrap.php
src/libs/aiki.php
src/libs/output.php
src/sql/CreateTables.sql
--
lp:aikiframework
https://code.launchpad.net/~aikiframework-devel/aikiframework/trunk
Your team Aiki Framework Developers is subscribed to branch lp:aikiframework.
To unsubscribe from this branch go to
https://code.launchpad.net/~aikiframework-devel/aikiframework/trunk/+edit-subscription
=== modified file 'src/bootstrap.php'
--- src/bootstrap.php 2011-09-16 20:16:12 +0000
+++ src/bootstrap.php 2011-09-21 20:56:48 +0000
@@ -140,7 +140,7 @@
*/
$aiki->load('url');
-$aiki->load("site");
+$aiki->load('site');
$membership = $aiki->load("membership");
$aiki->load("languages");
@@ -166,3 +166,5 @@
$aiki->load("view_parser");
$aiki->load("image");
$aiki->load("errors");
+
+$aiki->load("plugins");
=== modified file 'src/libs/aiki.php'
--- src/libs/aiki.php 2011-09-16 20:16:12 +0000
+++ src/libs/aiki.php 2011-09-21 20:56:48 +0000
@@ -184,7 +184,7 @@
* @return boolean
*/
- function match_pair( $condition,$first, $second) {
+ function match_pair( $condition,$first, $second="*", $third ="*") {
//clean conditions,
$condition= strtr(
$condition,
@@ -197,9 +197,10 @@
$matches = explode (" ",$condition);
foreach ( $matches as $match) {
- $pair = explode("/", $match,2);
- if ( $this->match_pair_one($pair[0],$first ) &&
- ( !isset($pair[1]) || $this->match_pair_one($pair[1],$second) ) ){
+ $pair = explode("/", $match,3)+ array("*","*","*");
+ if ( $this->match_pair_one($pair[0],$first) &&
+ $this->match_pair_one($pair[1],$second) &&
+ $this->match_pair_one($pair[2],$third) ) {
return true;
}
}
=== modified file 'src/libs/output.php'
--- src/libs/output.php 2011-09-16 20:16:12 +0000
+++ src/libs/output.php 2011-09-21 20:56:48 +0000
@@ -84,6 +84,7 @@
<meta name="generator" content="Aikiframework '.
AIKI_VERSION.'.'.AIKI_REVISION.'" />
';
+
return $header;
}
@@ -186,8 +187,10 @@
*
*/
public function footer()
- {
- return "\n</body>\n</html>";
+ { global $aiki;
+ $footer = "\n</body>\n</html>";
+ $aiki->plugins->do_action("output_html", &$footer);
+ return $footer;
}
=== added file 'src/libs/plugins.php'
--- src/libs/plugins.php 1970-01-01 00:00:00 +0000
+++ src/libs/plugins.php 2011-09-21 20:56:48 +0000
@@ -0,0 +1,343 @@
+<?php
+
+/**
+ * Aiki Framework (PHP)
+ *
+ * LICENSE
+ *
+ * This source file is subject to the AGPL-3.0 license that is bundled
+ * with this package in the file LICENSE.
+ *
+ * @author Roger martin - Aikilab http://www.aikilab.com
+ * @copyright (c) 2008-2011 Aiki Lab Pte Ltd
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html
+ * @link http://www.aikiframework.org
+ * @category Aiki
+ * @package Library
+ * @filesource
+ *
+ * A class plugin class for aiki. Based in wordpress plugin systems.
+ *
+ */
+
+
+
+
+/**
+ * Plugins class
+ * A store of plugins. Plugins loads all active plugins, loads actions
+ *
+ * Actions is stored in 'three-dimensional' array:
+ * - $actions[action] is array of priorities for a given action.
+ * Before calling plugins, the class checks if priorities are sorted.
+ * - $action[action][priority] is a array containing references to plugin
+ * that must be called.
+ *
+ */
+
+define ("AIKI_PLUGIN_DIR","plugins");
+
+class plugins {
+
+ private $plugins;
+ private $actions, $must_sorted;
+
+ function __construct(){
+ global $aiki, $db;
+ global $AIKI_ROOT_DIR;
+
+ $this->plugins = array();
+ $this->actions = array();
+ $this->must_sorted= array();
+
+ // read active plugins configuration
+ $site = $aiki->site->get_site();
+ $view = $aiki->site->view();
+ $language= $aiki->site->language();
+ $sql = "SELECT plconf_routes, plconf_values, plconf_plugin_id".
+ " FROM aiki_plugin_configurations".
+ " WHERE plconf_active='active'".
+ " ORDER BY plconf_priority";
+ $configurations = $db->get_results($sql);
+ if ( is_null($configurations) ) {
+ return;
+ }
+
+ // select plugins that match site/view/language
+ $pluginsActivated= array();
+ foreach ( $configurations as $configuration ){
+ if ( !isset($pluginsActivated[$configuration->plconf_plugin_id]) &&
+ $aiki->match_pair( $configuration->plconf_routes,
+ $site, $view, $language) ){
+ // is active plugins
+ $pluginsActivated[$configuration->plconf_plugin_id] = $configuration->plconf_values;
+ }
+ }
+
+ // init plugins: set action and load configuration
+ if ( count($pluginsActivated)>0 ){
+ $sql = "SELECT plugin_id, plugin_file,plugin_class_name FROM aiki_plugins ".
+ " WHERE plugin_state='available' AND (plugin_id='". implode("OR plugin_id='", array_keys($pluginsActivated)). "')";
+ $toload= $db->get_results($sql);
+ if ( !is_null( $toload ) ) {
+ foreach ($toload as $load){
+ $file= $AIKI_ROOT_DIR ."/". AIKI_PLUGIN_DIR. "/". $load->plugin_file ;
+ if ( file_exists ($file) ){
+ include_once($file);
+ $this->plugins[]= new $load->plugin_class_name($this, $pluginsActivated[ $load->plugin_id]) ;
+ } else {
+ // @todo conditional warning when file not exist.
+ $aiki->message->error("<br>Can't load plugin:". $file, NULL, false);
+ // deactive plugins.
+ // @todo warning to system adminstrator?
+ $db->query("UPDATE plugin_state='missing' WHERE plugin_id='" .$load->plugin_id."'");
+ }
+ }
+ }
+ $pluginsActivated="";
+ }
+
+ } // end of constructor
+
+ /**
+ * Add a action to aiki
+ *
+ * @param string $action
+ * @param object $callback. A reference to plugin objetc
+ * @param optional integer $priority
+ */
+
+ function add_action( $action, $callback, $priority=999){
+ $this->actions[$action][$priority][]= $callback;
+ $this->must_sorted[$action]= true;
+ }
+
+ /**
+ * call all plugin that are attached to action
+ *
+ * @param string $action
+ * @param byref $string
+ */
+
+ function do_action( $action, &$text ){
+
+ if ( !isset($this->actions[$action]) ){
+ return 0;
+ }
+
+ // if needed sorts callback by prioty
+ if ($this->must_sorted[$action]){
+ asort($this->actions[$action]);
+ $this->must_sorted[$action]= false;
+ }
+
+ $i=0;
+ // call plugin
+ foreach ( $this->actions[$action] as $priority => $callbacks){
+ foreach ( $callbacks as $callback ){
+ $callback->action($action,$text);
+ $i++;
+ }
+ }
+ return $i;
+ }
+
+
+ /**
+ * Extract a field (text like FIELD: ... from a given text)
+ *
+ * @param string $field Field to extract, without ":".
+ * @param string $text Text to parse.
+ */
+
+ static private function extract_field($field, $text){
+ $matches="";
+ $pattern= "#^[ ]*\*[ ]+".preg_quote($field). "\:(.*)#im";
+ if (preg_match($pattern, $text, $matches) ){
+ return $matches[1];
+ }
+ return false;
+ }
+
+
+ static private function data(&$data,$field){
+ if ( isset($data[$field]) ) {
+ return "'". addslashes($data[$field]) ."'";
+ }
+ return "''";
+ }
+
+
+ /**
+ * Save and activate a plugin for given route.
+ *
+ * @param array $founded Founded plugins
+ * @retun integer $number of inserted plugins
+ */
+
+ static function insert_plugin_configuration ($plugin_id, $route, $priority=999, $vars=array() ){
+ global $db;
+ $sql= "INSERT INTO aiki_plugin_configurations".
+ " (plconf_plugin_id, plconf_routes, plconf_priority, plconf_values, plconf_active)".
+ " VALUES ({$plugin_id},'{$route}', '{$priority}','". addslashes(serialize($vars))."','active')";
+ echo "insertando:",$sql,"<br>";
+
+ $db->query($sql);
+
+ }
+
+
+ /**
+ * Update aiki_plug with new plugins
+ *
+ * @param array $founded Founded plugins
+ * @retun integer $number of inserted plugins
+ */
+
+ static function available_plugins( $founded){
+ global $db;
+ if ( !is_array($founded) || count($founded)==0 ){
+ return 0;
+ }
+ $inserted=0;
+ // note than in case that plugin is in $founded, it will be re-available
+ $db->query("UPDATE aiki_plug SET plugin_state='missing' WHERE plugin_state='available'");
+ foreach ( $founded as $file=>$data){
+ $id= $db->get_row(
+ "SELECT plugin_id, plugin_state FROM aiki_plugins".
+ " WHERE plugin_file='" .addslashes($file). "'");
+ if ( !is_null($id) ) {
+ // update plugin if found
+ $set= ( $id->plugin_state=="missing" ? "plugin_state='available',":"").
+ "plugin_class_name='{$data['class_name']}',".
+ "plugin_name=" .plugins::data( $data,"name") .",".
+ "plugin_version=".plugins::data( $data,"version") .",".
+ "plugin_author=" .plugins::data( $data,"author") .",".
+ "plugin_short_description=". plugins::data( $data,"description") ;
+ $db->query ("UPDATE aiki_plugins SET $set WHERE plugin_id='".$id->plugin_id ."'");
+
+ } else {
+ // insert a new plugin
+ $values= "'$file',".
+ plugins::data( $data,"name") .",".
+ plugins::data ($data,"class_name") .",".
+ plugins::data( $data,"version") .",".
+ plugins::data( $data,"author") .",".
+ plugins::data( $data,"description") .",".
+ "'available'";
+ $db->query ("INSERT INTO aiki_plugins ".
+ "(plugin_file,plugin_name,plugin_class_name,plugin_version, plugin_author,plugin_short_description, plugin_state)".
+ " VALUES ( $values )" );
+ $inserted++;
+ }
+ }
+ return $inserted;
+ }
+
+
+
+ /**
+ * Search a directory (and subdirectories) for plugin
+ *
+ * @param $dir directory to search.
+ * @retun $array of all plugins
+ */
+
+ static function search_plugins( $dir="."){
+ $founded= false;
+
+ // search php files that contains /* This is a aiki plugin
+ // and extract information
+ foreach ( glob("$dir/*.php") as $file){
+ $file_content = file_get_contents($file);
+ $start = stripos($file_content,"* This is a aiki plugin:");
+ if ($start && preg_match( "/class ([a-z_0-9]+) extends plugin \{/i", $file_content, $temp_match) ) {
+ $file = preg_replace( "~^". preg_quote(AIKI_PLUGIN_DIR . "/" ). "~","",$file);
+ $founded[$file]['class_name']= $temp_match[1];
+ $end = stripos ($file_content, "*/",$start);
+ $information= substr($file_content, $start, $end - $start );
+ $file_content=""; // clear buffer
+ $search_for = array("author","version","description","name");
+ foreach ($search_for as $search){
+ $field = plugins::extract_field($search,$information);
+ if ($field) {
+ $founded[$file][$search]=$field;
+ }
+ }
+ }
+ }
+ // now search subdirectories
+ foreach ( glob("$dir/*", GLOB_ONLYDIR) as $directory ){
+ $new = $this->search_plugins($directory);
+ if ( $new ){
+ if ($founded) {
+ $founded = $founded+ $new;
+ } else {
+ $founded = $new;
+ }
+ }
+ }
+ return $founded;
+ }
+
+
+}
+
+
+/**
+ * Abstract class to implements plugins
+ *
+ * You need declare a las class :
+ * class MyPluginName extends plugin { ..here code }
+ *
+ * The code must contain the two functions:
+ * - set_actions that must return a array of actions=>priorities
+ * - do_action that receive two parameters action and &text ..
+ *
+ * You must not:
+ * - create a plugin object.
+ * - declare a constructor in class.
+ *
+ */
+
+
+abstract class plugin {
+ protected $plugins;
+ protected $parameters;
+
+ function __construct($pluginStore, $serializedParameters=""){
+ global $aiki, $db;
+ $this->plugins= $pluginStore;
+ $this->parameters = array();
+
+ // set actions
+ foreach ($this->set_actions() as $key=>$value ){
+ if ( is_numeric($key) ){
+ $this->plugins->add_action($value, &$this) ;
+ } else {
+ $this->plugins->add_action($key, &$this ,$value) ;
+ }
+ }
+ // read configuration
+ if ( $serializedParameters!="" &&
+ preg_match('~^a:[1-9]+[0-0]*:\{~',$serializedParameters) ){ //is array ? a:99:{...
+ $this->parameters = unserialize($serializedParameters);
+ }
+
+ if ( method_exists( $this,"onload") ){
+ $this->onload();
+ }
+
+ }
+
+ function get($parameter) {
+ if ( isset($this->parameters[$parameter]) ){
+ return $this->parameters[$parameter];
+ }
+ return NULL;
+ }
+
+ abstract function set_actions();
+ abstract function action($action, &$text);
+
+}
=== modified file 'src/sql/CreateTables.sql'
--- src/sql/CreateTables.sql 2011-09-16 20:16:12 +0000
+++ src/sql/CreateTables.sql 2011-09-21 20:56:48 +0000
@@ -156,6 +156,35 @@
-- ------------------------------------------------------
+CREATE TABLE IF NOT EXISTS `aiki_plugins` (
+ `plugin_id` int(11) NOT NULL AUTO_INCREMENT,
+ `plugin_name` varchar(64) NOT NULL,
+ `plugin_class_name` varchar(64) NOT NULL,
+ `plugin_short_description` text NOT NULL,
+ `plugin_description` text NOT NULL,
+ `plugin_author` varchar(64) NOT NULL,
+ `plugin_version` varchar(32) NOT NULL,
+ `plugin_file` varchar(96) NOT NULL,
+ `plugin_state` varchar(12) NOT NULL,
+ `plugin_default_values` text NOT NULL,
+ PRIMARY KEY (`plugin_id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- ------------------------------------------------------
+
+CREATE TABLE IF NOT EXISTS `aiki_plugin_configurations` (
+ `plconf_id` int(11) NOT NULL AUTO_INCREMENT,
+ `plconf_active` varchar(11) NOT NULL,
+ `plconf_plugin_id` int(11) NOT NULL,
+ `plconf_routes` text NOT NULL,
+ `plconf_priority` int(11) NOT NULL,
+ `plconf_values` text NOT NULL,
+ PRIMARY KEY (`plconf_id`),
+ KEY `plconf_plugin_id` (`plconf_plugin_id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- ------------------------------------------------------
+
CREATE TABLE IF NOT EXISTS aiki_sites (
site_id int(11) NOT NULL AUTO_INCREMENT,
site_name varchar(255) NOT NULL,
_______________________________________________
Mailing list: https://launchpad.net/~aikiframework-devel
Post to : [email protected]
Unsubscribe : https://launchpad.net/~aikiframework-devel
More help : https://help.launchpad.net/ListHelp