OSDN Git Service

Corresponds to event_PreComment.
[nucleus-jp/nucleus-plugins.git] / trunk / NP_List / NP_List.php
1 <?php
2 /**
3  * NP_List - Output various lists (with sub-plugins) for NucleusCMS
4  * 
5  * @author   yu
6  * @license  GNU GPL2
7  * @version  0.4
8  * 
9  * History
10  * v0.4   2008-05-14  Support itemvars. (yu)
11  *                    Add operator "=~"(LIKE) and "!~"(NOT LIKE) in filter. (yu)
12  *                    Fix filter bug ("!=" and "<>" weren't worked correctly). (yu)
13  * v0.32  2008-05-13  Support current memberid in getFilter(). (yu)
14  * v0.31  2008-05-08  Fix subplugin loader (NP_ListOf*Uppercase-first*). (yu)
15  * v0.3   2008-05-06  Refine subplugin class. (yu)
16  * v0.2   2008-05-02  Add new methods in subplugin class. (yu)
17  * v0.1   2008-04-30  First release. (yu)
18  */
19 class NP_List extends NucleusPlugin 
20 {
21     function getName() { return 'List'; }
22     function getAuthor()  { return 'yu'; }
23     function getURL() { return 'http://nucleus.datoka.jp/'; }
24     function getVersion() { return '0.4'; }
25     function getMinNucleusVersion() { return 330; }
26     function supportsFeature($what) { return (int)($what == 'SqlTablePrefix'); }
27 //  function getPluginDep() { return array('NP_Container'); }
28
29     function getDescription()
30     { 
31         return "Output various lists with sub-plugins.";
32     }
33     
34     var $params;
35     var $parts;
36     var $container;
37     
38     function init()
39     {
40         global $manager, $blogid;
41         
42         $this->params = array();
43         $this->parts = array();
44         
45         //if NP_Container is installed, hold reference of container instance.
46         if ($manager->pluginInstalled('NP_Container')) {
47             $this->container =& $manager->getPlugin('NP_Container');
48         }
49     }
50
51     function doItemVar(&$item)
52     {
53         global $blogid;
54         
55         //check container parts
56         $this->checkContainer();
57         
58         //init params
59         $this->params = array(); //initialize
60         $this->params['blogid'] = $blogid;
61         $this->params['skintype'] = 'item';
62         $this->params['item'] =& $item;
63         
64         //set params
65         $params = func_get_args();
66         array_shift($params); // remove item reference
67         $this->setParams($params);
68         
69         if ($this->params['type']) {
70             //dynamic call
71             $sub =& $this->callSubPlugin($this->params['type']);
72             if (is_object($sub)) $sub->main();
73         }
74     }
75     
76     function doSkinVar($skinType)
77     {
78         global $blogid;
79         
80         //check container parts
81         $this->checkContainer();
82         
83         //init params
84         $this->params = array(); //initialize
85         $this->params['blogid'] = $blogid;
86         $this->params['skintype'] = $skinType;
87         
88         //set params
89         $params = func_get_args();
90         array_shift($params); // remove skintype parameter
91         $this->setParams($params);
92         
93         if ($this->params['type']) {
94             //dynamic call
95             $sub =& $this->callSubPlugin($this->params['type']);
96             if (is_object($sub)) $sub->main();
97         }
98     }
99
100     /**
101      * parse param string and set them to $this->params
102      * 
103      * @access private
104      * @param  $params  array of parameters
105      * @return void
106      */
107     function setParams($params)
108     {
109         foreach ($params as $param) {
110             if ($flg_esc = (strpos($param, '\:') !== false)) $param = str_replace('\:', '[[ESCAPED-COLON]]', $param);
111             list($key, $value) = explode(':', $param);
112             if ($flg_esc) $value = str_replace('[[ESCAPED-COLON]]', ':', $value);
113             
114             switch ($key) {
115             case 'amount':
116                 $this->params['amount'] = (int)$value;
117                 break;
118             case 'len':
119             case 'length':
120                 $this->params['length'] = (int)$value;
121                 break;
122             case 'tpl':
123             case 'template':
124                 $this->params['template'] = $value;
125                 break;
126             default:
127                 $this->params[$key] = $value;
128             }
129         }
130     }
131     
132     /**
133      * check container parts in skin data
134      * 
135      * @access private
136      * @param  void
137      * @return void
138      */
139     function checkContainer()
140     {
141         static $flg_setparts;
142         
143         //get container parts (if exists)
144         if (isset($this->container) and !$flg_setparts) {
145             if ( is_array($cparts = $this->container->getParts($this->getName())) ) {
146                 foreach ($cparts as $ckey => $cval) {
147                     list($ckey2, $ckey3) = split('_', $ckey, 2);
148                     $this->parts[$ckey2][$ckey3] = $cval;
149                 }
150             }
151             $flg_setparts = true;
152         }
153     }
154     
155     /**
156      * generate/reuse an instance of sub plugin
157      * 
158      * @access public
159      * @param  $name  sub plugin name
160      * @return object reference
161      */
162     function &callSubPlugin($name) 
163     {
164         global $DIR_PLUGINS;
165         
166         if (empty($name) or preg_match('/[^0-9a-zA-Z_-]/', $name)) return false;
167         
168         $classname = 'NP_ListOf'. ucfirst($name);
169         if (!class_exists($classname)) {
170             $filename = $DIR_PLUGINS .'list/'. $classname .'.php';
171             if (!file_exists($filename)) {
172                 ACTIONLOG::add(WARNING, 'Plugin ' . $classname . ' was not loaded (File not found)');
173                 return false;
174             }
175             
176             include_once($filename);
177             
178             if (!class_exists($classname)) {
179                 ACTIONLOG::add(WARNING, 'Plugin ' . $classname . ' was not loaded (Class not found in file, possible parse error)');
180                 return false;
181             }
182         }
183         
184         //$classname::show(&$params); //PHP5.3~
185         //eval($classname .'::show($params);'); //call static class
186         
187         //eval('$sub =& '. $classname .'::getInstance($this);'); //get instance (singleton) from subplugin
188         eval('$sub =& $this->getInstance('.$classname.');'); //get instance (singleton) from instance manager
189         return $sub;
190         
191     }
192     
193     /**
194      * get an instance of the class (singleton)
195      * 
196      * @access private
197      * @param  $classname  class name
198      * @return object
199      */
200     function &getInstance($classname)
201     {
202         static $instances;
203         if ($instances[$classname] == null) {
204             $instances[$classname] =& new $classname();
205             $instances[$classname]->init($this);
206         }
207         else {
208             $instances[$classname]->reset(); //reset flags and template
209         }
210         
211         return $instances[$classname];
212     }
213     
214     /**
215      * get parsed filter string
216      * 
217      * @access public
218      * @param  $filter    filter string
219      * @param  $aliasmap  key 'search'  has an array of alias name
220      *                    key 'replace' has an array of column name
221      * @param  $current   an array of current values
222      * @return string
223      */
224     function getFilter($filter, $aliasmap, $current='') 
225     {
226         global $blogid, $catid, $memberid, $archive;
227         
228         $fparams = split(' ', $filter);
229         
230         if (! is_array($current)) {
231             $current = array(
232                 'blogid'   => $blogid,
233                 'catid'    => $catid,
234                 'memberid' => $memberid,
235                 'arcdate'  => $archive,
236                 );
237         }
238         
239         $filters = array();
240         foreach ($fparams as $fil) {
241             //replace '@' to current id
242             if (substr($fil, -1, 1) == '@') {
243                 preg_match('/^([a-z]+?)[!=<>]/', $fil, $match); //pick up left side
244                 if ($current[ $match[1] ]) {
245                     $fil = substr($fil, 0, -1) . $current[ $match[1] ];
246                 }
247                 else continue; //if current key/value is not defined, skip it.
248             }
249             
250             //replace because it can't use aliases in WHERE clause.
251             $fil = str_replace($aliasmap['search'], $aliasmap['replace'], $fil);
252             
253             $match = null;
254             preg_match('/^([a-zA-Z0-9(),._-]+?)(<>|>=|<=|!=|=~|!~|[=<>])(.+?)$/', $fil, $match);
255             
256             if (isset($match[1]) and isset($match[2]) and isset($match[3])) {
257                 if ($match[2] == '=~') $match[2] = ' LIKE ';
258                 if ($match[2] == '!~') $match[2] = ' NOT LIKE ';
259                 
260                 if (strpos($match[3], '|')) { //multiple values
261                     $values = split('\|', $match[3]);
262                     $f = array();
263                     foreach ($values as $v) {
264                         $f[] = $match[1] . $match[2] .'"'. mysql_real_escape_string($v) .'"';
265                     }
266                     if ($match[2] == '<>' or $match[2] == '!=' or $match[2] == '!~') $cond = ' AND '; //'NOT' condition
267                     else $cond = ' OR '; //normal condition
268                     $fil = '(' . join($cond, $f) . ')';
269                     $filters[] = $fil;
270                 }
271                 else { //single value 
272                     $fil = $match[1] . $match[2] .'"'. mysql_real_escape_string($match[3]) .'"';
273                     $filters[] = $fil;
274                 }
275             }
276             else {
277                 //wrong filter. skip it.
278             }
279         }
280         return join(' AND ', $filters);
281     }
282 }
283
284
285 /**
286  * base class of sub plugins
287  * 
288  * The class extended from this must implement main() method.
289  * 
290  * @abstract
291  * @see NP_List
292  */
293 class NP_ListOfSubPlugin
294 {
295     var $caller;
296     var $templates;
297     var $params;
298     var $flg;
299     
300     /**
301      * main method (*MUST* implement it)
302      * 
303      * @access public
304      * @param  void
305      * @return void
306      */
307     function main() 
308     {
309         echo 'echo of sub plugin.';
310     }
311     
312     /**
313      * get default template (implement it if needed)
314      * 
315      * @access private
316      * @param  void
317      * @return array
318      */
319     function _getDefaultTemplate() 
320     {
321         return array();
322     }
323     
324     /**
325      * initicialize a instance
326      * 
327      * Hold a reference of the caller object (NP_List).
328      * 
329      * @access public
330      * @param  &$oCaller  caller object
331      * @return void
332      * @see    NP_List::getInstance()
333      */
334     function init(&$oCaller) 
335     {
336         //set caller
337         $this->caller =& $oCaller;
338         
339         //set params
340         $this->params =& $this->caller->params;
341         
342         //set default params, flags and template
343         $this->reset();
344     }
345     
346     /**
347      * reset flags and template
348      * 
349      * @access public
350      * @param  void
351      * @return void
352      * @see    NP_List::getInstance()
353      */
354     function reset() 
355     {
356         //set default params
357         $this->_setDefaultParams();
358         
359         //set flags
360         $this->flg = $this->_getFlag($this->params['flag']);
361         
362         //set template
363         $this->_setTemplate();
364     }
365     
366     /**
367      * set template data to property $this->templates
368      * 
369      * If use standard template, get it from $manager.
370      * If use container, get it with param 'type' and 'tplprefix' (if it is set). 
371      * First, get default data. Second, get custom parts and merge them.
372      * 
373      * @access private
374      * @param  $forced  'true' forces to reset template
375      * @return void
376      */
377     function _setTemplate($forced = false) 
378     {
379         $default = $this->_getDefaultTemplate(); // sub plugin's original default template
380         
381         if ($this->params['template']) { //standard Nucleus template
382             $name = $this->params['template'];
383         }
384         else { //custom template (container)
385             $name = $this->params['tplprefix'] . strtoupper($this->params['type']);
386         }
387         
388         if ($forced or $this->templates[$name] == null) {
389             if ($this->params['template']) {
390                 global $manager;
391                 $custom =& $manager->getTemplate($name);
392             }
393             else {
394                 $custom = $this->caller->parts[$name]; //container parts
395             }
396             
397             if ($custom) {
398                 $this->templates[$name] = array_merge($default, $custom);
399             }
400             else {
401                 $this->templates[$name] = $default;
402             }
403         }
404     }
405     
406     /**
407      * get template data from property $this->templates
408      * 
409      * @access private
410      * @param  void
411      * @return array
412      */
413     function &_getTemplate() 
414     {
415         if ($this->params['template']) { //standard Nucleus template
416             $name = $this->params['template'];
417         }
418         else {
419             $name = $this->params['tplprefix'] . strtoupper($this->params['type']);
420         }
421         if (! $this->templates[$name]) {
422             $this->_setTemplate();
423         }
424         
425         return $this->templates[$name];
426     }
427     
428     /**
429      * get parsed filter string (wrapper)
430      * 
431      * @access private
432      * @param  $filter    filter string
433      * @param  $aliasmap  key 'search'  has an array of alias name
434      *                    key 'replace' has an array of column name
435      * @param  $current   an array of current values
436      * @return string
437      * @see    NP_List::getFilter()
438      */
439     function _getFilter($filter, $aliasmap, $current='') 
440     {
441         return $this->caller->getFilter($filter, $aliasmap, $current);
442     }
443     
444     /**
445      * get default params
446      * 
447      * @access private
448      * @param  void
449      * @return void
450      */
451     function _setDefaultParams() 
452     {
453         if (!isset($this->params['amount'])) $this->params['amount'] = 5;
454         if (!isset($this->params['length'])) $this->params['length'] = 25;
455         if (!isset($this->params['trimmarker'])) $this->params['trimmarker'] = '..';
456     }
457     
458     /**
459      * get flags
460      * 
461      * @access private
462      * @param  $str   flag string
463      * @return array
464      */
465     function _getFlag($str) 
466     {
467         $keys = split(' ', $str);
468         $flags = array();
469         foreach ($keys as $key) {
470             if (empty($key)) continue;
471             $flags[$key] = true;
472         }
473         
474         return $flags;
475     }
476     
477     /**
478      * scan a templatevar in the string
479      * 
480      * @access private
481      * @param $str  string
482      * @param $var  templatevar name
483      * @return bool
484      */
485     function _scan($str, $var)
486     {
487         return (strpos($str, $var) !== false);
488     }
489     
490     /**
491      * fill the template with variables (wrapper)
492      * 
493      * @access private
494      * @param $str   template string
495      * @param $vars  array of vars
496      * @return string
497      */
498     function _fill($str, $vars)
499     {
500         return TEMPLATE::fill($str, $vars);
501     }
502     
503     /**
504      * make class property
505      * 
506      * @access private
507      * @param $class  array (classname => condition)
508      * @return string
509      */
510     function _makeClassProperty($class)
511     {
512         $str = '';
513         if (!count($class)) return $str;
514         
515         foreach ($class as $name => $bool) {
516             if ($bool) $str .= ' '.$name;
517         }
518         if ($str) $str = ' class="'. ltrim($str) .'"';
519         
520         return $str;
521     }
522 }
523
524 ?>