I have a parser function #lookup that performs a database query, given a string key. When a wiki page contains {{#lookup:MyKey}}, the callback function looks up the associated value and uses StripState to place it into the article:
$parser->setFunctionHook('lookup', 'lookupCallback')); ... function lookupCallback($parser, $key) { $value = bigDatabaseQuery($key); return $parser->insertStripItem($value); }
This works fine, but when there are many #lookup calls on a single wiki page, we are making many database calls. So I'd like to collect all the keys from all the #lookup calls and perform a SINGLE database query "where key in ('key1', 'key2', ..., 'keyN')", then call insertStripItem() with each value. I can't seem to figure out how to architect this.
The callback (lookupCallback) is the ideal place to call insertStripItem with the looked-up values, since it places the UNIQ string in the right location in the article. But it also seems to be the only place that I can collect all the keys for performing the single SQL query. This is a chicken-and-egg problem. I can't seem to do the SQL query earlier than lookupCallback because if I do, this logic will run even when #lookup is not present.
Any advice on how to structure this? Thanks, DanB
On Tue, Mar 13, 2012 at 1:47 PM, Daniel Barrett danb@vistaprint.com wrote:
Any advice on how to structure this?
It sounds to me like stripState should have a way to change what a given strip marker's value is after you've already inserted it. That in combination with a hook that runs at the right time (after all the stripping is done but before the unstripping begins) would fix your problem AFAICT.
Roan
Roan writes:
It sounds to me like stripState should have a way to change what a given strip marker's value is after you've already inserted it. That in combination with a hook that runs at the right time (after all the stripping is done but before the unstripping begins) would fix your problem AFAICT.
Thanks Roan -- That would be a great solution, but the StripState class looks remarkably closed. All the members are protected (not public), and I didn't see any accessor functions to change the values of strip markers. There is a merge() function to merge a second StripState into the original, but I haven't figured out yet if this can do what I need.
DanB
I wrote:
...the StripState class looks remarkably closed. All the members are protected (not public), and I didn't see any accessor functions to change the values of strip markers.
I worked around this by defining a subclass of StripState, MyStripState, that can change those protected members:
class MyStripState extends StripState { function __construct($parentStripState) { // Copy the parent into me. // This will break if StripState gets new public/protected members. parent::__construct($parentStripState->prefix); $this->data = $parentStripState->data; $this->regex = $parentStripState->regex; $this->tempType = $parentStripState->tempType; $this->tempMergePrefix = $parentStripState->tempMergePrefix; } function modifyTheStuffINeed() { $this->data = whatever...; } }
Then I substitute my extended StripState class for the real one:
$wgHooks['InternalParseBeforeLinks'][] = 'MyParserFunction::render'; class MyParserFunction { static function render(&$parser, &$text, &$stripState) { $ss = new MyStripState ($stripState); $ssw-> modifyTheStuffINeed(); $stripState = $ss; return true; } }|
and it works. Hopefully not too much of a hack.
DanB
wikitech-l@lists.wikimedia.org