From 160230943592591fe105efb85255284f6ff48a97 Mon Sep 17 00:00:00 2001 From: Kevin Chabowski Date: Sat, 19 May 2012 13:40:15 +0200 Subject: ArticleExtradata class and other changes to models.php * ArticleExtradata class added. This class gives plugins the possibility to assign additional data to articles. * Abstract class KVStorage added. ArticleExtradata and PluginKVStorage extend from it. * Added dbversion function, it returns the version of the database model currently in use. The version is stored in the PREFIX_meta table. If there is no PREFIX_meta table, dbversion returns version 0. This will be useful for updating the system. * New MySQL tables. --- ratatoeskr/setup/create_tables.php | 49 ++++++---- ratatoeskr/sys/models.php | 180 +++++++++++++++++++++++++------------ 2 files changed, 154 insertions(+), 75 deletions(-) diff --git a/ratatoeskr/setup/create_tables.php b/ratatoeskr/setup/create_tables.php index 819970a..97a4cd5 100644 --- a/ratatoeskr/setup/create_tables.php +++ b/ratatoeskr/setup/create_tables.php @@ -20,12 +20,12 @@ CREATE TABLE IF NOT EXISTS `PREFIX_articles` ( `timestamp` bigint(20) NOT NULL, `allow_comments` int(11) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_article_tag_relations` ( `tag` int(11) NOT NULL, `article` int(11) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_comments` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -38,30 +38,30 @@ CREATE TABLE IF NOT EXISTS `PREFIX_comments` ( `visible` tinyint(4) NOT NULL, `read_by_admin` tinyint(4) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_groups` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` text COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_group_members` ( `user` int(11) NOT NULL, `group` int(11) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_images` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` text COLLATE utf8_unicode_ci NOT NULL, `file` text COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_multilingual` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_plugins` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -82,13 +82,13 @@ CREATE TABLE IF NOT EXISTS `PREFIX_plugins` ( `update` tinyint(4) NOT NULL, `api` int(11) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_plugin_kvstorage` ( `plugin` int(11) NOT NULL, `key` text COLLATE utf8_unicode_ci NOT NULL, `value` text COLLATE utf8_unicode_ci NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_repositories` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -98,7 +98,7 @@ CREATE TABLE IF NOT EXISTS `PREFIX_repositories` ( `pkgcache` text COLLATE utf8_unicode_ci NOT NULL, `lastrefresh` bigint(20) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_sections` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -107,38 +107,38 @@ CREATE TABLE IF NOT EXISTS `PREFIX_sections` ( `template` text COLLATE utf8_unicode_ci NOT NULL, `styles` text COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_section_style_relations` ( `section` int(11) NOT NULL, `style` int(11) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_settings_kvstorage` ( `key` text COLLATE utf8_unicode_ci NOT NULL, `value` text COLLATE utf8_unicode_ci NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_styles` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` text COLLATE utf8_unicode_ci NOT NULL, `code` text COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_tags` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` text COLLATE utf8_unicode_ci NOT NULL, `title` int(11) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_translations` ( `multilingual` int(11) NOT NULL, `language` varchar(10) COLLATE utf8_unicode_ci NOT NULL, `text` text COLLATE utf8_unicode_ci NOT NULL, `texttype` text COLLATE utf8_unicode_ci NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `PREFIX_users` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -148,7 +148,20 @@ CREATE TABLE IF NOT EXISTS `PREFIX_users` ( `fullname` text COLLATE utf8_unicode_ci NOT NULL, `language` varchar(10) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +CREATE TABLE IF NOT EXISTS `PREFIX_meta` ( + `key` text COLLATE utf8_unicode_ci NOT NULL, + `value` text COLLATE utf8_unicode_ci NOT NULL +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + + +CREATE TABLE IF NOT EXISTS `PREFIX_article_extradata` ( + `article` int(11) NOT NULL, + `plugin` int(11) NOT NULL, + `key` text COLLATE utf8_unicode_ci NOT NULL, + `value` text COLLATE utf8_unicode_ci NOT NULL +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; SQL; function create_mysql_tables() @@ -161,6 +174,8 @@ function create_mysql_tables() if(!empty($q)) qdb($q); } + + qdb("INSERT INTO `PREFIX_meta` (`key`, `value`) VALUES ('dbversion', '%s')", base64_encode(serialize(1))); } ?> diff --git a/ratatoeskr/sys/models.php b/ratatoeskr/sys/models.php index fe80ce4..bc48908 100644 --- a/ratatoeskr/sys/models.php +++ b/ratatoeskr/sys/models.php @@ -88,6 +88,79 @@ abstract class BySQLRowEnabled } } +abstract class KVStorage implements Countable, ArrayAccess, Iterator +{ + private $keybuffer; + private $counter; + private $prepared_queries; + + final protected function init($sqltable, $common_fields) + { + $this->keybuffer = array(); + + $selector = "WHERE " . (empty($common_fields) ? 1 : implode(" AND ", array_map(function($x) { return qdb_fmt("`{$x[0]}` = {$x[1]}", $x[2]); }, $common_fields))); + $this->prepared_queries = array( + "get" => "SELECT `value` FROM `$sqltable` $selector AND `key` = '%s'", + "unset" => "DELETE FROM `$sqltable` $selector AND `key` = '%s'", + "update" => "UPDATE `$sqltable` SET `value` = '%s' $selector AND `key` = '%s'", + "create" => "INSERT INTO `$sqltable` (`key`, `value` " + . (empty($common_fields) ?: ", " . implode(", ", array_map(function($x) { return "`".$x[0]."`"; }, $common_fields))) + . ") VALUES ('%s', '%s'" + . (empty($common_fields) ?: ", " . implode(", ", array_map(function($x) { return qdb_fmt($x[1], $x[2]); }, $common_fields))) + . ")" + ); + + $result = qdb("SELECT `key` FROM `$sqltable` $selector"); + while($sqlrow = mysql_fetch_assoc($result)) + $this->keybuffer[] = $sqlrow["key"]; + + $this->counter = 0; + } + + /* Countable interface implementation */ + final public function count() { return count($this->keybuffer); } + + /* ArrayAccess interface implementation */ + final public function offsetExists($offset) { return in_array($offset, $this->keybuffer); } + final public function offsetGet($offset) + { + if($this->offsetExists($offset)) + { + $result = qdb($this->prepared_queries["get"], $offset); + $sqlrow = mysql_fetch_assoc($result); + return unserialize(base64_decode($sqlrow["value"])); + } + else + throw new DoesNotExistError(); + } + final public function offsetUnset($offset) + { + if($this->offsetExists($offset)) + { + unset($this->keybuffer[array_search($offset, $this->keybuffer)]); + $this->keybuffer = array_merge($this->keybuffer); + qdb($this->prepared_queries["unset"], $offset); + } + } + final public function offsetSet($offset, $value) + { + if($this->offsetExists($offset)) + qdb($this->prepared_queries["update"], base64_encode(serialize($value)), $offset); + else + { + qdb($this->prepared_queries["create"], $offset, base64_encode(serialize($value))); + $this->keybuffer[] = $offset; + } + } + + /* Iterator interface implementation */ + final public function rewind() { return $this->counter = 0; } + final public function current() { return $this->offsetGet($this->keybuffer[$this->counter]); } + final public function key() { return $this->keybuffer[$this->counter]; } + final public function next() { ++$this->counter; } + final public function valid() { return isset($this->keybuffer[$this->counter]); } +} + /* * Class: User * Data model for Users @@ -772,12 +845,8 @@ $ratatoeskr_settings = Settings::get_instance(); * Can be accessed like an array. * Keys are strings and Values can be everything serialize() can process. */ -class PluginKVStorage implements Countable, ArrayAccess, Iterator +class PluginKVStorage extends KVStorage { - private $plugin_id; - private $keybuffer; - private $counter; - /* * Constructor: __construct * @@ -786,60 +855,10 @@ class PluginKVStorage implements Countable, ArrayAccess, Iterator */ public function __construct($plugin_id) { - $this->keybuffer = array(); - $this->plugin_id = $plugin_id; - - $result = qdb("SELECT `key` FROM `PREFIX_plugin_kvstorage` WHERE `plugin` = %d", $plugin_id); - while($sqlrow = mysql_fetch_assoc($result)) - $this->keybuffer[] = $sqlrow["key"]; - - $this->counter = 0; - } - - /* Countable interface implementation */ - public function count() { return count($this->keybuffer); } - - /* ArrayAccess interface implementation */ - public function offsetExists($offset) { return in_array($offset, $this->keybuffer); } - public function offsetGet($offset) - { - if($this->offsetExists($offset)) - { - $result = qdb("SELECT `value` FROM `PREFIX_plugin_kvstorage` WHERE `key` = '%s' AND `plugin` = %d", $offset, $this->plugin_id); - $sqlrow = mysql_fetch_assoc($result); - return unserialize(base64_decode($sqlrow["value"])); - } - else - throw new DoesNotExistError(); - } - public function offsetUnset($offset) - { - if($this->offsetExists($offset)) - { - unset($this->keybuffer[array_search($offset, $this->keybuffer)]); - $this->keybuffer = array_merge($this->keybuffer); - qdb("DELETE FROM `PREFIX_plugin_kvstorage` WHERE `key` = '%s' AND `plugin` = %d", $offset, $this->plugin_id); - } - } - public function offsetSet($offset, $value) - { - if($this->offsetExists($offset)) - qdb("UPDATE `PREFIX_plugin_kvstorage` SET `value` = '%s' WHERE `key` = '%s' AND `plugin` = %d", - base64_encode(serialize($value)), $offset, $this->plugin_id); - else - { - qdb("INSERT INTO `PREFIX_plugin_kvstorage` (`plugin`, `key`, `value`) VALUES (%d, '%s', '%s')", - $this->plugin_id, $offset, base64_encode(serialize($value))); - $this->keybuffer[] = $offset; - } + $this->init("PREFIX_plugin_kvstorage", array( + array("plugin", "%d", $plugin_id) + )); } - - /* Iterator interface implementation */ - function rewind() { return $this->position = 0; } - function current() { return $this->offsetGet($this->keybuffer[$this->position]); } - function key() { return $this->keybuffer[$this->position]; } - function next() { ++$this->position; } - function valid() { return isset($this->keybuffer[$this->position]); } } /* @@ -1372,6 +1391,7 @@ class Plugin extends BySQLRowEnabled { qdb("DELETE FROM `PREFIX_plugins` WHERE `id` = %d", $this->id); qdb("DELETE FROM `PREFIX_plugin_kvstorage` WHERE `plugin` = %d", $this->id); + qdb("DELETE FROM `PREFIX_article_extradata` WHERE `plugin` = %d", $this->id); if(is_dir(SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/private/" . $this->id)) delete_directory(SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/private/" . $this->id); if(is_dir(SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/public/" . $this->id)) @@ -2604,10 +2624,54 @@ WHERE " . implode(" AND ", $subqueries) . " $sorting"); $comment->delete(); qdb("DELETE FROM `PREFIX_article_tag_relations` WHERE `article` = %d", $this->id); + qdb("DELETE FROM `PREFIX_article_extradata` WHERE `article` = %d", $this->id); qdb("DELETE FROM `PREFIX_articles` WHERE `id` = %d", $this->id); } } +/* + * Class: ArticleExtradata + * A Key-Value-Storage assigned to Articles for plugins to store additional data. + * Can be accessed like an array. + * Keys are strings and Values can be everything serialize() can process. + */ +class ArticleExtradata extends KVStorage +{ + /* + * Constructor: __construct + * + * Parameters: + * $article_id - The ID of the Article. + * $plugin_id - The ID of the Plugin. + */ + public function __construct($article_id, $plugin_id) + { + $this->init("PREFIX_article_extradata", array( + array("article", "%d", $article_id), + array("plugin", "%d", $plugin_id) + )); + } +} + +/* + * Function: dbversion + * Get the version of the database structure currently used. + * + * Returns: + * The numerical version of the current database structure. + */ +function dbversion() +{ + /* Is the meta table present? If no, the version is 0. */ + $result = qdb("SHOW TABLES LIKE 'PREFIX_meta'"); + if(mysql_num_rows($result) == 0) + return 0; + + $result = qdb("SELECT `value` FROM `PREFIX_meta` WHERE `key` = 'dbversion'"); + $sqlrow = mysql_fetch_assoc($result); + return unserialize(base64_decode($sqlrow["value"])); +} + /* * Function: clean_database * Clean up the database -- cgit v1.2.3-54-g00ecf From 1bfb9653d6e9139445ca9cde5808228c3b16399e Mon Sep 17 00:00:00 2001 From: Kevin Chabowski Date: Sun, 20 May 2012 12:55:27 +0200 Subject: Added silent mode to abstract KVStorage class. Activated silent mode will return NULL instead of throwing an DoesNotExistError Exception, if a key does not exist. --- ratatoeskr/sys/models.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ratatoeskr/sys/models.php b/ratatoeskr/sys/models.php index bc48908..9f3a96a 100644 --- a/ratatoeskr/sys/models.php +++ b/ratatoeskr/sys/models.php @@ -88,14 +88,23 @@ abstract class BySQLRowEnabled } } +/* + * Class: KVStorage + * An abstract class for a KVStorage. + * + * See also: + * , + */ abstract class KVStorage implements Countable, ArrayAccess, Iterator { private $keybuffer; private $counter; private $prepared_queries; + private $silent_mode; final protected function init($sqltable, $common_fields) { + $this->silent_mode = False; $this->keybuffer = array(); $selector = "WHERE " . (empty($common_fields) ? 1 : implode(" AND ", array_map(function($x) { return qdb_fmt("`{$x[0]}` = {$x[1]}", $x[2]); }, $common_fields))); @@ -117,6 +126,17 @@ abstract class KVStorage implements Countable, ArrayAccess, Iterator $this->counter = 0; } + /* + * Functions: Silent mode + * If the silent mode is enabled, the KVStorage behaves even more like a PHP array, i.e. it just returns NULL, + * if a unknown key was requested and does not throw an DoesNotExistError Exception. + * + * enable_silent_mode - Enable the silent mode. + * disable_silent_mode - Disable the silent mode (default). + */ + final public function enable_silent_mode() { $this->silent_mode = True; } + final public function disable_silent_mode() { $this->silent_mode = False; } + /* Countable interface implementation */ final public function count() { return count($this->keybuffer); } @@ -130,6 +150,8 @@ abstract class KVStorage implements Countable, ArrayAccess, Iterator $sqlrow = mysql_fetch_assoc($result); return unserialize(base64_decode($sqlrow["value"])); } + elseif($this->silent_mode) + return NULL; else throw new DoesNotExistError(); } @@ -844,6 +866,8 @@ $ratatoeskr_settings = Settings::get_instance(); * A Key-Value-Storage for Plugins * Can be accessed like an array. * Keys are strings and Values can be everything serialize() can process. + * + * Extends the abstract class. */ class PluginKVStorage extends KVStorage { @@ -2634,6 +2658,8 @@ WHERE " . implode(" AND ", $subqueries) . " $sorting"); * A Key-Value-Storage assigned to Articles for plugins to store additional data. * Can be accessed like an array. * Keys are strings and Values can be everything serialize() can process. + * + * Extends the abstract class. */ class ArticleExtradata extends KVStorage { -- cgit v1.2.3-54-g00ecf From 793b0e31beb22fe33402c8a9ceebf47a5a950635 Mon Sep 17 00:00:00 2001 From: Kevin Chabowski Date: Sun, 20 May 2012 13:00:31 +0200 Subject: Plugins can now hook into the Article editor. * Plugins can display additional fields in the article editor. * Plugins can perform actions when saving an article and even veto the saving. * Plugins can get their ArticleExtradata objects. --- ratatoeskr/backend.php | 79 +++++++++++++++++----- ratatoeskr/frontend.php | 15 ++-- ratatoeskr/sys/models.php | 15 ++++ ratatoeskr/sys/plugin_api.php | 55 +++++++++++++-- .../src/systemtemplates/content_write.html | 5 ++ 5 files changed, 142 insertions(+), 27 deletions(-) diff --git a/ratatoeskr/backend.php b/ratatoeskr/backend.php index 19d3891..a1ab570 100644 --- a/ratatoeskr/backend.php +++ b/ratatoeskr/backend.php @@ -12,6 +12,7 @@ require_once(dirname(__FILE__) . "/sys/models.php"); require_once(dirname(__FILE__) . "/sys/pwhash.php"); require_once(dirname(__FILE__) . "/sys/textprocessors.php"); +require_once(dirname(__FILE__) . "/sys/plugin_api.php"); require_once(dirname(__FILE__) . "/languages.php"); $admin_grp = NULL; @@ -116,6 +117,7 @@ $backend_subactions = url_action_subactions(array( } } load_language(); + /* If we are here, user is not logged in... */ $url_next = array("login"); }, @@ -159,7 +161,7 @@ $backend_subactions = url_action_subactions(array( "content" => url_action_subactions(array( "write" => function(&$data, $url_now, &$url_next) { - global $ste, $translation, $textprocessors, $ratatoeskr_settings, $languages; + global $ste, $translation, $textprocessors, $ratatoeskr_settings, $languages, $articleeditor_plugins; list($article, $editlang) = array_slice($url_next, 0); if(!isset($editlang)) @@ -234,14 +236,21 @@ $backend_subactions = url_action_subactions(array( if(isset($_POST["saveaslang"])) $editlang = $_POST["saveaslang"]; } + else + { + /* Call articleeditor plugins */ + $article = empty($article) ? NULL : Article::by_urlname($article); + foreach($articleeditor_plugins as $plugin) + call_user_func($plugin["fx"], $article, False); + } function fill_article(&$article, $inputs, $editlang) { $article->urlname = $inputs["urlname"]; $article->status = $inputs["article_status"]; $article->timestamp = $inputs["date"]; - $article->title [$editlang] = new Translation($inputs["title"], "" ); - $article->text [$editlang] = new Translation($inputs["content"], $inputs["content_txtproc"]); + $article->title[$editlang] = new Translation($inputs["title"], ""); + $article->text[$editlang] = new Translation($inputs["content"], $inputs["content_txtproc"]); $article->excerpt[$editlang] = new Translation($inputs["excerpt"], $inputs["excerpt_txtproc"]); $article->set_tags(maketags($inputs["tags"], $editlang)); $article->set_section($inputs["article_section"]); @@ -256,15 +265,32 @@ $backend_subactions = url_action_subactions(array( { $article = Article::create($inputs["urlname"]); fill_article($article, $inputs, $editlang); - try + + /* Calling articleeditor plugins */ + $call_after_save = array(); + foreach($articleeditor_plugins as $plugin) { - $article->save(); - $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang); - $ste->vars["success"] = htmlesc($translation["article_save_success"]); + $result = call_user_func($plugin["fx"], $article, True); + if(is_string($result)) + $fail_reasons[] = $result; + elseif($result !== NULL) + $call_after_save[] = $result; } - catch(AlreadyExistsError $e) + + if(empty($fail_reasons)) { - $fail_reasons[] = $translation["article_name_already_in_use"]; + try + { + $article->save(); + foreach($call_after_save as $cb) + call_user_func($cb, $article); + $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang); + $ste->vars["success"] = htmlesc($translation["article_save_success"]); + } + catch(AlreadyExistsError $e) + { + $fail_reasons[] = $translation["article_name_already_in_use"]; + } } } } @@ -272,7 +298,8 @@ $backend_subactions = url_action_subactions(array( { try { - $article = Article::by_urlname($article); + if(!($article instanceof Article)) + $article = Article::by_urlname($article); } catch(DoesNotExistError $e) { @@ -282,15 +309,32 @@ $backend_subactions = url_action_subactions(array( if(empty($fail_reasons) and isset($_POST["save_article"])) { fill_article($article, $inputs, $editlang); - try + + /* Calling articleeditor plugins */ + $call_after_save = array(); + foreach($articleeditor_plugins as $plugin) { - $article->save(); - $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang); - $ste->vars["success"] = htmlesc($translation["article_save_success"]); + $result = call_user_func($plugin["fx"], $article, True); + if(is_string($result)) + $fail_reasons[] = $result; + elseif($result !== NULL) + $call_after_save[] = $result; } - catch(AlreadyExistsError $e) + + if(empty($fail_reasons)) { - $fail_reasons[] = $translation["article_name_already_in_use"]; + try + { + $article->save(); + foreach($call_after_save as $cb) + call_user_func($cb, $article); + $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang); + $ste->vars["success"] = htmlesc($translation["article_save_success"]); + } + catch(AlreadyExistsError $e) + { + $fail_reasons[] = $translation["article_name_already_in_use"]; + } } } @@ -366,6 +410,9 @@ $backend_subactions = url_action_subactions(array( $ste->vars[$k_out] = $inputs[$k_in]; } + /* Displaying article editor plugins */ + $ste->vars["displayed_plugins"] = array_map(function($x) { return array("label" => $x["label"], "template" => $x["template"]); }, array_filter($articleeditor_plugins, function($x) { return $x["display"]; })); + if(!empty($fail_reasons)) $ste->vars["failed"] = $fail_reasons; diff --git a/ratatoeskr/frontend.php b/ratatoeskr/frontend.php index 883f842..0bc083b 100644 --- a/ratatoeskr/frontend.php +++ b/ratatoeskr/frontend.php @@ -25,9 +25,10 @@ require_once(dirname(__FILE__) . "/libs/kses.php"); * * Returns: * Array with these fields: - * * id - * * name - * * title + * * id - The ID of the section. + * * name - The name of the section. + * * title - The title of the section in the current language + * * __obj - The
object. Useful for plugins, so they do not need to fetch the object from the database again. */ function section_transform_ste($section, $lang) { @@ -49,9 +50,10 @@ function section_transform_ste($section, $lang) * * Returns: * Array with these fields: - * * id - * * name - * * title + * * id - The ID of the tag. + * * name - The name of the tag. + * * title - The title in the current language. + * * __obj - The object. Useful for plugins, so they do not need to fetch the object from the database again. */ function tag_transform_ste($tag, $lang) { @@ -93,6 +95,7 @@ function tag_transform_ste($tag, $lang) * * tags (array(sub-fields: )) * * languages (array: language name=>url) * * comments_allowed + * * __obj - Useful for plugins, so they do not need to fetch the object from the database again. */ function article_transform_ste($article, $lang) { diff --git a/ratatoeskr/sys/models.php b/ratatoeskr/sys/models.php index 9f3a96a..3cda168 100644 --- a/ratatoeskr/sys/models.php +++ b/ratatoeskr/sys/models.php @@ -2605,6 +2605,21 @@ WHERE " . implode(" AND ", $subqueries) . " $sorting"); $this->section_obj = $section; } + /* + * Function: get_extradata + * Get the extradata for this article and the given plugin. + * + * Parameters: + * $plugin_id - The ID of the plugin. + * + * Returns: + * An object. + */ + public function get_extradata($plugin_id) + { + return new ArticleExtradata($this->id, $plugin_id); + } + /* * Function: save */ diff --git a/ratatoeskr/sys/plugin_api.php b/ratatoeskr/sys/plugin_api.php index f6d1c2d..cd3e42b 100644 --- a/ratatoeskr/sys/plugin_api.php +++ b/ratatoeskr/sys/plugin_api.php @@ -15,17 +15,18 @@ require_once(dirname(__FILE__) . "/../frontend.php"); /* * Constant: APIVERSION - * The current API version (5). + * The current API version (6). */ -define("APIVERSION", 5); +define("APIVERSION", 6); /* * Array: $api_compat * Array of API versions, this version is compatible to (including itself). */ -$api_compat = array(3, 4, 5); +$api_compat = array(3, 4, 5, 6); + +$url_handlers = array(); /* master URL handler */ -$url_handlers = array(); /* * Function: register_url_handler * Register an URL handler. See for more details. @@ -42,6 +43,8 @@ function register_url_handler($name, $callback) $pluginpages_handlers = array(); +$articleeditor_plugins = array(); + /* * Class: RatatoeskrPlugin * An abstract class to be extended in order to write your own Plugin. @@ -93,7 +96,7 @@ abstract class RatatoeskrPlugin final protected function get_custompub_dir() { return SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/public/" . $this->id; } final protected function get_custompub_url() { return $GLOBALS["rel_path_to_root"] . "/ratatoeskr/plugin_extradata/public/" . $this->id; } final protected function get_template_dir() { return "/plugintemplates/" . $this->id; } - + /* * Function: register_url_handler * Register a URL handler @@ -193,6 +196,33 @@ abstract class RatatoeskrPlugin }; } + /* + * Function: register_articleeditor_plugin + * Register a plugin for the article editor in the backend. + * + * Parameters: + * $label - The label for the plugin. + * $fx - A function that will be called during the articleeditor. + * This function must accept these parameters: + * * $article - An
object or NULL, if no Article is edited right now. + * * $about_to_save - If True, the article is about to be saved. + * If you want to veto the saving, return the rejection reason as a string. + * If everything is okay and you need to save additional data, return a callback function that accepts the saved
object (that callback should also write data back to the template, if necessary). + * If everything is okay and you do not need to save additional data, return NULL. + * $template - The name of the template to display in the editor, relative to your template directory. If you do not want to display anything, you can set ths to NULL. + */ + final protected function register_articleeditor_plugin($label, $fx, $template) + { + global $articleeditor_plugins; + + $articleeditor_plugins[] = array( + "label" => $label, + "fx" => $fx, + "template" => $this->get_template_dir() . "/" . $template, + "display" => $template != NULL + ); + } + /* * Function: get_backend_pluginpage_url * Get the URL to your backend plugin page. @@ -206,6 +236,21 @@ abstract class RatatoeskrPlugin return "$rel_path_to_root/backend/pluginpages/p{$this->id}"; } + /* + * Function: get_article_extradata + * Get the object for this plugin and the given article. + * + * Parameters: + * $article - An
object. + * + * Returns: + * An object for this plugin and the given article. + */ + final protected function get_article_extradata($article) + { + return new ArticleExtradata($article->get_id(), $this->id); + } + /* * Function: prepare_backend_pluginpage * Automatically sets the page title and highlights the menu-entry of your backend subpage. diff --git a/ratatoeskr/templates/src/systemtemplates/content_write.html b/ratatoeskr/templates/src/systemtemplates/content_write.html index 82c86c4..3d63c61 100644 --- a/ratatoeskr/templates/src/systemtemplates/content_write.html +++ b/ratatoeskr/templates/src/systemtemplates/content_write.html @@ -49,6 +49,11 @@

:

+ + +

$plugin[label]

+ +
-- cgit v1.2.3-54-g00ecf