From 3d232f4b9342e1c5844b1bf4c6811e407ac30b63 Mon Sep 17 00:00:00 2001 From: EugenMayer Date: Tue, 16 Dec 2008 03:19:44 +0000 Subject: [PATCH] Item468: some minor bugfixes, cleaning up and doc additions git-svn-id: http://svn.foswiki.org/trunk/DBConnectorPlugin@1386 0b4bb1d4-4e5a-0410-9cc4-b2b747904278 --- data/System/DBConnectorPlugin.txt | 71 ++++++---- lib/Foswiki/Plugins/DBConnectorPlugin.pm | 133 ++++++++++-------- .../Plugins/DBConnectorPlugin/Config.spec | 2 +- 3 files changed, 122 insertions(+), 84 deletions(-) diff --git a/data/System/DBConnectorPlugin.txt b/data/System/DBConnectorPlugin.txt index b035f1a..d3bbcd2 100644 --- a/data/System/DBConnectorPlugin.txt +++ b/data/System/DBConnectorPlugin.txt @@ -7,7 +7,11 @@ Enables you to use simple methods to store and read data for topics, you dont wa ---++ Introduction This plugin enables you to store and read additional topic data in a variable backend very easy. The setup e.g. with SQLite should be straight forward and easy, -if not, leave me a note. In addition, the database is stored on filesystem-level in the working_areas and is backuped by the old great cp / rsync way like the general topic data +if not, leave me a note. In addition, the database is stored on filesystem-level in the working_areas and is backuped by the old great cp / rsync way like the general topic data. + +In addition, the Connector watches fields you choose to be updated including references on a topic, when this topic gets renamed in Foswiki. This is excatly the same behavior you get when renaming topics with searching for references, to rename them. +This behavior is enabled by default but can be disabled or only enabled for specific webs + ---++ Usage and Methods I will give a example on using this plugin with !SQLite when you used the optional example installation. There will be a table, named by the Web-Name with @@ -16,71 +20,82 @@ if not, leave me a note. In addition, the database is stored on filesystem-level * samplefield2: and text field You can also look at [[DBConnectorPluginCreateTableQuery][topic]] to see, which query was used to create the table and also modify it ----+++ getValues( $web, $topic, @fields ) -> ( %result ) +*Example application* +The plugin TopicSpecificNavigationPlugin is a good and simple example on how to use DBConnectorPlugin -get values for out of the database +---+++ getValues( $web, $topic, @fields ) -> ( %result ) + +get values for out of the database * =$web= - Web name, required, will be used as table * =$topic= Topic name, required, will be used as identifier/key - * =@fields= - Array of field names, optional. This fields are fetched out of the db -Return: =( %result )= Result, a hash with each fetched field-name as key + * =$fields= - reference on an array of field names, optional. This fields are fetched out of the db + * =$checkAccess= if this is zero, access is not checked +Return: =( %result )= Result, a hash with each fetched field-name as ke if you want to fetch fields ('samplefield1','samplefield2') from System.WebHome you call it : -
my %result getValues("System",'WebHome',('samplefield1','samplefield2')); accessing results this way print %result->{'bar'}; 
+
my %result getValues("System",'WebHome',('samplefield1','samplefield2'));
+accessing results this way
+print %result->{'bar'};
+
+ ----+++ updateValues( $web, $topic, $fiedValuePairs ) -> ( ) +---+++ updateValues( $web, $topic, $fiedValuePairs ) -> ( ) -get values for out of the database +get values for out of the database * =$web= - Web name, required, will be used as table * =$topic= Topic name, required, will be used as identifier/key * =$fiedValuePairs= reference to a hash, which has the field-name as key and the hash-value as field-value + * =$checkAccess= if this is zero, access is not checked Return: - if you want to update fields ('samplefield1','samplefield2') from System.WebHome you call it : -
my %pairs; %pairs->{'samplefield1'} = 20; %pairs->{'samplefield2'} = "myvalue1"; # Attention, you must use a reference! updateValues("System",'WebHome',\%pairs); 
+
+my %pairs;
+%pairs->{'samplefield1'} = 20;
+%pairs->{'samplefield2'} = "myvalue1";
+# Attention, you must use a reference!
+updateValues("System",'WebHome',\%pairs);
+
----+++ createdb rest handler +---+++ deleteEntry( $web, $topic ) -> ( ) + +deletes an entry out of the database $web, identiefied by $topic + * =$web= - Web name, required, will be used as table + * =$topic= Topic name, required, will be used as identifier/key -if you want to create a initial table for a web, where informations can be stored for topics, you got to run this rest handler to initialize/create it. The query defined on topic !DBConnectorPluginCreateTableQuery is used as a template for the query. +---+++ _createDB( $session ) -> ( ) + +if you want to create a initial table for a web, where informations can be stored for topics, you got to run this rest handler to initialize/create it. The query defined on topic Syste.DBConnectorPluginCreateTableQuery is used as a template for the query. * %TABLENAME% gets expanded to the corresponding Web, when you create the table; * %TOPICNAME% gets expanded to the topic. This should be actually always be a existing topic. In normal cases, this value is not needed in the template# * %DBCONTABLEKEYFIELD% gets expanded to the primary key which is defined in the Configuration-Center $Foswiki::cfg{Plugins}{DBConnectorPlugin}{TableKeyField} -__you can disallow the creation of table by unchecking $Foswiki::cfg{Plugins}{DBConnectorPlugin}{allowCreatedb} in the Configuration-Center__ - +_you can disallow the creatinof table with unchecking $Foswiki::cfg{Plugins}{DBConnectorPlugin}{allowCreatedb} in the Configuration-Center _ you call the rest handler this way, creating a data for the web "TheWeb"
%SCRIPTURL{"rest"}%/DBConnectorPlugin/createdb?topic=TheWeb.WebHome 
-__Attention: If the table exists already, it will not be touched. No data will be erase or even a other table created__ - ----+++ sendQry( $query ) -> ( $results) - -use this method to simply run querys on the database. You get a result like described by getValues - * $query Complete SQL query; -Return: returning a reference on an hash which has an integer-key for each row fetch, for each of this values a hash is stored, by {fieldname} = value like in getValues - ---++ Installation instructions * just use the installer attached to the topic or even easier, use the configure-system/Extension to easy install it trough an user-interface ---+++ Configuration - * Use the Configuration Center ( bin/configure ) to configure the driver you want to use, the DSN and user / password + * Use the Configuration Center ( bin/configure ) to configure the driver you want to use, the DSN. Decide if you want links to be auto updated, if a topic gets removed and whic webs should be searched for such topic-references ---+++ Optional: Create table 1 check this [[DBConnectorPluginCreateTableQuery][topic]] to see, which query is used to create the table for a web, where information is stored 1 click [[%SCRIPTURL{"rest"}%/DBConnectorPlugin/createdb?topic=System.WebHome][here]] to create a test table for the System-Web - 1 no you can query the database with update and get queries like described abo -__Note:__ You do not need to install anything on the browser to use this Plugin. The following instructions are for the administrator who installs the Plugin on the server where Foswiki is running. + 1 now you can query the database with update and get queries like described above +__Note:__ You do not need to install anything on the browser to use this plugin. The following instructions are for the administrator who installs the Plugin on the server where Foswiki is running. ---++ !ToDo - * provide easy way to remove values * provide easy way to set fields for a topic to the default-values - * Build an example-application * auto-creating of tables for all webs and stuff like that - * Add "onRename" and "onMove" and "onRemove" handler to keep the whole thing sync + | Plugin Author: | Foswiki:Main.EugenMayer | | Copyright: | © Impressive.media | | License: | GPL ([[http://www.gnu.org/copyleft/gpl.html][GNU General Public License]]) | -| Plugin Version: | 15 Dez 2008 (V0.1) | +| Plugin Version: | 16 Dez 2008 (V0.2) | | Change History: | | +| 16 Dez 2008: | extended functionality to update references(links) on topics, when this topcis are renamed. Tested, bugixed. | | 15 Dez 2008: | initial release | | Foswiki Dependency: | | | CPAN Dependencies: | DBI | diff --git a/lib/Foswiki/Plugins/DBConnectorPlugin.pm b/lib/Foswiki/Plugins/DBConnectorPlugin.pm index 269c167..f253027 100644 --- a/lib/Foswiki/Plugins/DBConnectorPlugin.pm +++ b/lib/Foswiki/Plugins/DBConnectorPlugin.pm @@ -28,6 +28,7 @@ use DBI; use Error qw(:try); + # $VERSION is referred to by Foswiki, and is the only global variable that # *must* exist in this package. use vars qw( $VERSION $RELEASE $SHORTDESCRIPTION $debug $pluginName $NO_PREFS_IN_TOPIC ); @@ -39,7 +40,7 @@ $VERSION = '$Rev: 12445$'; # This is a free-form string you can use to "name" your own plugin version. # It is *not* used by the build automation tools, but is reported as part # of the version number in PLUGINDESCRIPTIONS. -$RELEASE = '0.1'; +$RELEASE = '0.2'; # Short description of this plugin # One line description, is shown in the %FoswikiWEB%.TextFormattingRules topic: @@ -55,6 +56,7 @@ our $curWeb; our $curTopic; our $curUser; + sub initPlugin { my( $topic, $web, $user, $installWeb ) = @_; @@ -63,6 +65,9 @@ sub initPlugin { $TableKeyField = $Foswiki::cfg{Plugins}{DBConnectorPlugin}{TableKeyField}; # Plugin correctly initialized _connect(); + # setup a error handler + $DBC_con->{HandleError} = sub { _warn(shift) }; + $curWeb = $web; $curTopic = $topic; $curUser = $user; @@ -144,15 +149,17 @@ my %pairs; updateValues("System",'WebHome',\%pairs); =cut + sub updateValues { my $web = shift; my $topic = shift; my $fiedValuePairs = shift; my $checkAccess = shift || 1; _debug("Updating values inserted",keys %{$fiedValuePairs}); + #checking acces if i have to. Also checking if the table exists if($checkAccess && !_hasAccess("CHANGE")) { # no access; - return undef; + return (); } _createEntryForTopicIfNotExitent($web,$topic); # craete a field list with placeholder(?), while each field is surrounded by ` @@ -160,13 +167,13 @@ sub updateValues { my $qry = qq(UPDATE $web SET $values WHERE `$TableKeyField`='$topic' ); _debug("Query: $qry"); - my $qryobj = $DBC_con->prepare($qry); + my $qryobj = eval { $DBC_con->prepare($qry) }; unless ($qryobj) { - _warn("could not prepare qry ($qry), table missing? \nerror:".$DBC_con->errstr); + _warn("could not prepare qry (".$DBC_con->Statement()."), table missing? \nerror:".$DBC_con->errstr); return; } # now insert the values for the placeholders into the query - $qryobj->execute(values %{$fiedValuePairs}) or _warn("could not insert values for $web.$topic \nerror:".$qryobj->err); + eval { $qryobj->execute(values %{$fiedValuePairs}) }or _warn("could not insert values for $web.$topic \nerror:".$DBC_con->errstr,values %{$fiedValuePairs}); $qryobj->finish(); _debug("Values upated"); } @@ -174,6 +181,7 @@ sub updateValues { sub _createEntryForTopicIfNotExitent { my ( $web, $topic ) = @_; _debug("Creating topic entry if not existent"); + my $created = 0; if(!getValues($web,$topic,["topic_id"],0)) { my $qry = "INSERT into $web (`$TableKeyField`) VALUES ('$topic')"; @@ -185,6 +193,59 @@ sub _createEntryForTopicIfNotExitent { } +=begin TML +---+++ sendQry( $query ) -> ( $results) + +use this method to simply run querys on the database. You get a result like described by getValues + * $query Complete SQL query; +Return: returning a hash which has an the topic-identiefer as key for each row fetch, for each of this values a hash is stored, by {fieldname} = value like in getValues +=cut + +sub sendQry { + my $qry = shift; + my $table = shift || ""; + + _debug("Sending direct query '$qry'"); + # TODO: add access control? how? + + my $qryobj = $DBC_con->prepare($qry); + my $results; + if(! (defined $qryobj)){ + _warn("could not prepare qry ($qry), table missing? \nerror:".$DBC_con->errstr); + return (); + + } + + + # now insert the values for the placeholders into the query + $qryobj->execute() or _warn("could not run direct query".$qry); + $results = $qryobj->fetchall_hashref($TableKeyField); + # returning the values as {fieldname} = value pairs. If no row could be fetched, this result is undef + _debug("Returned values:", values(%{ $results })); + $qryobj->finish; + return %{$results}; +} + +=begin TML +---+++ deleteEntry( $web, $topic ) -> ( ) + +deletes an entry out of the database $web, identiefied by $topic + * =$web= - Web name, required, will be used as table + * =$topic= Topic name, required, will be used as identifier/key +=cut + +sub deleteEntry{ + my $web = shift; + my $topic = shift; + my $checkAccess = shift || 1; + + if($checkAccess && !_hasAccess("CHANGE")) { + # no access; + return; + } + + $DBC_con->do("DELETE from `$web` where `$TableKeyField`='$topic'"); +} =begin TML @@ -198,7 +259,6 @@ if you want to create a initial table for a web, where informations can be store you call the rest handler this way, creating a data for the web "TheWeb"
%SCRIPTURL{"rest"}%/DBConnectorPlugin/createdb?topic=TheWeb.WebHome 
-__ Attention: If the table exists allready, it will not be touched. No data will be erase or even a other table created __ =cut sub _createDB { # TODO: test if there is allready a database, if yes, do not create anything and cancel @@ -254,45 +314,6 @@ sub _createDB { } -=begin TML ----+++ sendQry( $query ) -> ( $results) - -use this method to simply run querys on the database. You get a result like described by getValues - * $query Complete SQL query; -Return: returning a hash which has an the topic-identiefer as key for each row fetch, for each of this values a hash is stored, by {fieldname} = value like in getValues -=cut - -sub sendQry { - my $qry = shift; - # TODO: add access control? how? - my $qryobj = $DBC_con->prepare($qry); - my $results; - unless ($qryobj) { - _warn("could not prepare qry ($qry), table missing? \nerror:".$DBC_con->errstr); - return $results; - } - - _debug("Runnging direct query '$qry'"); - # now insert the values for the placeholders into the query - $qryobj->execute() or _warn("could not run direct query".$qry); - $results = $qryobj->fetchall_hashref($TableKeyField); - # returning the values as {fieldname} = value pairs. If no row could be fetched, this result is undef - _debug("Returned values:", values(%{ $results })); - $qryobj->finish; - return %{$results}; -} - -sub deleteEntry{ - my $web = shift; - my $topic = shift; - my $checkAccess = shift || 1; - if($checkAccess && !_hasAccess("CHANGE")) { - # no access; - return; - } - - $DBC_con->do("DELETE from `$web` where `$TableKeyField`='$topic'"); -} sub afterRenameHandler { @@ -331,7 +352,8 @@ sub afterRenameHandler { } _updateLinksInWebs($oldWeb, $oldTopic, $newWeb, $newTopic,\@webs); - } + } + return 1; } sub _updateLinksInWebs { @@ -340,11 +362,12 @@ sub _updateLinksInWebs { my @fieldlist = split(";",$Foswiki::cfg{Plugins}{DBConnectorPlugin}{UpdateOnInvolveFiedlsList}); my $pattern = '%'.$oldTopic.'%'; for(my $i = 0; $i < @fieldlist;$i++) { - @fieldlist[$i] = "`".@fieldlist[$i]."` LIKE '$pattern'"; + $fieldlist[$i] = "`".$fieldlist[$i]."` LIKE '$pattern'"; } foreach my $curWeb (@webs) { #get all entries needing an update - my %topicsNeedUpdates = sendQry("SELECT * FROM $curWeb WHERE ".join(" OR ", @fieldlist)); + _debug("getting topics needs to be fixed"); + my %topicsNeedUpdates = sendQry("SELECT * FROM $curWeb WHERE ".join(" OR ", @fieldlist), $curWeb); # go trough all topics needs an update if(%topicsNeedUpdates) { @@ -356,7 +379,7 @@ sub _updateLinksInWebs { _debug("fixed string is:\n".%topicsNeedUpdates->{$topicid}{$field}); } # update the entry in the DB. DB name is the current web, the identifier - updateValues($curWeb,$topicid, \%topicsNeedUpdates->{$topicid},0); + updateValues($curWeb,$topicid, $topicsNeedUpdates{$topicid},0); } } } @@ -367,7 +390,7 @@ sub _updateLinksInString { # TODO: this one should be checked for really working properly -> unit test $string =~ s/$oldWeb.$oldTopic/$newWeb.$newTopic/g; $string =~ s/$oldWeb\/$oldTopic/$newWeb\/$newTopic/g; - $string =~ s/$oldTopic/$newTopic/g; + $string =~ s/\b$oldTopic\b/\b$newTopic\b/g; return $string; } @@ -387,8 +410,8 @@ sub _debug sub _warn { - my $message = shift; - _debug($message); + my ($message,@param) = @_;; + _debug($message,@param); return TWiki::Func::writeWarning( $message ); } @@ -419,7 +442,7 @@ sub _connect { $DBC_con = DBI->connect( $dsn, "","", { - #RaiseError => 1, + RaiseError => 1, #PrintError => 1, FetchHashKeyName => NAME_lc => @_ @@ -430,8 +453,7 @@ sub _connect { _debug($error); throw Error::Simple($error); } - _debug("connection successfully"); - + _debug("connection successfully"); } sub _disconnect @@ -441,5 +463,6 @@ sub _disconnect $DBC_con->disconnect; } + 1; # vim: ft=perl foldmethod=marker \ No newline at end of file diff --git a/lib/Foswiki/Plugins/DBConnectorPlugin/Config.spec b/lib/Foswiki/Plugins/DBConnectorPlugin/Config.spec index 0e8f7d9..585ced8 100644 --- a/lib/Foswiki/Plugins/DBConnectorPlugin/Config.spec +++ b/lib/Foswiki/Plugins/DBConnectorPlugin/Config.spec @@ -25,7 +25,7 @@ $Foswiki::cfg{Plugins}{DBConnectorPlugin}{UpdateOnInvolveFiedlsList} = "subnavig # **STRING** # semicolon separated list of fields to include when updating links -$Foswiki::cfg{Plugins}{DBConnectorPlugin}{UpdateOnChangeWebList} = "*"; +$Foswiki::cfg{Plugins}{DBConnectorPlugin}{UpdateOnChangeWebList} = "Main;System"; #

Logging

# **BOOLEAN**