1Wiki::Toolkit(3)      User Contributed Perl Documentation     Wiki::Toolkit(3)
2
3
4

NAME

6       Wiki::Toolkit - A toolkit for building Wikis.
7

DESCRIPTION

9       Helps you develop Wikis quickly by taking care of the boring bits for
10       you.  You will still need to write some code - this isn't an instant
11       Wiki.
12

SYNOPSIS

14         # Set up a wiki object with an SQLite storage backend, and an
15         # inverted index/DB_File search backend.  This store/search
16         # combination can be used on systems with no access to an actual
17         # database server.
18         #
19         # The database should already exist; it can be created using
20         # the supplied wiki-toolkit-setupdb script.
21
22         my $store     = Wiki::Toolkit::Store::SQLite->new(
23             dbname => "/home/wiki/store.db" );
24         my $indexdb   = Search::InvertedIndex::DB::DB_File_SplitHash->new(
25             -map_name  => "/home/wiki/indexes.db",
26             -lock_mode => "EX" );
27         my $search    = Wiki::Toolkit::Search::SII->new(
28             indexdb => $indexdb );
29
30         my $wiki      = Wiki::Toolkit->new( store     => $store,
31                                             search    => $search );
32
33         # Do all the CGI stuff.
34         my $q      = CGI->new;
35         my $action = $q->param("action");
36         my $node   = $q->param("node");
37
38         if ($action eq 'display') {
39             my $raw    = $wiki->retrieve_node($node);
40             my $cooked = $wiki->format($raw);
41             print_page(node    => $node,
42                        content => $cooked);
43         } elsif ($action eq 'preview') {
44             my $submitted_content = $q->param("content");
45             my $preview_html      = $wiki->format($submitted_content);
46             print_editform(node    => $node,
47                            content => $submitted_content,
48                            preview => $preview_html);
49         } elsif ($action eq 'commit') {
50             my $submitted_content = $q->param("content");
51             my $cksum = $q->param("checksum");
52             my $written = $wiki->write_node($node, $submitted_content, $cksum);
53             if ($written) {
54                 print_success($node);
55             } else {
56                 handle_conflict($node, $submitted_content);
57             }
58         }
59

METHODS

61       new
62             # Set up store, search and formatter objects.
63             my $store     = Wiki::Toolkit::Store::SQLite->new(
64                 dbname => "/home/wiki/store.db" );
65             my $indexdb   = Search::InvertedIndex::DB::DB_File_SplitHash->new(
66                 -map_name  => "/home/wiki/indexes.db",
67                 -lock_mode => "EX" );
68             my $search    = Wiki::Toolkit::Search::SII->new(
69                 indexdb => $indexdb );
70             my $formatter = My::HomeMade::Formatter->new;
71
72             my $wiki = Wiki::Toolkit->new(
73                 store     => $store,     # mandatory
74                 search    => $search,    # defaults to undef
75                 formatter => $formatter  # defaults to something suitable
76             );
77
78           "store" must be an object of type "Wiki::Toolkit::Store::*" and
79           "search" if supplied must be of type "Wiki::Toolkit::Search::*"
80           (though this isn't checked yet - FIXME). If "formatter" isn't
81           supplied, it defaults to an object of class
82           Wiki::Toolkit::Formatter::Default.
83
84           You can get a searchable Wiki up and running on a system without an
85           actual database server by using the SQLite storage backend with the
86           SII/DB_File search backend - cut and paste the lines above for a
87           quick start, and see Wiki::Toolkit::Store::SQLite,
88           Wiki::Toolkit::Search::SII, and
89           Search::InvertedIndex::DB::DB_File_SplitHash when you want to learn
90           the details.
91
92           "formatter" can be any object that behaves in the right way; this
93           essentially means that it needs to provide a "format" method which
94           takes in raw text and returns the formatted version. See
95           Wiki::Toolkit::Formatter::Default for a simple example. Note that
96           you can create a suitable object from a sub very quickly by using
97           Test::MockObject like so:
98
99             my $formatter = Test::MockObject->new();
100             $formatter->mock( 'format', sub { my ($self, $raw) = @_;
101                                               return uc( $raw );
102                                             } );
103
104           I'm not sure whether to put this in the module or not - it'd let
105           you just supply a sub instead of an object as the formatter, but it
106           feels wrong to be using a Test::* module in actual code.
107
108       retrieve_node
109             my $content = $wiki->retrieve_node($node);
110
111             # Or get additional data about the node as well.
112             my %node = $wiki->retrieve_node("HomePage");
113             print "Current Version: " . $node{version};
114
115             # Maybe we stored some of our own custom metadata too.
116             my $categories = $node{metadata}{category};
117             print "Categories: " . join(", ", @$categories);
118             print "Postcode: $node{metadata}{postcode}[0]";
119
120             # Or get an earlier version:
121             my %node = $wiki->retrieve_node( name    => "HomePage",
122                                              version => 2,
123                                             );
124             print $node{content};
125
126           In scalar context, returns the current (raw Wiki language) contents
127           of the specified node. In list context, returns a hash containing
128           the contents of the node plus additional data:
129
130           last_modified
131           version
132           checksum
133           metadata - a reference to a hash containing any caller-supplied
134           metadata sent along the last time the node was written
135
136           The "node" parameter is mandatory. The "version" parameter is
137           optional and defaults to the newest version. If the node hasn't
138           been created yet, it is considered to exist but be empty (this
139           behaviour might change).
140
141           Note on metadata - each hash value is returned as an array ref,
142           even if that type of metadata only has one value.
143
144       moderate_node
145             my $ok = $wiki->moderate_node(name => $node, version => $version);
146
147           Marks the given version of the node as moderated. If this is the
148           highest moderated version, then update the node's contents to hold
149           this version.
150
151       set_node_moderation
152             my $ok = $wiki->set_node_moderation(name => $node, required => $required);
153
154           Sets if a node requires moderation or not.  (Moderation is required
155           when $required is true).
156
157           When moderation is required, new versions of a node will sit about
158           until they're tagged as moderated, when they will become the new
159           node.
160
161       rename_node
162             my $ok = $wiki->rename_node(old_name => $old_name, new_name => $new_name, create_new_versions => $create_new_versions );
163
164           Renames a node, updating any references to it as required.
165
166           Uses the internal_links table to identify the nodes that link to
167           this one, and re-writes any wiki links in these to point to the new
168           name. If required, it can mark these updates to other pages as a
169           new version.
170
171       verify_checksum
172             my $ok = $wiki->verify_checksum($node, $checksum);
173
174           Sees whether your checksum is current for the given node. Returns
175           true if so, false if not.
176
177           NOTE: Be aware that when called directly and without locking, this
178           might not be accurate, since there is a small window between the
179           checking and the returning where the node might be changed, so
180           don't rely on it for safe commits; use "write_node" for that. It
181           can however be useful when previewing edits, for example.
182
183       list_backlinks
184             # List all nodes that link to the Home Page.
185             my @links = $wiki->list_backlinks( node => "Home Page" );
186
187       list_dangling_links
188             # List all nodes that have been linked to from other nodes but don't
189             # yet exist.
190             my @links = $wiki->list_dangling_links;
191
192           Each node is returned once only, regardless of how many other nodes
193           link to it.
194
195       list_all_nodes
196             my @nodes = $wiki->list_all_nodes;
197
198           Returns a list containing the name of every existing node.  The
199           list won't be in any kind of order; do any sorting in your calling
200           script.
201
202       list_nodes_by_metadata
203             # All documentation nodes.
204             my @nodes = $wiki->list_nodes_by_metadata(
205                 metadata_type  => "category",
206                 metadata_value => "documentation",
207                 ignore_case    => 1,   # optional but recommended (see below)
208             );
209
210             # All pubs in Hammersmith.
211             my @pubs = $wiki->list_nodes_by_metadata(
212                 metadata_type  => "category",
213                 metadata_value => "Pub",
214             );
215             my @hsm  = $wiki->list_nodes_by_metadata(
216                 metadata_type  => "category",
217                 metadata_value  => "Hammersmith",
218             );
219             my @results = my_l33t_method_for_ANDing_arrays( \@pubs, \@hsm );
220
221           Returns a list containing the name of every node whose caller-
222           supplied metadata matches the criteria given in the parameters.
223
224           By default, the case-sensitivity of both "metadata_type" and
225           "metadata_value" depends on your database - if it will return rows
226           with an attribute value of "Pubs" when you asked for "pubs", or
227           not.  If you supply a true value to the "ignore_case" parameter,
228           then you can be sure of its being case-insensitive.  This is
229           recommended.
230
231           If you don't supply any criteria then you'll get an empty list.
232
233           This is a really really really simple way of finding things; if you
234           want to be more complicated then you'll need to call the method
235           multiple times and combine the results yourself, or write a plugin.
236
237       list_nodes_by_missing_metadata Returns nodes where either the metadata
238       doesn't exist, or is blank
239           Unlike list_nodes_by_metadata(), the metadata value is optional
240           (the metadata type is required).
241
242             # All nodes missing documentation
243             my @nodes = $store->list_nodes_by_missing_metadata(
244                 metadata_type  => "category",
245                 metadata_value => "documentation",
246                 ignore_case    => 1,   # optional but recommended (see below)
247             );
248
249             # All nodes which don't have a latitude defined
250             my @nodes = $store->list_nodes_by_missing_metadata(
251                 metadata_type  => "latitude"
252             );
253
254       list_recent_changes
255           This is documented in Wiki::Toolkit::Store::Database; see there for
256           parameters and return values.  All parameters are passed through
257           directly to the store object, so, for example,
258
259             my @nodes = $wiki->list_recent_changes( days => 7 );
260
261           does exactly the same thing as
262
263             my @nodes = $wiki->store->list_recent_changes( days => 7 );
264
265       list_unmoderated_nodes
266             my @nodes = $wiki->list_unmoderated_nodes();
267             my @nodes = $wiki->list_unmoderated_nodes(
268                                                           only_where_latest => 1
269                                                       );
270
271             $nodes[0]->{'name'}              # The name of the node
272             $nodes[0]->{'node_id'}           # The id of the node
273             $nodes[0]->{'version'}           # The version in need of moderation
274             $nodes[0]->{'moderated_version'} # The newest moderated version
275
276             Fetches details of all the node versions that require moderation (id,
277              name, version, and latest moderated version).
278
279             If only_where_latest is set, then only the latest version of nodes where
280              the latest version needs moderating are returned.
281             Otherwise, all node versions (including old ones, and possibly multiple
282              per node) are returned.
283
284       list_node_all_versions
285             my @versions = $wiki->list_node_all_versions("HomePage");
286
287             my @versions = $wiki->list_node_all_versions(
288                                                           name => 'HomePage',
289                                                           with_content => 1,
290                                                           with_metadata => 0
291                            );
292
293           Returns all the versions of a node, optionally including the
294           content and metadata, as an array of hashes (newest versions
295           first).
296
297       list_last_version_before List the last version of every node before a
298       given date. If no version existed before that date, will return undef
299       for version. Returns a hash of id, name, version and date
300               my @nv = $wiki->list_last_version_before('2007-01-02 10:34:11')
301               foreach my $data (@nv) {
302
303               }
304
305       node_exists
306             my $ok = $wiki->node_exists( "Wombat Defenestration" );
307
308             # or ignore case - optional but recommended
309             my $ok = $wiki->node_exists(
310                                          name        => "monkey brains",
311                                          ignore_case => 1,
312                                        );
313
314           Returns true if the node has ever been created (even if it is
315           currently empty), and false otherwise.
316
317           By default, the case-sensitivity of "node_exists" depends on your
318           store backend.  If you supply a true value to the "ignore_case"
319           parameter, then you can be sure of its being case-insensitive.
320           This is recommended.
321
322       node_required_moderation
323             my $needs = $wiki->node_required_moderation( "Wombat Defenestration" );
324
325           Returns true if the node exists and requires moderation, and false
326           otherwise.
327
328       delete_node
329             $wiki->delete_node( name => "Home Page", version => 15 );
330
331           "version" is optional.  If it is supplied then only that version of
332           the node will be deleted.  Otherwise the node and all its history
333           will be completely deleted.
334
335           Doesn't do any locking though - to fix? You probably don't want to
336           let anyone except Wiki admins call this. You may not want to use it
337           at all.
338
339           Croaks on error, silently does nothing if the node or version
340           doesn't exist, returns true if no error.
341
342       search_nodes
343             # Find all the nodes which contain the word 'expert'.
344             my %results = $wiki->search_nodes('expert');
345
346           Returns a (possibly empty) hash whose keys are the node names and
347           whose values are the scores in some kind of relevance-scoring
348           system I haven't entirely come up with yet. For OR searches, this
349           could initially be the number of terms that appear in the node,
350           perhaps.
351
352           Defaults to AND searches (if $and_or is not supplied, or is
353           anything other than "OR" or "or").
354
355           Searches are case-insensitive.
356
357           Croaks if you haven't defined a search backend.
358
359       supports_phrase_searches
360             if ( $wiki->supports_phrase_searches ) {
361                 return $wiki->search_nodes( '"fox in socks"' );
362             }
363
364           Returns true if your chosen search backend supports phrase
365           searching, and false otherwise.
366
367       supports_fuzzy_searches
368             if ( $wiki->supports_fuzzy_searches ) {
369                 return $wiki->fuzzy_title_match( 'Kings Cross, St Pancreas' );
370             }
371
372           Returns true if your chosen search backend supports fuzzy title
373           searching, and false otherwise.
374
375       fuzzy_title_match
376           NOTE: This section of the documentation assumes you are using a
377           search engine which supports fuzzy matching. (See above.) The
378           Wiki::Toolkit::Search::DBIxFTS backend in particular does not.
379
380             $wiki->write_node( "King's Cross St Pancras", "A station." );
381             my %matches = $wiki->fuzzy_title_match( "Kings Cross St. Pancras" );
382
383           Returns a (possibly empty) hash whose keys are the node names and
384           whose values are the scores in some kind of relevance-scoring
385           system I haven't entirely come up with yet.
386
387           Note that even if an exact match is found, any other similar enough
388           matches will also be returned. However, any exact match is
389           guaranteed to have the highest relevance score.
390
391           The matching is done against "canonicalised" forms of the search
392           string and the node titles in the database: stripping vowels,
393           repeated letters and non-word characters, and lowercasing.
394
395           Croaks if you haven't defined a search backend.
396
397       register_plugin
398             my $plugin = Wiki::Toolkit::Plugin::Foo->new;
399             $wiki->register_plugin( plugin => $plugin );
400
401           Registers the plugin with the wiki as one that needs to be informed
402           when we write a node.
403
404           If the plugin "isa" Wiki::Toolkit::Plugin, calls the methods set up
405           by that parent class to let it know about the backend store, search
406           and formatter objects.
407
408           Finally, calls the plugin class's "on_register" method, which
409           should be used to check tables are set up etc. Note that because of
410           the order these things are done in, "on_register" for
411           Wiki::Toolkit::Plugin subclasses can use the "datastore", "indexer"
412           and "formatter" methods as it needs to.
413
414       get_registered_plugins
415             my @plugins = $wiki->get_registered_plugins;
416
417           Returns an array of plugin objects.
418
419       write_node
420             my $written = $wiki->write_node($node, $content, $checksum, \%metadata, $requires_moderation);
421             if ($written) {
422                 display_node($node);
423             } else {
424                 handle_conflict();
425             }
426
427           Writes the specified content into the specified node in the backend
428           storage; and indexes/reindexes the node in the search indexes (if a
429           search is set up); calls "post_write" on any registered plugins.
430
431           Note that you can blank out a node without deleting it by passing
432           the empty string as $content, if you want to.
433
434           If you expect the node to already exist, you must supply a
435           checksum, and the node is write-locked until either your checksum
436           has been proved old, or your checksum has been accepted and your
437           change committed.  If no checksum is supplied, and the node is
438           found to already exist and be nonempty, a conflict will be raised.
439
440           The first two parameters are mandatory, the others optional. If you
441           want to supply metadata but have no checksum (for a newly-created
442           node), supply a checksum of "undef".
443
444           The final parameter, $requires_moderation (which defaults to
445           false), is ignored except on new nodes. For existing nodes, use
446           $wiki->toggle_node_moderation to change the node moderation flag.
447
448           Returns the version of the updated node on success, 0 on conflict,
449           croaks on error.
450
451           Note on the metadata hashref: Any data in here that you wish to
452           access directly later must be a key-value pair in which the value
453           is either a scalar or a reference to an array of scalars.  For
454           example:
455
456             $wiki->write_node( "Calthorpe Arms", "nice pub", $checksum,
457                                { category => [ "Pubs", "Bloomsbury" ],
458                                  postcode => "WC1X 8JR" } );
459
460             # and later
461
462             my @nodes = $wiki->list_nodes_by_metadata(
463                 metadata_type  => "category",
464                 metadata_value => "Pubs"             );
465
466           For more advanced usage (passing data through to registered
467           plugins) you may if you wish pass key-value pairs in which the
468           value is a hashref or an array of hashrefs. The data in the
469           hashrefs will not be stored as metadata; it will be checksummed and
470           the checksum will be stored instead. Such data can only be accessed
471           via plugins.
472
473       format
474             my $cooked = $wiki->format($raw, $metadata);
475
476           Passed straight through to your chosen formatter object. You do not
477           have to supply the $metadata hashref, but if your formatter allows
478           node metadata to affect the rendering of the node then you will
479           want to.
480
481       store
482             my $store  = $wiki->store;
483             my $dbname = eval { $wiki->store->dbname; }
484               or warn "Not a DB backend";
485
486           Returns the storage backend object.
487
488       search_obj
489             my $search_obj = $wiki->search_obj;
490
491           Returns the search backend object.
492
493       formatter
494             my $formatter = $wiki->formatter;
495
496           Returns the formatter backend object.
497

SEE ALSO

499       For a very quick Wiki startup without any of that icky programming
500       stuff, see Tom Insam's Wiki::Toolkit::Kwiki, an instant wiki based on
501       Wiki::Toolkit.
502
503       Or for the specialised application of a wiki about a city, see the
504       OpenGuides distribution.
505
506       Wiki::Toolkit allows you to use different formatting modules.
507       Text::WikiFormat might be useful for anyone wanting to write a custom
508       formatter. Existing formatters include:
509
510       •   Wiki::Toolkit::Formatter::Default (in this distro)
511
512       •   Wiki::Toolkit::Formatter::Pod
513
514       •   Wiki::Toolkit::Formatter::UseMod
515
516       There's currently a choice of three storage backends - all database-
517       backed.
518
519       •   Wiki::Toolkit::Store::MySQL (in this distro)
520
521       •   Wiki::Toolkit::Store::Pg (in this distro)
522
523       •   Wiki::Toolkit::Store::SQLite (in this distro)
524
525       •   Wiki::Toolkit::Store::Database (parent class for the above - in
526           this distro)
527
528       A search backend is optional:
529
530       •   Wiki::Toolkit::Search::DBIxFTS (in this distro, uses
531           DBIx::FullTextSearch)
532
533       •   Wiki::Toolkit::Search::SII (in this distro, uses
534           Search::InvertedIndex)
535
536       Standalone plugins can also be written - currently they should only
537       read from the backend storage, but write access guidelines are coming
538       soon. Plugins written so far and available from CPAN:
539
540       •   Wiki::Toolkit::Plugin::GeoCache
541
542       •   Wiki::Toolkit::Plugin::Categoriser
543
544       •   Wiki::Toolkit::Plugin::Locator::UK
545
546       •   Wiki::Toolkit::Plugin::RSS::ModWiki
547
548       If writing a plugin you might want an easy way to run tests for it on
549       all possible backends:
550
551       •   Wiki::Toolkit::TestConfig::Utilities (in this distro)
552
553       Other ways to implement Wikis in Perl include:
554
555       •   CGI::Kwiki (an instant wiki)
556
557       •   CGI::pWiki
558
559       •   AxKit::XSP::Wiki
560
561       •   Apache::MiniWiki
562
563       •   UseModWiki <http://usemod.com>
564
565       •   Chiq Chaq <http://chiqchaq.sourceforge.net/>
566

AUTHOR

568       Kake Pugh (kake@earth.li) and the Wiki::Toolkit team (including Nick
569       Burch and Dominic Hargreaves)
570

SUPPORT

572       Questions should go to cgi-wiki-dev@earth.li.
573
575            Copyright (C) 2002-2004 Kake Pugh.  All Rights Reserved.
576            Copyright (C) 2006-2013 the Wiki::Toolkit team. All Rights Reserved.
577
578       This module is free software; you can redistribute it and/or modify it
579       under the same terms as Perl itself.
580

FEEDBACK

582       The developer web site and bug tracker is at
583         http://www.wiki-toolkit.org/ - please file bugs there as appropriate.
584
585       You could also subscribe to the dev list at
586         http://www.earth.li/cgi-bin/mailman/listinfo/cgi-wiki-dev
587

BUGS

589       Bugs are documented at
590       <https://github.com/OpenGuides/Wiki-Toolkit/issues>
591

CREDITS

593       Various London.pm types helped out with code review, encouragement,
594       JFDI, style advice, code snippets, module recommendations, and so on;
595       far too many to name individually, but particularly Richard Clamp, Tony
596       Fisher, Mark Fowler, and Chris Ball.
597
598       blair christensen sent patches and gave me some good ideas. chromatic
599       continues to patiently apply my patches to Text::WikiFormat and help me
600       get it working in just the way I need. Paul Makepeace helped me add
601       support for connecting to non-local databases. Shevek has been prodding
602       me a lot lately. The OpenGuides team keep me well-supplied with
603       encouragement and bug reports.
604
605       Nick Burch has been leading the way with development leading up to the
606       release under the Wiki::Toolkit name.
607

GRATUITOUS PLUG

609       I'm only obsessed with Wikis because of the Open Guide to London --
610       <http://openguides.org/london/>
611
612
613
614perl v5.36.0                      2022-07-22                  Wiki::Toolkit(3)
Impressum