]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiPlugin.php
Updated comment for future users looking in this file for answers to why ||= doesn...
[SourceForge/phpwiki.git] / lib / WikiPlugin.php
1 <?php //-*-php-*-
2 rcs_id('$Id: WikiPlugin.php,v 1.9 2002-01-12 06:29:10 carstenklapp Exp $');
3
4 class WikiPlugin
5 {
6     function getDefaultArguments() {
7         return array();
8     }
9
10
11     // FIXME: args?
12     function run ($argstr, $request) {
13         trigger_error("WikiPlugin::run: pure virtual function",
14                       E_USER_ERROR);
15     }
16
17     /**
18      * Get name of plugin.
19      *
20      * This is used (by default) by getDefaultLinkArguments and
21      * getDefaultFormArguments to compute the default link/form
22      * targets.
23      *
24      * If you want to gettextify the name (probably a good idea),
25      * override this method in your plugin class, like:
26      * <pre>
27      *   function getName() { return _("MyPlugin"); }
28      * </pre>
29      *
30      * @return string plugin name/target.
31      */
32     function getName() {
33         return preg_replace('/^.*_/', '',  get_class($this));
34     }
35
36     function getDescription() {
37         return $this->getName();
38     }
39
40     
41     function getArgs($argstr, $request, $defaults = false) {
42         if ($defaults === false)
43             $defaults = $this->getDefaultArguments();
44
45         list ($argstr_args, $argstr_defaults) = $this->parseArgStr($argstr);
46
47         foreach ($defaults as $arg => $default_val) {
48             if (isset($argstr_args[$arg]))
49                 $args[$arg] = $argstr_args[$arg];
50             elseif ( ($argval = $request->getArg($arg)) !== false )
51                 $args[$arg] = $argval;
52             elseif (isset($argstr_defaults[$arg]))
53                 $args[$arg] = (string) $argstr_defaults[$arg];
54             else
55                 $args[$arg] = $default_val;
56
57             $args[$arg] = $this->expandArg($args[$arg], $request);
58             
59             unset($argstr_args[$arg]);
60             unset($argstr_defaults[$arg]);
61         }
62
63         foreach (array_merge($argstr_args, $argstr_defaults) as $arg => $val) {
64             trigger_error(sprintf(_("argument '%s' not declared by plugin"),$arg),
65                           E_USER_NOTICE);
66         }
67         
68         return $args;
69     }
70
71     function expandArg($argval, $request) {
72         return preg_replace('/\[(\w[\w\d]*)\]/e', '$request->getArg("$1")', $argval);
73     }
74     
75         
76     function parseArgStr($argstr) {
77         $arg_p = '\w+';
78         $op_p = '(?:\|\|)?=';
79         $word_p = '\S+';
80         $qq_p = '"[^"]*"';
81         $q_p = "'[^']*'";
82         $opt_ws = '\s*';
83         $argspec_p = "($arg_p) $opt_ws ($op_p) $opt_ws ($qq_p|$q_p|$word_p)";
84
85         $args = array();
86         $defaults = array();
87         
88         while (preg_match("/^$opt_ws $argspec_p $opt_ws/x", $argstr, $m)) {
89             @ list(,$arg,$op,$val) = $m;
90             $argstr = substr($argstr, strlen($m[0]));
91
92             // Remove quotes from string values.
93             if ($val && ($val[0] == '"' || $val[0] == "'"))
94                 $val = substr($val, 1, strlen($val) - 2);
95
96             if ($op == '=') {
97                 $args[$arg] = $val;
98             }
99             else {
100                 // NOTE: This does work for multiple args. Use the
101                 // separator character defined in your webserver
102                 // configuration, usually & or &amp; (See
103                 // http://www.htmlhelp.com/faq/cgifaq.4.html)
104                 // e.g. <plugin RecentChanges days||=1 show_all||=0 show_minor||=0>
105                 // url: RecentChanges?days=1&show_all=1&show_minor=0
106                 assert($op == '||=');
107                 $defaults[$arg] = $val;
108             }
109         }
110         
111         if ($argstr) {
112             trigger_error(sprintf(_("trailing cruft in plugin args: '%s'"),$argstr), E_USER_WARNING);
113         }
114
115         return array($args, $defaults);
116     }
117     
118
119     function getDefaultLinkArguments() {
120         return array('targetpage' => $this->getName(),
121                      'linktext' => $this->getName(),
122                      'description' => $this->getDescription(),
123                      'class' => 'wikiaction');
124     }
125     
126     function makeLink($argstr, $request) {
127         $defaults = $this->getDefaultArguments();
128         $link_defaults = $this->getDefaultLinkArguments();
129         $defaults = array_merge($defaults, $link_defaults);
130
131         $args = $this->getArgs($argstr, $request, $defaults);
132         $plugin = $this->getName();
133         
134         $query_args = array();
135         foreach ($args as $arg => $val) {
136             if (isset($link_defaults[$arg]))
137                 continue;
138             if ($val != $defaults[$arg])
139                 $query_args[$arg] = $val;
140         }
141         
142         $attr = array('href' => WikiURL($args['targetpage'], $query_args),
143                       'class' => $args['class']);
144
145         if ($args['description']) {
146             $attr['title'] = $args['description'];
147             $attr['onmouseover'] = sprintf("window.status='%s';return true;",
148                                            str_replace("'", "\\'", $args['description']));
149             $attr['onmouseout'] = "window.status='';return true;";
150         }
151         return QElement('a', $attr, $args['linktext']);
152     }
153
154     function getDefaultFormArguments() {
155         return array('targetpage' => $this->getName(),
156                      'buttontext' => $this->getName(),
157                      'class' => 'wikiaction',
158                      'method' => 'get',
159                      'textinput' => 's',
160                      'description' => false,
161                      'formsize' => 30);
162     }
163
164     function makeForm($argstr, $request) {
165         $form_defaults = $this->getDefaultFormArguments();
166         $defaults = array_merge($this->getDefaultArguments(),
167                                 $form_defaults);
168
169         $args = $this->getArgs($argstr, $request, $defaults);
170         $plugin = $this->getName();
171         $textinput = $args['textinput'];
172         assert(!empty($textinput) && isset($args['textinput']));
173
174         $formattr = array('action' => WikiURL($args['targetpage']),
175                           'method' => $args['method'],
176                           'class' => $args['class']);
177         $contents = '';
178         foreach ($args as $arg => $val) {
179             if (isset($form_defaults[$arg]))
180                 continue;
181             if ($arg != $textinput && $val == $defaults[$arg])
182                 continue;
183             
184             $attr = array('name' => $arg, 'value' => $val);
185             
186             if ($arg == $textinput) {
187                 //if ($inputs[$arg] == 'file')
188                 //    $attr['type'] = 'file';
189                 //else
190                 $attr['type'] = 'text';
191                 $attr['size'] = $args['formsize'];
192                 if ($args['description']) {
193                     $attr['title'] = $args['description'];
194                     $attr['onmouseover'] = sprintf("window.status='%s';return true;",
195                                                    str_replace("'", "\\'", $args['description']));
196                     $attr['onmouseout'] = "window.status='';return true;";
197                 }
198             }
199             else {
200                 $attr['type'] = 'hidden';
201             }
202             
203             $contents .= Element('input', $attr);
204
205             // FIXME: hackage
206             if ($attr['type'] == 'file') {
207                 $formattr['enctype'] = 'multipart/form-data';
208                 $formattr['method'] = 'post';
209                 $contents .= Element('input',
210                                      array('name' => 'MAX_FILE_SIZE',
211                                            'value' => MAX_UPLOAD_SIZE,
212                                            'type' => 'hidden'));
213             }
214         }
215
216         if (!empty($args['buttontext'])) {
217             $contents .= Element('input',
218                                  array('type' => 'submit',
219                                        'class' => 'button',
220                                        'value' => $args['buttontext']));
221         }
222
223         //FIXME: can we do without this table?
224         return Element('form', $formattr,
225                        Element('table',
226                                Element('tr',
227                                        Element('td', $contents))));
228     }
229 }
230
231 class WikiPluginLoader {
232     var $_errors;
233     
234     function expandPI($pi, $dbi, $request) {
235         if (!preg_match('/^\s*<\?(plugin(?:-form|-link)?)\s+(\w+)\s*(.*?)\s*\?>\s*$/s', $pi, $m))
236             return $this->_error(sprintf(_("Bad %s"),'PI'));
237
238         list(, $pi_name, $plugin_name, $plugin_args) = $m;
239         $plugin = $this->getPlugin($plugin_name);
240         if (!is_object($plugin)) {
241             return QElement($pi_name == 'plugin-link' ? 'span' : 'p',
242                             array('class' => 'plugin-error'),
243                             $this->getErrorDetail());
244         }
245         switch ($pi_name) {
246         case 'plugin':
247             return $plugin->run($dbi, $plugin_args, $request);
248         case 'plugin-link':
249             return $plugin->makeLink($plugin_args, $request);
250         case 'plugin-form':
251             return $plugin->makeForm($plugin_args, $request);
252         }
253     }
254     
255     function getPlugin($plugin_name) {
256
257         // Note that there seems to be no way to trap parse errors
258         // from this include.  (At least not via set_error_handler().)
259         $plugin_source = "lib/plugin/$plugin_name.php";
260         
261         if (!include_once("lib/plugin/$plugin_name.php")) {
262             if (!empty($GLOBALS['php_errormsg']))
263                 return $this->_error($GLOBALS['php_errormsg']);
264             // If the plugin source has already been included, the include_once()
265             // will fail, so we don't want to crap out just yet.
266             $include_failed = true;
267         } else {
268             // this avoids: lib/WikiPlugin.php:265: Notice[8]: Undefined variable: include_failed
269             $include_failed = false;
270         }
271         
272         $plugin_class = "WikiPlugin_$plugin_name";
273         if (!class_exists($plugin_class)) {
274             if ($include_failed)
275                 return $this->_error(sprintf(_("Include of '%s' failed"),$plugin_source));
276             return $this->_error(sprintf(_("%s: no such class"),$plugin_class));
277         }
278         
279     
280         $plugin = new $plugin_class;
281         if (!is_subclass_of($plugin, "WikiPlugin"))
282             return $this->_error(sprintf(_("%s: not a subclass of WikiPlugin"),$plugin_class));
283
284         return $plugin;
285     }
286
287     function getErrorDetail() {
288         return htmlspecialchars($this->_errors);
289     }
290     
291     function _error($message) {
292         $this->_errors = $message;
293         return false;
294     }
295
296         
297 };
298
299 // (c-file-style: "gnu")
300 // Local Variables:
301 // mode: php
302 // tab-width: 8
303 // c-basic-offset: 4
304 // c-hanging-comment-ender-p: nil
305 // indent-tabs-mode: nil
306 // End:   
307 ?>