4 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
\r
5 * Copyright (C) 2002-2012 The Nucleus Group
\r
7 * This program is free software; you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation; either version 2
\r
10 * of the License, or (at your option) any later version.
\r
11 * (see nucleus/documentation/index.html#license for more info)
\r
14 * This is an (abstract) class of which all Nucleus Plugins must inherit
\r
16 * for more information on plugins and how to write your own, see the
\r
17 * plugins.html file that is included with the Nucleus documenation
\r
19 * @license http://nucleuscms.org/license.txt GNU General Public License
\r
20 * @copyright Copyright (C) 2002-2012 The Nucleus Group
\r
21 * @version $Id: PLUGIN.php 1630 2012-01-28 12:16:14Z sakamocchi $
\r
23 abstract class NucleusPlugin
\r
25 // these public functions should to be redefined in your plugin
\r
26 public function getName()
\r
31 public function getAuthor()
\r
36 public function getURL()
\r
41 public function getVersion()
\r
46 public function getDescription()
\r
51 // these final public function _may_ be redefined in your plugin
\r
53 public function getMinNucleusVersion()
\r
58 public function getMinNucleusPatchLevel()
\r
63 public function getEventList()
\r
68 public function getTableList()
\r
73 public function hasAdminArea()
\r
78 public function install()
\r
83 public function unInstall()
\r
88 public function init()
\r
93 public function doSkinVar($skinType)
\r
98 public function doTemplateVar(&$item)
\r
100 $args = func_get_args();
\r
101 array_shift($args);
\r
102 array_unshift($args, 'template');
\r
103 call_user_func_array(array(&$this,'doSkinVar'),$args);
\r
107 public function doTemplateCommentsVar(&$item, &$comment)
\r
109 $args = func_get_args();
\r
110 array_shift($args);
\r
111 array_shift($args);
\r
112 array_unshift($args, 'template');
\r
113 call_user_func_array(array(&$this,'doSkinVar'),$args);
\r
117 public function doAction($type)
\r
119 return _ERROR_PLUGIN_NOSUCHACTION;
\r
122 public function doIf($key,$value)
\r
127 public function doItemVar (&$item)
\r
133 * Checks if a plugin supports a certain feature.
\r
135 * @returns 1 if the feature is reported, 0 if not
\r
137 * Name of the feature. See plugin documentation for more info
\r
138 * 'SqlTablePrefix' -> if the plugin uses the sql_table() method to get table names
\r
139 * 'HelpPage' -> if the plugin provides a helppage
\r
140 * 'SqlApi' -> if the plugin uses the complete sql_* or DB::* api (must also require nucleuscms 3.5)
\r
142 public function supportsFeature($feature)
\r
148 * Report a list of plugin that is required to final public function
\r
150 * @returns an array of names of plugin, an empty array indicates no dependency
\r
152 public function getPluginDep()
\r
157 // these helper final public functions should not be redefined in your plugin
\r
160 * Creates a new option for this plugin
\r
163 * A string uniquely identifying your option. (max. length is 20 characters)
\r
164 * @param description
\r
165 * A description that will show up in the nucleus admin area (max. length: 255 characters)
\r
167 * Either 'text', 'yesno' or 'password'
\r
168 * This info is used when showing 'edit plugin options' screens
\r
170 * Initial value for the option (max. value length is 128 characters)
\r
172 final public function createOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
174 return $this->create_option('global', $name, $desc, $type, $defValue, $typeExtras);
\r
177 final public function createBlogOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
179 return $this->create_option('blog', $name, $desc, $type, $defValue, $typeExtras);
\r
182 final public function createMemberOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
184 return $this->create_option('member', $name, $desc, $type, $defValue, $typeExtras);
\r
187 final public function createCategoryOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
189 return $this->create_option('category', $name, $desc, $type, $defValue, $typeExtras);
\r
192 final public function createItemOption($name, $desc, $type, $defValue = '', $typeExtras = '')
\r
194 return $this->create_option('item', $name, $desc, $type, $defValue, $typeExtras);
\r
198 * Removes the option from the database
\r
200 * Note: Options get erased automatically on plugin uninstall
\r
202 final public function deleteOption($name)
\r
204 return $this->delete_option('global', $name);
\r
207 final public function deleteBlogOption($name)
\r
209 return $this->delete_option('blog', $name);
\r
212 final public function deleteMemberOption($name)
\r
214 return $this->delete_option('member', $name);
\r
217 final public function deleteCategoryOption($name)
\r
219 return $this->delete_option('category', $name);
\r
222 final public function deleteItemOption($name)
\r
224 return $this->delete_option('item', $name);
\r
228 * Sets the value of an option to something new
\r
230 final public function setOption($name, $value)
\r
232 return $this->set_option('global', 0, $name, $value);
\r
235 final public function setBlogOption($blogid, $name, $value)
\r
237 return $this->set_option('blog', $blogid, $name, $value);
\r
240 final public function setMemberOption($memberid, $name, $value)
\r
242 return $this->set_option('member', $memberid, $name, $value);
\r
245 final public function setCategoryOption($catid, $name, $value)
\r
247 return $this->set_option('category', $catid, $name, $value);
\r
250 final public function setItemOption($itemid, $name, $value) {
\r
251 return $this->set_option('item', $itemid, $name, $value);
\r
255 * Retrieves the current value for an option
\r
257 final public function getOption($name)
\r
259 // only request the options the very first time. On subsequent requests
\r
260 // the static collection is used to save SQL queries.
\r
261 if ( $this->plugin_options == 0 )
\r
263 $this->plugin_options = array();
\r
265 $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
266 $query = sprintf($query, sql_table('plugin_option'), sql_table('plugin_option_desc'), (integer) $this->plugid);
\r
267 $result = DB::getResult($query);
\r
268 foreach ( $result as $row )
\r
270 $this->plugin_options[strtolower($row['name'])] = $row['value'];
\r
273 if ( isset($this->plugin_options[strtolower($name)]) )
\r
275 return $this->plugin_options[strtolower($name)];
\r
279 return $this->get_option('global', 0, $name);
\r
283 final public function getBlogOption($blogid, $name)
\r
285 return $this->get_option('blog', $blogid, $name);
\r
288 final public function getMemberOption($memberid, $name)
\r
290 return $this->get_option('member', $memberid, $name);
\r
293 final public function getCategoryOption($catid, $name)
\r
295 return $this->get_option('category', $catid, $name);
\r
298 final public function getItemOption($itemid, $name)
\r
300 return $this->get_option('item', $itemid, $name);
\r
304 * Retrieves an associative array with the option value for each
\r
307 final public function getAllBlogOptions($name)
\r
309 return $this->get_all_options('blog', $name);
\r
312 final public function getAllMemberOptions($name)
\r
314 return $this->get_all_options('member', $name);
\r
317 final public function getAllCategoryOptions($name)
\r
319 return $this->get_all_options('category', $name);
\r
322 final public function getAllItemOptions($name)
\r
324 return $this->get_all_options('item', $name);
\r
328 * Retrieves an indexed array with the top (or bottom) of an option
\r
329 * (delegates to getOptionTop())
\r
331 final public function getBlogOptionTop($name, $amount = 10, $sort = 'desc')
\r
333 return $this->get_option_top('blog', $name, $amount, $sort);
\r
336 final public function getMemberOptionTop($name, $amount = 10, $sort = 'desc')
\r
338 return $this->get_option_top('member', $name, $amount, $sort);
\r
341 final public function getCategoryOptionTop($name, $amount = 10, $sort = 'desc')
\r
343 return $this->get_option_top('category', $name, $amount, $sort);
\r
346 final public function getItemOptionTop($name, $amount = 10, $sort = 'desc')
\r
348 return $this->get_option_top('item', $name, $amount, $sort);
\r
352 * NucleusPlugin::getID()
\r
353 * get id for this plugin
\r
357 * @return integer this plugid id
\r
359 final public function getID()
\r
361 return (integer) $this->plugid;
\r
365 * NucleusPlugin::setID()
\r
366 * set favorite id for this plugin
\r
369 * @param integer $plugid favorite id for plugin
\r
372 final public function setID($plugid)
\r
374 $this->plugid = (integer) $plugid;
\r
379 * Returns the URL of the admin area for this plugin (in case there's
\r
380 * no such area, the returned information is invalid)
\r
384 final public function getAdminURL()
\r
387 return $CONF['PluginURL'] . $this->getShortName() . '/';
\r
391 * Returns the directory where the admin directory is located and
\r
392 * where the plugin can maintain his extra files
\r
396 final public function getDirectory()
\r
398 global $DIR_PLUGINS;
\r
399 return $DIR_PLUGINS . $this->getShortName() . '/';
\r
403 * Derives the short name for the plugin from the classname (all
\r
408 final public function getShortName()
\r
410 return str_replace('np_','',strtolower(get_class($this)));
\r
414 * Clears the option value cache which saves the option values during
\r
415 * the plugin execution. This function is usefull if the options has
\r
416 * changed during the plugin execution (especially in association with
\r
417 * the PrePluginOptionsUpdate and the PostPluginOptionsUpdate events)
\r
421 final public function clearOptionValueCache()
\r
423 $this->option_values = array();
\r
424 $this->plugin_options = 0;
\r
428 // internal functions of the class starts here
\r
429 protected $option_values; // oid_contextid => value
\r
430 protected $option_info; // context_name => array('oid' => ..., 'default' => ...)
\r
431 protected $plugin_options; // see getOption()
\r
432 protected $plugid; // plugin id
\r
435 * Class constructor: Initializes some internal data
\r
437 public function __construct()
\r
439 $this->option_values = array(); // oid_contextid => value
\r
440 $this->option_info = array(); // context_name => array('oid' => ..., 'default' => ...)
\r
441 $this->plugin_options = 0;
\r
445 * Retrieves an array of the top (or bottom) of an option from a plugin.
\r
447 * @param string $context the context for the option: item, blog, member,...
\r
448 * @param string $name the name of the option
\r
449 * @param int $amount how many rows must be returned
\r
450 * @param string $sort desc or asc
\r
451 * @return array array with both values and contextid's
\r
454 final protected function get_option_top($context, $name, $amount = 10, $sort = 'desc')
\r
456 if ( ($sort != 'desc') && ($sort != 'asc') )
\r
461 $oid = $this->get_option_id($context, $name);
\r
463 // retrieve the data and return
\r
464 $query = "SELECT otype, oextra FROM %s WHERE oid = %d;";
\r
465 $query = sprintf($query, sql_table('plugin_option_desc'), $oid);
\r
466 $row = DB::getRow($query);
\r
468 if ( ($this->optionCanBeNumeric($row['otype'])) && ($row['oextra'] == 'number' ) )
\r
470 $orderby = 'CAST(ovalue AS SIGNED)';
\r
474 $orderby = 'ovalue';
\r
476 $query = "SELECT ovalue value, ocontextid id FROM %s WHERE oid = %d ORDER BY %s %s LIMIT 0,%d;";
\r
477 $query = sprintf($query, sql_table('plugin_option'), $oid, $orderby, $sort, (integer) $amount);
\r
478 $result = DB::getResult($query);
\r
480 // create the array
\r
483 foreach( $result as $row )
\r
488 // return the array (duh!)
\r
493 * Creates an option in the database table plugin_option_desc
\r
497 final protected function create_option($context, $name, $desc, $type, $defValue, $typeExtras = '')
\r
499 // create in plugin_option_desc
\r
500 $query = 'INSERT INTO ' . sql_table('plugin_option_desc')
\r
501 .' (opid, oname, ocontext, odesc, otype, odef, oextra)'
\r
502 .' VALUES ('.intval($this->plugid)
\r
503 .', '.DB::quoteValue($name)
\r
504 .', '.DB::quoteValue($context)
\r
505 .', '.DB::quoteValue($desc)
\r
506 .', '.DB::quoteValue($type)
\r
507 .', '.DB::quoteValue($defValue)
\r
508 .', '.DB::quoteValue($typeExtras).')';
\r
509 DB::execute($query);
\r
510 $oid = DB::getInsertId();
\r
512 $key = $context . '_' . $name;
\r
513 $this->option_info[$key] = array('oid' => $oid, 'default' => $defValue);
\r
518 * Deletes an option from the database tables
\r
519 * plugin_option and plugin_option_desc
\r
523 final protected function delete_option($context, $name)
\r
525 $oid = $this->get_option_id($context, $name);
\r
528 return 0; // no such option
\r
531 // delete all things from plugin_option
\r
532 $query = "DELETE FROM %s WHERE oid=%d;";
\r
533 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid);
\r
534 DB::execute($query);
\r
536 // delete entry from plugin_option_desc
\r
537 $query = "DELETE FROM %s WHERE oid=%d;";
\r
538 $query = sprintf($query, sql_table('plugin_option_desc'), $oid);
\r
539 DB::execute($query);
\r
541 // clear from cache
\r
542 unset($this->option_info["{$context}_{$name}"]);
\r
543 $this->option_values = array();
\r
548 * Update an option in the database table plugin_option
\r
550 * returns: 1 on success, 0 on failure
\r
553 final protected function set_option($context, $contextid, $name, $value)
\r
557 $oid = $this->get_option_id($context, $name);
\r
563 // check if context id exists
\r
564 switch ( $context )
\r
567 if ( !Member::existsID($contextid) )
\r
573 if ( !$manager->existsBlogID($contextid) )
\r
579 if ( !$manager->existsCategory($contextid) )
\r
585 if ( !$manager->existsItem($contextid, true, true) )
\r
591 if ( $contextid != 0 )
\r
598 // update plugin_option
\r
599 $query = "DELETE FROM %s WHERE oid=%d and ocontextid=%d;";
\r
600 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid);
\r
601 DB::execute($query);
\r
603 $query = "INSERT INTO %s (ovalue, oid, ocontextid) VALUES (%s, %d, %d);";
\r
604 $query = sprintf($query, sql_table('plugin_option'), DB::quoteValue($value), $oid, $contextid);
\r
605 DB::execute($query);
\r
608 $this->option_values["{$oid}_{$contextid}"] = $value;
\r
609 if ( $context == 'global' )
\r
611 $this->plugin_options[strtolower($name)] = $value;
\r
618 * Get an option from Cache or database
\r
619 * - if not in the option Cache read it from the database
\r
620 * - if not in the database write default values into the database
\r
624 final protected function get_option($context, $contextid, $name)
\r
626 $oid = $this->get_option_id($context, $name);
\r
632 $key = "{$oid}_{$contextid}";
\r
634 if ( isset($this->option_values[$key]) )
\r
636 return $this->option_values[$key];
\r
640 $query = "SELECT ovalue FROM %s WHERE oid=%d and ocontextid=%d;";
\r
641 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid);
\r
642 $result = DB::getResult($query);
\r
644 if ( !$result || ($result->rowCount() == 0) )
\r
646 // fill DB with default value
\r
647 $this->option_values[$key] = $this->get_default_value($context, $name);
\r
648 $query = "INSERT INTO %s (oid, ocontextid, ovalue) VALUES (%d, %d, %s);";
\r
649 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid, DB::quoteValue($this->option_values[$key]));
\r
650 DB::execute($query);
\r
654 $row = $result->fetch();
\r
655 $this->option_values[$key] = $row['ovalue'];
\r
658 return $this->option_values[$key];
\r
662 * Returns assoc array with all values for a given option
\r
663 * (one option per possible context id)
\r
667 final protected function get_all_options($context, $name)
\r
669 $oid = $this->get_option_id($context, $name);
\r
674 $default_value = $this->get_default_value($context, $name);
\r
676 $options = array();
\r
677 $query = "SELECT %s as contextid FROM %s;";
\r
678 switch ( $context )
\r
681 $query = sprintf($query, 'bnumber', sql_table('blog'));
\r
684 $query = sprintf($query, 'catid', sql_table('category'));
\r
687 $query = sprintf($query, 'mnumber', sql_table('member'));
\r
690 $query = sprintf($query, 'inumber', sql_table('item'));
\r
694 $result = DB::getResult($query);
\r
697 foreach ( $result as $row )
\r
699 $options[$row['contextid']] = $default_value;
\r
703 $query = "SELECT ocontextid, ovalue FROM %s WHERE oid=%d;";
\r
704 $query = sprintf($query, sql_table('plugin_option'), $oid);
\r
705 $result = DB::getResult($query);
\r
706 foreach ( $result as $row )
\r
708 $options[$row['ocontextid']] = $row['ovalue'];
\r
715 * NucleusPlugin::get_option_id
\r
717 * Gets the 'option identifier' that corresponds to a given option name.
\r
718 * When this method is called for the first time, all the OIDs for the plugin
\r
719 * are loaded into memory, to avoid re-doing the same query all over.
\r
721 * @param string $context option context
\r
722 * @param string $name plugin name
\r
723 * @return integer option id
\r
725 final protected function get_option_id($context, $name)
\r
727 $key = "{$context}_{$name}";
\r
729 if ( array_key_exists($key, $this->option_info)
\r
730 && array_key_exists('oid', $this->option_info[$key]) )
\r
732 return $this->option_info[$key]['oid'];
\r
735 // load all OIDs for this plugin from the database
\r
736 $this->option_info = array();
\r
737 $query = "SELECT oid, oname, ocontext, odef FROM %s WHERE opid=%d;";
\r
738 $query = sprintf($query, sql_table('plugin_option_desc'), $this->plugid);
\r
739 $result = DB::getResult($query);
\r
740 foreach ( $result as $row )
\r
742 $k = $row['ocontext'] . '_' . $row['oname'];
\r
743 $this->option_info[$k] = array('oid' => $row['oid'], 'default' => $row['odef']);
\r
745 $result->closeCursor();
\r
747 return $this->option_info[$key]['oid'];
\r
749 final protected function get_default_value($context, $name)
\r
751 $key = $context . '_' . $name;
\r
753 if ( array_key_exists($key, $this->option_info)
\r
754 && array_key_exists('default', $this->option_info[$key]) )
\r
756 return $this->option_info[$key]['default'];
\r
762 * NucleusPlugin::delete_option_values()
\r
763 * Deletes all option values for a given context and contextid
\r
764 * (used when e.g. a blog, member or category is deleted)
\r
767 *@param String $context global/blog/category/item/member
\r
768 *@param Integer $contextid ID
\r
771 static public function delete_option_values($context, $contextid)
\r
773 // delete all associated plugin options
\r
776 $query = "SELECT oid FROM %s WHERE ocontext=%s;";
\r
777 $query = sprintf($query, sql_table('plugin_option_desc'), DB::quoteValue($context));
\r
779 $result = DB::getResult($query);
\r
780 foreach ( $result as $row )
\r
782 array_push($aOIDs, $row['oid']);
\r
784 $result->closeCursor();
\r
785 // delete those options. go go go
\r
786 if ( count($aOIDs) > 0 )
\r
788 $query = "DELETE FROM %s WHERE oid in (%s) and ocontextid=%d;";
\r
789 $query = sprintf($query, sql_table('plugin_option'), implode(',',$aOIDs), (integer) $contextid);
\r
790 DB::execute($query);
\r
796 * NucleusPlugin::getOptionMeta()
\r
797 * splits the option's typeextra field (at ;'s) to split the meta collection
\r
800 * @param string $typeExtra the value of the typeExtra field of an option
\r
801 * @return array array of the meta-key/value-pairs
\r
803 static public function getOptionMeta($typeExtra)
\r
807 /* 1. if $typeExtra includes delimiter ';', split it to tokens */
\r
808 $tokens = preg_split('#;#', $typeExtra);
\r
811 * 2. if each of tokens includes "=", it consists of key => value
\r
812 * else it's 'select' option
\r
814 foreach ( $tokens as $token )
\r
816 $matches = array();
\r
817 if ( preg_match("#^([^=]+)?=([^=]+)?$#", $token, $matches) )
\r
819 $meta[$matches[1]] = $matches[2];
\r
823 $meta['select'] = $token;
\r
830 * NucleusPlugin::getOptionSelectValues()
\r
831 * filters the selectlists out of the meta collection
\r
834 * @param string $typeExtra the value of the typeExtra field of an option
\r
835 * @return string the selectlist
\r
837 static public function getOptionSelectValues($typeExtra)
\r
839 $meta = NucleusPlugin::getOptionMeta($typeExtra);
\r
841 if ( array_key_exists('select', $meta) )
\r
843 return $meta['select'];
\r
849 * checks if the eventlist in the database is up-to-date
\r
850 * @return bool if it is up-to-date it return true, else false
\r
853 public function subscribtionListIsUptodate()
\r
855 $res = DB::getResult('SELECT event FROM '.sql_table('plugin_event').' WHERE pid = '.$this->plugid);
\r
857 foreach ( $res as $row )
\r
859 array_push($ev, $row['event']);
\r
861 if ( count($ev) != count($this->getEventList()) )
\r
865 $d = array_diff($ev, $this->getEventList());
\r
866 if ( count($d) > 0 )
\r
868 // there are differences so the db is not up-to-date
\r
875 * NucleusPlugin::apply_plugin_options()
\r
876 * Update its entry in database table
\r
879 * @param $options: array ( 'oid' => array( 'contextid' => 'value'))
\r
880 * (taken from request using requestVar())
\r
881 * @param $new_contextid: integer (accepts a contextid when it is for a new
\r
882 * contextid there was no id available at the moment of writing the
\r
883 * formcontrols into the page (by ex: itemOptions for new item)
\r
886 static public function apply_plugin_options(&$options, $new_contextid = 0)
\r
890 if ( !is_array($options) )
\r
895 foreach ( $options as $oid => $values )
\r
897 // get option type info
\r
898 $query = "SELECT opid, oname, ocontext, otype, oextra, odef FROM %s WHERE oid=%d;";
\r
899 $query = sprintf($query, sql_table('plugin_option_desc'), (integer) $oid);
\r
900 $result = DB::getRow($query);
\r
903 foreach ( $values as $id => $value )
\r
905 // decide wether we are using the contextid of newContextid
\r
906 if ( $new_contextid != 0 )
\r
908 $contextid = $new_contextid;
\r
915 // retreive any metadata
\r
916 $meta = NucleusPlugin::getOptionMeta($result['oextra']);
\r
918 // if the option is readonly or hidden it may not be saved
\r
919 if ( array_key_exists('access', $meta)
\r
920 && in_array($meta['access'], array('readonly', 'hidden')) )
\r
925 // value comes from request
\r
926 $value = undoMagic($value);
\r
928 /* validation the value according to its type */
\r
929 switch ( $result['otype'] )
\r
932 if ( ($value != 'yes') && ($value != 'no') )
\r
939 if ( array_key_exists('datatype', $meta)
\r
940 && ($meta['datatype'] == 'numerical') && ($value != (integer) $value) )
\r
942 $value = (integer) $result['odef'];
\r
952 * trigger event PrePluginOptionsUpdate to give the plugin the
\r
953 * possibility to change/validate the new value for the option
\r
956 'context' => $result['ocontext'],
\r
957 'plugid' => $result['opid'],
\r
958 'optionname' => $result['oname'],
\r
959 'contextid' => $contextid,
\r
960 'value' => &$value);
\r
961 $manager->notify('PrePluginOptionsUpdate', $data);
\r
963 // delete and insert its fields of table in database
\r
964 $query = "DELETE FROM %s WHERE oid=%d AND ocontextid=%d;";
\r
965 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid);
\r
966 DB::execute($query);
\r
967 $query = "INSERT INTO %s (oid, ocontextid, ovalue) VALUES (%d, %d, %s);";
\r
968 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid, DB::quoteValue($value));
\r
969 DB::execute($query);
\r
971 // clear option value cache if the plugin object is already loaded
\r
972 $plugin=& $manager->pidLoaded($result['opid']);
\r
975 $plugin->clearOptionValueCache();
\r
989 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
990 * Copyright (C) 2002-2009 The Nucleus Group
992 * This program is free software; you can redistribute it and/or
993 * modify it under the terms of the GNU General Public License
994 * as published by the Free Software Foundation; either version 2
995 * of the License, or (at your option) any later version.
996 * (see nucleus/documentation/index.html#license for more info)
999 * This is an (abstract) class of which all Nucleus Plugins must inherit
1001 * for more information on plugins and how to write your own, see the
1002 * plugins.html file that is included with the Nucleus documenation
1004 * @license http://nucleuscms.org/license.txt GNU General Public License
1005 * @copyright Copyright (C) 2002-2009 The Nucleus Group
1006 * @version $Id: PLUGIN.php 1866 2012-05-20 13:21:55Z sakamocchi $
1008 abstract class NucleusPlugin
1010 // these public functions should to be redefined in your plugin
1011 public function getName()
1016 public function getAuthor()
1021 public function getURL()
1026 public function getVersion()
1031 public function getDescription()
1036 // these final public function _may_ be redefined in your plugin
1038 public function getMinNucleusVersion()
1043 public function getMinNucleusPatchLevel()
1048 public function getEventList()
1053 public function getTableList()
1058 public function hasAdminArea()
1063 public function install()
1068 public function unInstall()
1073 public function init()
1078 public function doSkinVar($skinType)
1083 public function doTemplateVar(&$item)
1085 $args = func_get_args();
1087 array_unshift($args, 'template');
1088 call_user_func_array(array($this, 'doSkinVar'), $args);
1092 public function doTemplateCommentsVar(&$item, &$comment)
1094 $args = func_get_args();
1097 array_unshift($args, 'template');
1098 call_user_func_array(array($this, 'doSkinVar'), $args);
1102 public function doAction($type)
1104 return _ERROR_PLUGIN_NOSUCHACTION;
1107 public function doIf($key,$value)
1112 public function doItemVar (&$item)
1118 * Checks if a plugin supports a certain feature.
1120 * @returns 1 if the feature is reported, 0 if not
1122 * Name of the feature. See plugin documentation for more info
1123 * 'SqlTablePrefix' -> if the plugin uses the sql_table() method to get table names
1124 * 'HelpPage' -> if the plugin provides a helppage
1125 * 'SqlApi' -> if the plugin uses the complete sql_* or DB::* api (must also require nucleuscms 3.5)
1127 public function supportsFeature($feature)
1133 * Report a list of plugin that is required to final public function
1135 * @returns an array of names of plugin, an empty array indicates no dependency
1137 public function getPluginDep()
1142 // these helper final public functions should not be redefined in your plugin
1145 * Creates a new option for this plugin
1148 * A string uniquely identifying your option. (max. length is 20 characters)
1149 * @param description
1150 * A description that will show up in the nucleus admin area (max. length: 255 characters)
1152 * Either 'text', 'yesno' or 'password'
1153 * This info is used when showing 'edit plugin options' screens
1155 * Initial value for the option (max. value length is 128 characters)
1157 final public function createOption($name, $desc, $type, $defValue = '', $typeExtras = '')
1159 return $this->create_option('global', $name, $desc, $type, $defValue, $typeExtras);
1162 final public function createBlogOption($name, $desc, $type, $defValue = '', $typeExtras = '')
1164 return $this->create_option('blog', $name, $desc, $type, $defValue, $typeExtras);
1167 final public function createMemberOption($name, $desc, $type, $defValue = '', $typeExtras = '')
1169 return $this->create_option('member', $name, $desc, $type, $defValue, $typeExtras);
1172 final public function createCategoryOption($name, $desc, $type, $defValue = '', $typeExtras = '')
1174 return $this->create_option('category', $name, $desc, $type, $defValue, $typeExtras);
1177 final public function createItemOption($name, $desc, $type, $defValue = '', $typeExtras = '')
1179 return $this->create_option('item', $name, $desc, $type, $defValue, $typeExtras);
1183 * Removes the option from the database
1185 * Note: Options get erased automatically on plugin uninstall
1187 final public function deleteOption($name)
1189 return $this->delete_option('global', $name);
1192 final public function deleteBlogOption($name)
1194 return $this->delete_option('blog', $name);
1197 final public function deleteMemberOption($name)
1199 return $this->delete_option('member', $name);
1202 final public function deleteCategoryOption($name)
1204 return $this->delete_option('category', $name);
1207 final public function deleteItemOption($name)
1209 return $this->delete_option('item', $name);
1213 * Sets the value of an option to something new
1215 final public function setOption($name, $value)
1217 return $this->set_option('global', 0, $name, $value);
1220 final public function setBlogOption($blogid, $name, $value)
1222 return $this->set_option('blog', $blogid, $name, $value);
1225 final public function setMemberOption($memberid, $name, $value)
1227 return $this->set_option('member', $memberid, $name, $value);
1230 final public function setCategoryOption($catid, $name, $value)
1232 return $this->set_option('category', $catid, $name, $value);
1235 final public function setItemOption($itemid, $name, $value) {
1236 return $this->set_option('item', $itemid, $name, $value);
1240 * Retrieves the current value for an option
1242 final public function getOption($name)
1244 // only request the options the very first time. On subsequent requests
1245 // the static collection is used to save SQL queries.
1246 if ( $this->plugin_options == 0 )
1248 $this->plugin_options = array();
1250 $query = "SELECT d.oname as name, o.ovalue as value FROM %s o, %s d WHERE d.opid=%d AND d.oid=o.oid;";
1251 $query = sprintf($query, sql_table('plugin_option'), sql_table('plugin_option_desc'), (integer) $this->plugid);
1252 $result = DB::getResult($query);
1253 foreach ( $result as $row )
1255 $this->plugin_options[strtolower($row['name'])] = $row['value'];
1258 if ( isset($this->plugin_options[strtolower($name)]) )
1260 return $this->plugin_options[strtolower($name)];
1264 return $this->get_option('global', 0, $name);
1268 final public function getBlogOption($blogid, $name)
1270 return $this->get_option('blog', $blogid, $name);
1273 final public function getMemberOption($memberid, $name)
1275 return $this->get_option('member', $memberid, $name);
1278 final public function getCategoryOption($catid, $name)
1280 return $this->get_option('category', $catid, $name);
1283 final public function getItemOption($itemid, $name)
1285 return $this->get_option('item', $itemid, $name);
1289 * Retrieves an associative array with the option value for each
1292 final public function getAllBlogOptions($name)
1294 return $this->get_all_options('blog', $name);
1297 final public function getAllMemberOptions($name)
1299 return $this->get_all_options('member', $name);
1302 final public function getAllCategoryOptions($name)
1304 return $this->get_all_options('category', $name);
1307 final public function getAllItemOptions($name)
1309 return $this->get_all_options('item', $name);
1313 * Retrieves an indexed array with the top (or bottom) of an option
1314 * (delegates to getOptionTop())
1316 final public function getBlogOptionTop($name, $amount = 10, $sort = 'desc')
1318 return $this->get_option_top('blog', $name, $amount, $sort);
1321 final public function getMemberOptionTop($name, $amount = 10, $sort = 'desc')
1323 return $this->get_option_top('member', $name, $amount, $sort);
1326 final public function getCategoryOptionTop($name, $amount = 10, $sort = 'desc')
1328 return $this->get_option_top('category', $name, $amount, $sort);
1331 final public function getItemOptionTop($name, $amount = 10, $sort = 'desc')
1333 return $this->get_option_top('item', $name, $amount, $sort);
1337 * NucleusPlugin::getID()
1338 * get id for this plugin
1342 * @return integer this plugid id
1344 final public function getID()
1346 return (integer) $this->plugid;
1350 * NucleusPlugin::setID()
1351 * set favorite id for this plugin
1354 * @param integer $plugid favorite id for plugin
1357 final public function setID($plugid)
1359 $this->plugid = (integer) $plugid;
1364 * Returns the URL of the admin area for this plugin (in case there's
1365 * no such area, the returned information is invalid)
1369 final public function getAdminURL()
1372 return $CONF['PluginURL'] . $this->getShortName() . '/';
1376 * Returns the directory where the admin directory is located and
1377 * where the plugin can maintain his extra files
1381 final public function getDirectory()
1383 global $DIR_PLUGINS;
1384 return $DIR_PLUGINS . $this->getShortName() . '/';
1388 * Derives the short name for the plugin from the classname (all
1393 final public function getShortName()
1395 return str_replace('np_','',strtolower(get_class($this)));
1399 * Clears the option value cache which saves the option values during
1400 * the plugin execution. This function is usefull if the options has
1401 * changed during the plugin execution (especially in association with
1402 * the PrePluginOptionsUpdate and the PostPluginOptionsUpdate events)
1406 final public function clearOptionValueCache()
1408 $this->option_values = array();
1409 $this->plugin_options = 0;
1413 // internal functions of the class starts here
1414 protected $option_values; // oid_contextid => value
1415 protected $option_info; // context_name => array('oid' => ..., 'default' => ...)
1416 protected $plugin_options; // see getOption()
1417 protected $plugid; // plugin id
1420 * Class constructor: Initializes some internal data
1422 public function __construct()
1424 $this->option_values = array(); // oid_contextid => value
1425 $this->option_info = array(); // context_name => array('oid' => ..., 'default' => ...)
1426 $this->plugin_options = 0;
1430 * Retrieves an array of the top (or bottom) of an option from a plugin.
1432 * @param string $context the context for the option: item, blog, member,...
1433 * @param string $name the name of the option
1434 * @param int $amount how many rows must be returned
1435 * @param string $sort desc or asc
1436 * @return array array with both values and contextid's
1439 final protected function get_option_top($context, $name, $amount = 10, $sort = 'desc')
1441 if ( ($sort != 'desc') && ($sort != 'asc') )
1446 $oid = $this->get_option_id($context, $name);
1448 // retrieve the data and return
1449 $query = "SELECT otype, oextra FROM %s WHERE oid = %d;";
1450 $query = sprintf($query, sql_table('plugin_option_desc'), $oid);
1451 $row = DB::getRow($query);
1453 if ( ($this->optionCanBeNumeric($row['otype'])) && ($row['oextra'] == 'number' ) )
1455 $orderby = 'CAST(ovalue AS SIGNED)';
1459 $orderby = 'ovalue';
1461 $query = "SELECT ovalue value, ocontextid id FROM %s WHERE oid = %d ORDER BY %s %s LIMIT 0,%d;";
1462 $query = sprintf($query, sql_table('plugin_option'), $oid, $orderby, $sort, (integer) $amount);
1463 $result = DB::getResult($query);
1468 foreach( $result as $row )
1473 // return the array (duh!)
1478 * Creates an option in the database table plugin_option_desc
1482 final protected function create_option($context, $name, $desc, $type, $defValue, $typeExtras = '')
1484 // create in plugin_option_desc
1485 $query = 'INSERT INTO ' . sql_table('plugin_option_desc')
1486 .' (opid, oname, ocontext, odesc, otype, odef, oextra)'
1487 .' VALUES ('.intval($this->plugid)
1488 .', '.DB::quoteValue($name)
1489 .', '.DB::quoteValue($context)
1490 .', '.DB::quoteValue($desc)
1491 .', '.DB::quoteValue($type)
1492 .', '.DB::quoteValue($defValue)
1493 .', '.DB::quoteValue($typeExtras).')';
1494 DB::execute($query);
1495 $oid = DB::getInsertId();
1497 $key = $context . '_' . $name;
1498 $this->option_info[$key] = array('oid' => $oid, 'default' => $defValue);
1503 * Deletes an option from the database tables
1504 * plugin_option and plugin_option_desc
1508 final protected function delete_option($context, $name)
1510 $oid = $this->get_option_id($context, $name);
1513 return 0; // no such option
1516 // delete all things from plugin_option
1517 $query = "DELETE FROM %s WHERE oid=%d;";
1518 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid);
1519 DB::execute($query);
1521 // delete entry from plugin_option_desc
1522 $query = "DELETE FROM %s WHERE oid=%d;";
1523 $query = sprintf($query, sql_table('plugin_option_desc'), $oid);
1524 DB::execute($query);
1527 unset($this->option_info["{$context}_{$name}"]);
1528 $this->option_values = array();
1533 * Update an option in the database table plugin_option
1535 * returns: 1 on success, 0 on failure
1538 final protected function set_option($context, $contextid, $name, $value)
1542 $oid = $this->get_option_id($context, $name);
1548 // check if context id exists
1552 if ( !Member::existsID($contextid) )
1558 if ( !$manager->existsBlogID($contextid) )
1564 if ( !$manager->existsCategory($contextid) )
1570 if ( !$manager->existsItem($contextid, true, true) )
1576 if ( $contextid != 0 )
1583 // update plugin_option
1584 $query = "DELETE FROM %s WHERE oid=%d and ocontextid=%d;";
1585 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid);
1586 DB::execute($query);
1588 $query = "INSERT INTO %s (ovalue, oid, ocontextid) VALUES (%s, %d, %d);";
1589 $query = sprintf($query, sql_table('plugin_option'), DB::quoteValue($value), $oid, $contextid);
1590 DB::execute($query);
1593 $this->option_values["{$oid}_{$contextid}"] = $value;
1594 if ( $context == 'global' )
1596 $this->plugin_options[strtolower($name)] = $value;
1603 * Get an option from Cache or database
1604 * - if not in the option Cache read it from the database
1605 * - if not in the database write default values into the database
1609 final protected function get_option($context, $contextid, $name)
1611 $oid = $this->get_option_id($context, $name);
1617 $key = "{$oid}_{$contextid}";
1619 if ( isset($this->option_values[$key]) )
1621 return $this->option_values[$key];
1625 $query = "SELECT ovalue FROM %s WHERE oid=%d and ocontextid=%d;";
1626 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid);
1627 $result = DB::getResult($query);
1629 if ( !$result || ($result->rowCount() == 0) )
1631 // fill DB with default value
1632 $this->option_values[$key] = $this->get_default_value($context, $name);
1633 $query = "INSERT INTO %s (oid, ocontextid, ovalue) VALUES (%d, %d, %s);";
1634 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid, DB::quoteValue($this->option_values[$key]));
1635 DB::execute($query);
1639 $row = $result->fetch();
1640 $this->option_values[$key] = $row['ovalue'];
1643 return $this->option_values[$key];
1647 * Returns assoc array with all values for a given option
1648 * (one option per possible context id)
1652 final protected function get_all_options($context, $name)
1654 $oid = $this->get_option_id($context, $name);
1659 $default_value = $this->get_default_value($context, $name);
1662 $query = "SELECT %s as contextid FROM %s;";
1666 $query = sprintf($query, 'bnumber', sql_table('blog'));
1669 $query = sprintf($query, 'catid', sql_table('category'));
1672 $query = sprintf($query, 'mnumber', sql_table('member'));
1675 $query = sprintf($query, 'inumber', sql_table('item'));
1679 $result = DB::getResult($query);
1682 foreach ( $result as $row )
1684 $options[$row['contextid']] = $default_value;
1688 $query = "SELECT ocontextid, ovalue FROM %s WHERE oid=%d;";
1689 $query = sprintf($query, sql_table('plugin_option'), $oid);
1690 $result = DB::getResult($query);
1691 foreach ( $result as $row )
1693 $options[$row['ocontextid']] = $row['ovalue'];
1700 * NucleusPlugin::get_option_id
1702 * Gets the 'option identifier' that corresponds to a given option name.
1703 * When this method is called for the first time, all the OIDs for the plugin
1704 * are loaded into memory, to avoid re-doing the same query all over.
1706 * @param string $context option context
1707 * @param string $name plugin name
1708 * @return integer option id
1710 final protected function get_option_id($context, $name)
1712 $key = "{$context}_{$name}";
1714 if ( array_key_exists($key, $this->option_info)
1715 && array_key_exists('oid', $this->option_info[$key]) )
1717 return $this->option_info[$key]['oid'];
1720 // load all OIDs for this plugin from the database
1721 $this->option_info = array();
1722 $query = "SELECT oid, oname, ocontext, odef FROM %s WHERE opid=%d;";
1723 $query = sprintf($query, sql_table('plugin_option_desc'), $this->plugid);
1724 $result = DB::getResult($query);
1725 foreach ( $result as $row )
1727 $k = $row['ocontext'] . '_' . $row['oname'];
1728 $this->option_info[$k] = array('oid' => $row['oid'], 'default' => $row['odef']);
1730 $result->closeCursor();
1732 return $this->option_info[$key]['oid'];
1734 final protected function get_default_value($context, $name)
1736 $key = $context . '_' . $name;
1738 if ( array_key_exists($key, $this->option_info)
1739 && array_key_exists('default', $this->option_info[$key]) )
1741 return $this->option_info[$key]['default'];
1747 * NucleusPlugin::delete_option_values()
1748 * Deletes all option values for a given context and contextid
1749 * (used when e.g. a blog, member or category is deleted)
1752 *@param String $context global/blog/category/item/member
1753 *@param Integer $contextid ID
1756 static public function delete_option_values($context, $contextid)
1758 // delete all associated plugin options
1761 $query = "SELECT oid FROM %s WHERE ocontext=%s;";
1762 $query = sprintf($query, sql_table('plugin_option_desc'), DB::quoteValue($context));
1764 $result = DB::getResult($query);
1765 foreach ( $result as $row )
1767 array_push($aOIDs, $row['oid']);
1769 $result->closeCursor();
1770 // delete those options. go go go
1771 if ( count($aOIDs) > 0 )
1773 $query = "DELETE FROM %s WHERE oid in (%s) and ocontextid=%d;";
1774 $query = sprintf($query, sql_table('plugin_option'), implode(',',$aOIDs), (integer) $contextid);
1775 DB::execute($query);
1781 * NucleusPlugin::getOptionMeta()
1782 * splits the option's typeextra field (at ;'s) to split the meta collection
1785 * @param string $typeExtra the value of the typeExtra field of an option
1786 * @return array array of the meta-key/value-pairs
1788 static public function getOptionMeta($typeExtra)
1792 /* 1. if $typeExtra includes delimiter ';', split it to tokens */
1793 $tokens = preg_split('#;#', $typeExtra);
1796 * 2. if each of tokens includes "=", it consists of key => value
1797 * else it's 'select' option
1799 foreach ( $tokens as $token )
1802 if ( preg_match("#^([^=]+)?=([^=]+)?$#", $token, $matches) )
1804 $meta[$matches[1]] = $matches[2];
1808 $meta['select'] = $token;
1815 * NucleusPlugin::getOptionSelectValues()
1816 * filters the selectlists out of the meta collection
1819 * @param string $typeExtra the value of the typeExtra field of an option
1820 * @return string the selectlist
1822 static public function getOptionSelectValues($typeExtra)
1824 $meta = NucleusPlugin::getOptionMeta($typeExtra);
1826 if ( array_key_exists('select', $meta) )
1828 return $meta['select'];
1834 * checks if the eventlist in the database is up-to-date
1835 * @return bool if it is up-to-date it return true, else false
1838 public function subscribtionListIsUptodate()
1840 $res = DB::getResult('SELECT event FROM '.sql_table('plugin_event').' WHERE pid = '.$this->plugid);
1842 foreach ( $res as $row )
1844 array_push($ev, $row['event']);
1846 if ( count($ev) != count($this->getEventList()) )
1850 $d = array_diff($ev, $this->getEventList());
1851 if ( count($d) > 0 )
1853 // there are differences so the db is not up-to-date
1860 * NucleusPlugin::apply_plugin_options()
1861 * Update its entry in database table
1864 * @param $options: array ( 'oid' => array( 'contextid' => 'value'))
1865 * (taken from request using requestVar())
1866 * @param $new_contextid: integer (accepts a contextid when it is for a new
1867 * contextid there was no id available at the moment of writing the
1868 * formcontrols into the page (by ex: itemOptions for new item)
1871 static public function apply_plugin_options(&$options, $new_contextid = 0)
1875 if ( !is_array($options) )
1880 foreach ( $options as $oid => $values )
1882 // get option type info
1883 $query = "SELECT opid, oname, ocontext, otype, oextra, odef FROM %s WHERE oid=%d;";
1884 $query = sprintf($query, sql_table('plugin_option_desc'), (integer) $oid);
1885 $result = DB::getRow($query);
1888 foreach ( $values as $id => $value )
1890 // decide wether we are using the contextid of newContextid
1891 if ( $new_contextid != 0 )
1893 $contextid = $new_contextid;
1900 // retreive any metadata
1901 $meta = NucleusPlugin::getOptionMeta($result['oextra']);
1903 // if the option is readonly or hidden it may not be saved
1904 if ( array_key_exists('access', $meta)
1905 && in_array($meta['access'], array('readonly', 'hidden')) )
1910 // value comes from request
1911 $value = undoMagic($value);
1913 /* validation the value according to its type */
1914 switch ( $result['otype'] )
1917 if ( ($value != 'yes') && ($value != 'no') )
1924 if ( array_key_exists('datatype', $meta)
1925 && ($meta['datatype'] == 'numerical') && ($value != (integer) $value) )
1927 $value = (integer) $result['odef'];
1937 * trigger event PrePluginOptionsUpdate to give the plugin the
1938 * possibility to change/validate the new value for the option
1941 'context' => $result['ocontext'],
1942 'plugid' => $result['opid'],
1943 'optionname' => $result['oname'],
1944 'contextid' => $contextid,
1945 'value' => &$value);
1946 $manager->notify('PrePluginOptionsUpdate', $data);
1948 // delete and insert its fields of table in database
1949 $query = "DELETE FROM %s WHERE oid=%d AND ocontextid=%d;";
1950 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid);
1951 DB::execute($query);
1952 $query = "INSERT INTO %s (oid, ocontextid, ovalue) VALUES (%d, %d, %s);";
1953 $query = sprintf($query, sql_table('plugin_option'), (integer) $oid, (integer) $contextid, DB::quoteValue($value));
1954 DB::execute($query);
1956 // clear option value cache if the plugin object is already loaded
1957 $plugin=& $manager->pidLoaded($result['opid']);
1960 $plugin->clearOptionValueCache();
1971 >>>>>>> skinnable-master