3 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
\r
4 * Copyright (C) 2002-2009 The Nucleus Group
\r
6 * This program is free software; you can redistribute it and/or
\r
7 * modify it under the terms of the GNU General Public License
\r
8 * as published by the Free Software Foundation; either version 2
\r
9 * of the License, or (at your option) any later version.
\r
10 * (see nucleus/documentation/index.html#license for more info)
\r
13 * This is an (abstract) class of which all Nucleus Plugins must inherit
\r
15 * for more information on plugins and how to write your own, see the
\r
16 * plugins.html file that is included with the Nucleus documenation
\r
18 * @license http://nucleuscms.org/license.txt GNU General Public License
\r
19 * @copyright Copyright (C) 2002-2009 The Nucleus Group
\r
20 * @version $Id: PLUGIN.php 1630 2012-01-28 12:16:14Z sakamocchi $
\r
22 abstract class NucleusPlugin
\r
24 // these public functions should to be redefined in your plugin
\r
25 public function getName()
\r
30 public function getAuthor()
\r
35 public function getURL()
\r
40 public function getVersion()
\r
45 public function getDescription()
\r
50 // these final public function _may_ be redefined in your plugin
\r
52 public function getMinNucleusVersion()
\r
57 public function getMinNucleusPatchLevel()
\r
62 public function getEventList()
\r
67 public function getTableList()
\r
72 public function hasAdminArea()
\r
77 public function install()
\r
82 public function unInstall()
\r
87 public function init()
\r
92 public function doSkinVar($skinType)
\r
97 public function doTemplateVar(&$item)
\r
99 $args = func_get_args();
\r
100 array_shift($args);
\r
101 array_unshift($args, 'template');
\r
102 call_user_func_array(array(&$this,'doSkinVar'),$args);
\r
106 public function doTemplateCommentsVar(&$item, &$comment)
\r
108 $args = func_get_args();
\r
109 array_shift($args);
\r
110 array_shift($args);
\r
111 array_unshift($args, 'template');
\r
112 call_user_func_array(array(&$this,'doSkinVar'),$args);
\r
116 public function doAction($type)
\r
118 return _ERROR_PLUGIN_NOSUCHACTION;
\r
121 public function doIf($key,$value)
\r
126 public function doItemVar (&$item)
\r
132 * Checks if a plugin supports a certain feature.
\r
134 * @returns 1 if the feature is reported, 0 if not
\r
136 * Name of the feature. See plugin documentation for more info
\r
137 * 'SqlTablePrefix' -> if the plugin uses the sql_table() method to get table names
\r
138 * 'HelpPage' -> if the plugin provides a helppage
\r
139 * 'SqlApi' -> if the plugin uses the complete sql_* api (must also require nucleuscms 3.5)
\r
141 public function supportsFeature($feature)
\r
147 * Report a list of plugin that is required to final public function
\r
149 * @returns an array of names of plugin, an empty array indicates no dependency
\r
151 public function getPluginDep()
\r
156 // these helper final public functions should not be redefined in your plugin
\r
159 * Creates a new option for this plugin
\r
162 * A string uniquely identifying your option. (max. length is 20 characters)
\r
163 * @param description
\r
164 * A description that will show up in the nucleus admin area (max. length: 255 characters)
\r
166 * Either 'text', 'yesno' or 'password'
\r
167 * This info is used when showing 'edit plugin options' screens
\r
169 * Initial value for the option (max. value length is 128 characters)
\r
171 final public function createOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
173 return $this->create_option('global', $name, $desc, $type, $defValue, $typeExtras);
\r
176 final public function createBlogOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
178 return $this->create_option('blog', $name, $desc, $type, $defValue, $typeExtras);
\r
181 final public function createMemberOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
183 return $this->create_option('member', $name, $desc, $type, $defValue, $typeExtras);
\r
186 final public function createCategoryOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
188 return $this->create_option('category', $name, $desc, $type, $defValue, $typeExtras);
\r
191 final public function createItemOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
193 return $this->create_option('item', $name, $desc, $type, $defValue, $typeExtras);
\r
197 * Removes the option from the database
\r
199 * Note: Options get erased automatically on plugin uninstall
\r
201 final public function deleteOption($name)
\r
203 return $this->delete_option('global', $name);
\r
206 final public function deleteBlogOption($name)
\r
208 return $this->delete_option('blog', $name);
\r
211 final public function deleteMemberOption($name)
\r
213 return $this->delete_option('member', $name);
\r
216 final public function deleteCategoryOption($name)
\r
218 return $this->delete_option('category', $name);
\r
221 final public function deleteItemOption($name)
\r
223 return $this->delete_option('item', $name);
\r
227 * Sets the value of an option to something new
\r
229 final public function setOption($name, $value)
\r
231 return $this->set_option('global', 0, $name, $value);
\r
234 final public function setBlogOption($blogid, $name, $value)
\r
236 return $this->set_option('blog', $blogid, $name, $value);
\r
239 final public function setMemberOption($memberid, $name, $value)
\r
241 return $this->set_option('member', $memberid, $name, $value);
\r
244 final public function setCategoryOption($catid, $name, $value)
\r
246 return $this->set_option('category', $catid, $name, $value);
\r
249 final public function setItemOption($itemid, $name, $value) {
\r
250 return $this->set_option('item', $itemid, $name, $value);
\r
254 * Retrieves the current value for an option
\r
256 final public function getOption($name)
\r
258 // only request the options the very first time. On subsequent requests
\r
259 // the static collection is used to save SQL queries.
\r
260 if ( $this->plugin_options == 0 )
\r
262 $this->plugin_options = array();
\r
264 $query = "SELECT d.oname as name, o.ovalue as value FROM %s o, %s d WHERE d.opid=%d AND d.oid=o.oid;";
\r
265 $query = sprintf($query, sql_table('plugin_option'), sql_table('plugin_option_desc'), (integer) $this->plugid);
\r
266 $result = sql_query($query);
\r
267 while ( $row = sql_fetch_object($result) )
\r
269 $this->plugin_options[strtolower($row->name)] = $row->value;
\r
272 if ( isset($this->plugin_options[strtolower($name)]) )
\r
274 return $this->plugin_options[strtolower($name)];
\r
278 return $this->get_option('global', 0, $name);
\r
282 final public function getBlogOption($blogid, $name)
\r
284 return $this->get_option('blog', $blogid, $name);
\r
287 final public function getMemberOption($memberid, $name)
\r
289 return $this->get_option('member', $memberid, $name);
\r
292 final public function getCategoryOption($catid, $name)
\r
294 return $this->get_option('category', $catid, $name);
\r
297 final public function getItemOption($itemid, $name)
\r
299 return $this->get_option('item', $itemid, $name);
\r
303 * Retrieves an associative array with the option value for each
\r
306 final public function getAllBlogOptions($name)
\r
308 return $this->get_all_options('blog', $name);
\r
311 final public function getAllMemberOptions($name)
\r
313 return $this->get_all_options('member', $name);
\r
316 final public function getAllCategoryOptions($name)
\r
318 return $this->get_all_options('category', $name);
\r
321 final public function getAllItemOptions($name)
\r
323 return $this->get_all_options('item', $name);
\r
327 * Retrieves an indexed array with the top (or bottom) of an option
\r
328 * (delegates to getOptionTop())
\r
330 final public function getBlogOptionTop($name, $amount = 10, $sort = 'desc')
\r
332 return $this->get_option_top('blog', $name, $amount, $sort);
\r
335 final public function getMemberOptionTop($name, $amount = 10, $sort = 'desc')
\r
337 return $this->get_option_top('member', $name, $amount, $sort);
\r
340 final public function getCategoryOptionTop($name, $amount = 10, $sort = 'desc')
\r
342 return $this->get_option_top('category', $name, $amount, $sort);
\r
345 final public function getItemOptionTop($name, $amount = 10, $sort = 'desc')
\r
347 return $this->get_option_top('item', $name, $amount, $sort);
\r
351 * NucleusPlugin::getID()
\r
352 * get id for this plugin
\r
356 * @return integer this plugid id
\r
358 final public function getID()
\r
360 return (integer) $this->plugid;
\r
364 * NucleusPlugin::setID()
\r
365 * set favorite id for this plugin
\r
368 * @param integer $plugid favorite id for plugin
\r
371 final public function setID($plugid)
\r
373 $this->plugid = (integer) $plugid;
\r
378 * Returns the URL of the admin area for this plugin (in case there's
\r
379 * no such area, the returned information is invalid)
\r
383 final public function getAdminURL()
\r
386 return $CONF['PluginURL'] . $this->getShortName() . '/';
\r
390 * Returns the directory where the admin directory is located and
\r
391 * where the plugin can maintain his extra files
\r
395 final public function getDirectory()
\r
397 global $DIR_PLUGINS;
\r
398 return $DIR_PLUGINS . $this->getShortName() . '/';
\r
402 * Derives the short name for the plugin from the classname (all
\r
407 final public function getShortName()
\r
409 return str_replace('np_','',strtolower(get_class($this)));
\r
413 * Clears the option value cache which saves the option values during
\r
414 * the plugin execution. This function is usefull if the options has
\r
415 * changed during the plugin execution (especially in association with
\r
416 * the PrePluginOptionsUpdate and the PostPluginOptionsUpdate events)
\r
420 final public function clearOptionValueCache()
\r
422 $this->option_values = array();
\r
423 $this->plugin_options = 0;
\r
427 // internal functions of the class starts here
\r
428 protected $option_values; // oid_contextid => value
\r
429 protected $option_info; // context_name => array('oid' => ..., 'default' => ...)
\r
430 protected $plugin_options; // see getOption()
\r
431 protected $plugid; // plugin id
\r
434 * Class constructor: Initializes some internal data
\r
436 public function __construct()
\r
438 $this->option_values = array(); // oid_contextid => value
\r
439 $this->option_info = array(); // context_name => array('oid' => ..., 'default' => ...)
\r
440 $this->plugin_options = 0;
\r
444 * Retrieves an array of the top (or bottom) of an option from a plugin.
\r
446 * @param string $context the context for the option: item, blog, member,...
\r
447 * @param string $name the name of the option
\r
448 * @param int $amount how many rows must be returned
\r
449 * @param string $sort desc or asc
\r
450 * @return array array with both values and contextid's
\r
453 final protected function get_option_top($context, $name, $amount = 10, $sort = 'desc')
\r
455 if ( ($sort != 'desc') && ($sort != 'asc') )
\r
460 $oid = $this->get_option_id($context, $name);
\r
462 // retrieve the data and return
\r
463 $query = "SELECT otype, oextra FROM %s WHERE oid = %d;";
\r
464 $query = sprintf($query, sql_table('plugin_option_desc'), $oid);
\r
465 $result = sql_query($query);
\r
467 $o = sql_fetch_array($result);
\r
469 if ( ($this->optionCanBeNumeric($o['otype'])) && ($o['oextra'] == 'number' ) )
\r
471 $orderby = 'CAST(ovalue AS SIGNED)';
\r
475 $orderby = 'ovalue';
\r
477 $query = "SELECT ovalue value, ocontextid id FROM %s WHERE oid = %d ORDER BY %s %s LIMIT 0,%d;";
\r
478 $query = sprintf($query, sql_table('plugin_option'), $oid, $orderby, $sort, (integer) $amount);
\r
479 $result = sql_query($query);
\r
481 // create the array
\r
484 while( $row = sql_fetch_array($result) )
\r
489 // return the array (duh!)
\r
494 * Creates an option in the database table plugin_option_desc
\r
498 final protected function create_option($context, $name, $desc, $type, $defValue, $typeExtras = '')
\r
500 // create in plugin_option_desc
\r
501 $query = 'INSERT INTO ' . sql_table('plugin_option_desc')
\r
502 .' (opid, oname, ocontext, odesc, otype, odef, oextra)'
\r
503 .' VALUES ('.intval($this->plugid)
\r
504 .', \''.sql_real_escape_string($name).'\''
\r
505 .', \''.sql_real_escape_string($context).'\''
\r
506 .', \''.sql_real_escape_string($desc).'\''
\r
507 .', \''.sql_real_escape_string($type).'\''
\r
508 .', \''.sql_real_escape_string($defValue).'\''
\r
509 .', \''.sql_real_escape_string($typeExtras).'\');';
\r
511 $oid = sql_insert_id();
\r
513 $key = $context . '_' . $name;
\r
514 $this->option_info[$key] = array('oid' => $oid, 'default' => $defValue);
\r
519 * Deletes an option from the database tables
\r
520 * plugin_option and plugin_option_desc
\r
524 final protected function delete_option($context, $name)
\r
526 $oid = $this->get_option_id($context, $name);
\r
529 return 0; // no such option
\r
532 // delete all things from plugin_option
\r
533 $query = "DELETE FROM %s WHERE oid=%d;";
\r
534 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid);
\r
537 // delete entry from plugin_option_desc
\r
538 $query = "DELETE FROM %s WHERE oid=%d;";
\r
539 $query = sprintf($query, sql_table('plugin_option_desc'), $oid);
\r
542 // clear from cache
\r
543 unset($this->option_info["{$context}_{$name}"]);
\r
544 $this->option_values = array();
\r
549 * Update an option in the database table plugin_option
\r
551 * returns: 1 on success, 0 on failure
\r
554 final protected function set_option($context, $contextid, $name, $value)
\r
558 $oid = $this->get_option_id($context, $name);
\r
564 // check if context id exists
\r
565 switch ( $context )
\r
568 if ( !MEMBER::existsID($contextid) )
\r
574 if ( !$manager->existsBlogID($contextid) )
\r
580 if ( !$manager->existsCategory($contextid) )
\r
586 if ( !$manager->existsItem($contextid, true, true) )
\r
592 if ( $contextid != 0 )
\r
599 // update plugin_option
\r
600 $query = "DELETE FROM %s WHERE oid=%d and ocontextid=%d;";
\r
601 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid);
\r
604 $query = "INSERT INTO %s (ovalue, oid, ocontextid) VALUES ('%s', %d, %d);";
\r
605 $query = sprintf($query, sql_table('plugin_option'), sql_real_escape_string($value), $oid, $contextid);
\r
609 $this->option_values["{$oid}_{$contextid}"] = $value;
\r
610 if ( $context == 'global' )
\r
612 $this->plugin_options[strtolower($name)] = $value;
\r
619 * Get an option from Cache or database
\r
620 * - if not in the option Cache read it from the database
\r
621 * - if not in the database write default values into the database
\r
625 final protected function get_option($context, $contextid, $name)
\r
627 $oid = $this->get_option_id($context, $name);
\r
633 $key = "{$oid}_{$contextid}";
\r
635 if ( isset($this->option_values[$key]) )
\r
637 return $this->option_values[$key];
\r
641 $query = "SELECT ovalue FROM %s WHERE oid=%d and ocontextid=%d;";
\r
642 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid);
\r
643 $result = sql_query($query);
\r
645 if ( !$result || (sql_num_rows($result) == 0) )
\r
647 // fill DB with default value
\r
648 $this->option_values[$key] = $this->get_default_value($context, $name);
\r
649 $query = "INSERT INTO %s (oid, ocontextid, ovalue) VALUES (%d, %d, '%s');";
\r
650 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid, sql_real_escape_string($defVal));
\r
655 $o = sql_fetch_object($result);
\r
656 $this->option_values[$key] = $o->ovalue;
\r
659 return $this->option_values[$key];
\r
663 * Returns assoc array with all values for a given option
\r
664 * (one option per possible context id)
\r
668 final protected function get_all_options($context, $name)
\r
670 $oid = $this->get_option_id($context, $name);
\r
675 $default_value = $this->get_default_value($context, $name);
\r
677 $options = array();
\r
678 $query = "SELECT %s as contextid FROM %s;";
\r
679 switch ( $context )
\r
682 $query = sprintf($query, 'bnumber', sql_table('blog'));
\r
685 $query = sprintf($query, 'catid', sql_table('category'));
\r
688 $query = sprintf($query, 'mnumber', sql_table('member'));
\r
691 $query = sprintf($query, 'inumber', sql_table('item'));
\r
695 $result = sql_query($query);
\r
698 while ( $o = sql_fetch_object($r) )
\r
700 $options[$o->contextid] = $default_value;
\r
704 $query = "SELECT ocontextid, ovalue FROM %s WHERE oid=%d;";
\r
705 $query = sprintf($query, sql_table('plugin_option'), $oid);
\r
706 $result = sql_query($query);
\r
707 while ( $o = sql_fetch_object($result) )
\r
709 $options[$o->ocontextid] = $o->ovalue;
\r
716 * NucleusPlugin::get_option_id
\r
718 * Gets the 'option identifier' that corresponds to a given option name.
\r
719 * When this method is called for the first time, all the OIDs for the plugin
\r
720 * are loaded into memory, to avoid re-doing the same query all over.
\r
722 * @param string $context option context
\r
723 * @param string $name plugin name
\r
724 * @return integer option id
\r
726 final protected function get_option_id($context, $name)
\r
728 $key = "{$context}_{$name}";
\r
730 if ( array_key_exists($key, $this->option_info)
\r
731 && array_key_exists('oid', $this->option_info[$key]) )
\r
733 return $this->option_info[$key]['oid'];
\r
736 // load all OIDs for this plugin from the database
\r
737 $this->option_info = array();
\r
738 $query = "SELECT oid, oname, ocontext, odef FROM %s WHERE opid=%d;";
\r
739 $query = sprintf($query, sql_table('plugin_option_desc'), $this->plugid);
\r
740 $result = sql_query($query);
\r
741 while ( $o = sql_fetch_object($result) )
\r
743 $k = $o->ocontext . '_' . $o->oname;
\r
744 $this->option_info[$k] = array('oid' => $o->oid, 'default' => $o->odef);
\r
746 sql_free_result($result);
\r
748 return $this->option_info[$key]['oid'];
\r
750 final protected function get_default_value($context, $name)
\r
752 $key = $context . '_' . $name;
\r
754 if ( array_key_exists($key, $this->option_info)
\r
755 && array_key_exists('default', $this->option_info[$key]) )
\r
757 return $this->option_info[$key]['default'];
\r
763 * NucleusPlugin::delete_option_values()
\r
764 * Deletes all option values for a given context and contextid
\r
765 * (used when e.g. a blog, member or category is deleted)
\r
768 *@param String $context global/blog/category/item/member
\r
769 *@param Integer $contextid ID
\r
772 static public function delete_option_values($context, $contextid)
\r
774 // delete all associated plugin options
\r
777 $query = "SELECT oid FROM %s WHERE ocontext='%s';";
\r
778 $query = sprintf($query, sql_table('plugin_option_desc'), sql_real_escape_string($context));
\r
780 $result = sql_query($query);
\r
781 while ( $o = sql_fetch_object($result) )
\r
783 array_push($aOIDs, $o->oid);
\r
785 sql_free_result($result);
\r
786 // delete those options. go go go
\r
787 if ( count($aOIDs) > 0 )
\r
789 $query = "DELETE FROM %s WHERE oid in (%s) and ocontextid=%d;";
\r
790 $query = sprintf($query, sql_table('plugin_option'), implode(',',$aOIDs), (integer) $contextid);
\r
797 * NucleusPlugin::getOptionMeta()
\r
798 * splits the option's typeextra field (at ;'s) to split the meta collection
\r
801 * @param string $typeExtra the value of the typeExtra field of an option
\r
802 * @return array array of the meta-key/value-pairs
\r
804 static public function getOptionMeta($typeExtra)
\r
808 /* 1. if $typeExtra includes delimiter ';', split it to tokens */
\r
809 $tokens = i18n::explode(';', $typeExtra);
\r
812 * 2. if each of tokens includes "=", it consists of key => value
\r
813 * else it's 'select' option
\r
815 foreach ( $tokens as $token )
\r
817 $matches = array();
\r
818 if ( preg_match("#^([^=]+)?=([^=]+)?$#", $token, $matches) )
\r
820 $meta[$matches[1]] = $matches[2];
\r
824 $meta['select'] = $token;
\r
831 * NucleusPlugin::getOptionSelectValues()
\r
832 * filters the selectlists out of the meta collection
\r
835 * @param string $typeExtra the value of the typeExtra field of an option
\r
836 * @return string the selectlist
\r
838 static public function getOptionSelectValues($typeExtra)
\r
840 $meta = NucleusPlugin::getOptionMeta($typeExtra);
\r
842 if ( array_key_exists('select', $meta) )
\r
844 return $meta['select'];
\r
850 * checks if the eventlist in the database is up-to-date
\r
851 * @return bool if it is up-to-date it return true, else false
\r
854 public function subscribtionListIsUptodate()
\r
856 $res = sql_query('SELECT event FROM '.sql_table('plugin_event').' WHERE pid = '.$this->plugid);
\r
858 while( $a = sql_fetch_array($res) )
\r
860 array_push($ev, $a['event']);
\r
862 if ( count($ev) != count($this->getEventList()) )
\r
866 $d = array_diff($ev, $this->getEventList());
\r
867 if ( count($d) > 0 )
\r
869 // there are differences so the db is not up-to-date
\r
876 * NucleusPlugin::apply_plugin_options()
\r
877 * Update its entry in database table
\r
880 * @param $options: array ( 'oid' => array( 'contextid' => 'value'))
\r
881 * (taken from request using requestVar())
\r
882 * @param $new_contextid: integer (accepts a contextid when it is for a new
\r
883 * contextid there was no id available at the moment of writing the
\r
884 * formcontrols into the page (by ex: itemOptions for new item)
\r
887 static public function apply_plugin_options(&$options, $new_contextid = 0)
\r
891 if ( !is_array($options) )
\r
896 foreach ( $options as $oid => $values )
\r
898 // get option type info
\r
899 $query = "SELECT opid, oname, ocontext, otype, oextra, odef FROM %s WHERE oid=%d;";
\r
900 $query = sprintf($query, sql_table('plugin_option_desc'), (integer) $oid);
\r
901 $result = sql_query($query);
\r
902 if ( $info = sql_fetch_object($result) )
\r
904 foreach ( $values as $id => $value )
\r
906 // decide wether we are using the contextid of newContextid
\r
907 if ( $new_contextid != 0 )
\r
909 $contextid = $new_contextid;
\r
916 // retreive any metadata
\r
917 $meta = NucleusPlugin::getOptionMeta($info->oextra);
\r
919 // if the option is readonly or hidden it may not be saved
\r
920 if ( array_key_exists('access', $meta)
\r
921 && in_array($meta['access'], array('readonly', 'hidden')) )
\r
926 // value comes from request
\r
927 $value = undoMagic($value);
\r
929 /* validation the value according to its type */
\r
930 switch ( $info->otype )
\r
933 if ( ($value != 'yes') && ($value != 'no') )
\r
940 if ( array_key_exists('datatype', $meta)
\r
941 && ($meta['datatype'] == 'numerical') && ($value != (integer) $value) )
\r
943 $value = (integer) $info->odef;
\r
953 * trigger event PrePluginOptionsUpdate to give the plugin the
\r
954 * possibility to change/validate the new value for the option
\r
957 'context' => $info->ocontext,
\r
958 'plugid' => $info->opid,
\r
959 'optionname' => $info->oname,
\r
960 'contextid' => $contextid,
\r
961 'value' => &$value);
\r
962 $manager->notify('PrePluginOptionsUpdate', $data);
\r
964 // delete and insert its fields of table in database
\r
965 $query = "DELETE FROM %s WHERE oid=%d AND ocontextid=%d;";
\r
966 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid);
\r
968 $query = "INSERT INTO %s (oid, ocontextid, ovalue) VALUES (%d, %d, '%s');";
\r
969 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid, sql_real_escape_string($value));
\r
973 // clear option value cache if the plugin object is already loaded
\r
974 if ( is_object($info) )
\r
976 $plugin=& $manager->pidLoaded($info->opid);
\r
979 $plugin->clearOptionValueCache();
\r