Extension talk:LO Parser Functions

From mediawiki.org
Latest comment: 16 years ago by Sledged in topic Wrong Expr.php

Missing i18n File[edit]

I've had some real troubles with this extension. After a bit of hackery, I finally got it to work. Here are my files. Note that the instructions make no mention of the i18n file, so I had to develop a new one based on the ControlStructureFunctions i18n file:

LOParserFunctions.php
<?php
 
if ( !defined( 'MEDIAWIKI' ) ) {
        die( 'This file is a MediaWiki extension, it is not a valid entry point' );
}
 
$wgExtensionFunctions[] = 'wfSetupLOParserFunctions';
$wgExtensionCredits['parserhook'][] = array(
        'name' => 'Left-Over Parser Functions',
        'url' => 'http://www.mediawiki.org/wiki/Extension:LO_Parser_Functions',
        'author' => 'Tim Starling',
        'description' => 'Enhance parser with logical functions',
);
 
$wgHooks['LanguageGetMagic'][]       = 'wfLOParserFunctionsLanguageGetMagic';
 
class ExtLOParserFunctions {
        var $mExprParser;
        var $mTimeCache = array();
        var $mTimeChars = 0;
        var $mMaxTimeChars = 6000; # ~10 seconds
 
        function clearState() {
                $this->mTimeChars = 0;
                return true;
        }
 
        function &getExprParser() {
                if ( !isset( $this->mExprParser ) ) {
                        if ( !class_exists( 'ExprParser' ) ) {
                                require( dirname( __FILE__ ) . '/Expr.php' );
                                ExprParser::addMessages();
                        }
                        $this->mExprParser = new ExprParser;
                }
                return $this->mExprParser;
        }
 
        function expr( &$parser, $expr = '' ) {
                try {
                        return $this->getExprParser()->doExpression( $expr );
                } catch(ExprError $e) {
                        return $e->getMessage();
                }
        }
 
        /**
         * Returns the absolute path to a subpage, relative to the current article
         * title. Treats titles as slash-separated paths.
         *
         * Following subpage link syntax instead of standard path syntax, an 
         * initial slash is treated as a relative path, and vice versa.
         */
        public function rel2abs( &$parser , $to = '' , $from = '' ) {
 
                $from = trim($from);
                if( $from == '' ) {
                        $from = $parser->getTitle()->getPrefixedText();
                }
 
                $to = rtrim( $to , ' /' );
 
                // if we have an empty path, or just one containing a dot
                if( $to == '' || $to == '.' ) {
                        return $from;
                }
 
                // if the path isn't relative
                if ( substr( $to , 0 , 1) != '/' &&
                 substr( $to , 0 , 2) != './' &&
                 substr( $to , 0 , 3) != '../' &&
                 $to != '..' )
                {
                        $from = '';
                }
                // Make a long path, containing both, enclose it in /.../
                $fullPath = '/' . $from . '/' .  $to . '/';
 
                // remove redundant current path dots
                $fullPath = preg_replace( '!/(\./)+!', '/', $fullPath );
 
                // remove double slashes
                $fullPath = preg_replace( '!/{2,}!', '/', $fullPath );
 
                // remove the enclosing slashes now
                $fullPath = trim( $fullPath , '/' );
                $exploded = explode ( '/' , $fullPath );
                $newExploded = array();
 
                foreach ( $exploded as $current ) {
                        if( $current == '..' ) { // removing one level
                                if( !count( $newExploded ) ){
                                        // attempted to access a node above root node
                                        return wfMsgForContent( 'pfunc_rel2abs_invalid_depth', $fullPath );
                                }
                                // remove last level from the stack
                                array_pop( $newExploded );
                        } else {
                                // add the current level to the stack
                                $newExploded[] = $current;
                        }
                }
 
                // we can now join it again
                return implode( '/' , $newExploded );
        }
 
        function time( &$parser, $format = '', $date = '', $local = false ) {
                global $wgContLang, $wgLocaltimezone;
                if ( isset( $this->mTimeCache[$format][$date][$local] ) ) {
                        return $this->mTimeCache[$format][$date][$local];
                }
 
                if ( $date !== '' ) {
                        $unix = @strtotime( $date );
                } else {
                        $unix = time();
                }
 
                if ( $unix == -1 || $unix == false ) {
                        $result = wfMsgForContent( 'pfunc_time_error' );
                } else {
                        $this->mTimeChars += strlen( $format );
                        if ( $this->mTimeChars > $this->mMaxTimeChars ) {
                                return wfMsgForContent( 'pfunc_time_too_long' );
                        } else {
                                if ( $local ) {
                                        # Use the time zone
                                        if ( isset( $wgLocaltimezone ) ) {
                                                $oldtz = getenv( 'TZ' );
                                                putenv( 'TZ='.$wgLocaltimezone );
                                        }
                                        wfSuppressWarnings(); // E_STRICT system time bitching
                                        $ts = date( 'YmdHis', $unix );
                                        wfRestoreWarnings();
                                        if ( isset( $wgLocaltimezone ) ) {
                                                putenv( 'TZ='.$oldtz );
                                        }
                                } else {
                                        $ts = wfTimestamp( TS_MW, $unix );
                                }
                                if ( method_exists( $wgContLang, 'sprintfDate' ) ) {
                                        $result = $wgContLang->sprintfDate( $format, $ts );
                                } else {
                                        if ( !class_exists( 'SprintfDateCompat' ) ) {
                                                require( dirname( __FILE__ ) . '/SprintfDateCompat.php' );
                                        }
 
                                        $result = SprintfDateCompat::sprintfDate( $format, $ts );
                                }
                        }
                }
                $this->mTimeCache[$format][$date][$local] = $result;
                return $result;
        }
 
        function localTime( &$parser, $format = '', $date = '' ) {
                return $this->time( $parser, $format, $date, true );
        }
 
        /**
         * Obtain a specified number of slash-separated parts of a title,
         * e.g. {{#titleparts:Hello/World|1}} => "Hello"
         *
         * @param Parser $parser Parent parser
         * @param string $title Title to split
         * @param int $parts Number of parts to keep
         * @param int $offset Offset starting at 1
         * @return string
         */
        public function titleparts( $parser, $title = '', $parts = -1, $offset = 1 ) {
                $parts = intval( $parts );
                $offset = intval( $offset ) - 1;
                $ntitle = Title::newFromText( $title );
                if( $ntitle instanceof Title ) {
                        $bits = explode( '/', $ntitle->getPrefixedText() );
                        if( $parts <= 0 || $parts > count( $bits ) ) {
                                return $ntitle->getPrefixedText();
                        } elseif( $offset < 0 || $offset > count( $bits ) ) {
                                return $ntitle->getPrefixedText();
                        } else {
                                $keep = array();
                                for( $i = 0; $i < $offset; $i++ )
                                        array_shift( $bits );
                                for( $i = 0; $i < $parts; $i++ )
                                        $keep[] = array_shift( $bits );
                                return implode( '/', $keep );
                        }
                } else {
                        return $title;
                }
        }
}
 
function wfSetupLOParserFunctions() {
        global $wgParser, $wgMessageCache, $wgExtLOParserFunctions, $wgMessageCache, $wgHooks;
 
        $wgExtLOParserFunctions = new ExtLOParserFunctions;
 
        $wgParser->setFunctionHook( 'expr', array( &$wgExtLOParserFunctions, 'expr' ) );
        $wgParser->setFunctionHook( 'time', array( &$wgExtLOParserFunctions, 'time' ) );
        $wgParser->setFunctionHook( 'timel', array( &$wgExtLOParserFunctions, 'localTime' ) );
        $wgParser->setFunctionHook( 'rel2abs', array( &$wgExtLOParserFunctions, 'rel2abs' ) );
        $wgParser->setFunctionHook( 'titleparts', array( &$wgExtLOParserFunctions, 'titleparts' ) );
        
        include_once( dirname( __FILE__ ) . '/LOParserFunctions.i18n.php' );
        foreach( LOParserFunctions_i18n::efLOParserFunctionsMessages() as $lang => $messages )
                $wgMessageCache->addMessages( $messages, $lang );
 
        $wgHooks['ParserClearState'][] = array( &$wgExtLOParserFunctions, 'clearState' );
}
 
function wfLOParserFunctionsLanguageGetMagic( &$magicWords, $langCode ) {
        include_once( dirname( __FILE__ ) . '/LOParserFunctions.i18n.php' );
        foreach( LOParserFunctions_i18n::efLOParserFunctionsWords( $langCode ) as $word => $trans )
                $magicWords[$word] = $trans;
        return true;
}

LOParserFunctions.i18n.php
<?php
 
class LOParserFunctions_i18n
{
    private static $words = array(
    // English
        'en' => array(
            'expr'      => array( 0, 'expr' ),
            'time'    => array( 0, 'time' ),
            'timel'  => array( 0, 'timel' ),
            'rel2abs'  => array( 0, 'rel2abs' ),
            'titleparts' => array( 0, 'titleparts' ),
        ),
    );
 
    public static $messages = array(
    // English
        'en' => array(
            'pfunc_rel2abs_invalid_depth' =>
                "Invalid depth on rel2abs",
            'pfunc_time_error' =>
                "Time Error",
            'pfunc_time_too_long' =>
                "Time too long",
        )
    );
 
    /**
     * Get translated magic words, if available
     *
     * @param string $lang Language code
     * @return array
     */
    public static function efLOParserFunctionsWords( $lang )
    {
        // English is used as a fallback, and the English synonyms are
        // used if a translation has not been provided for a given word
        return ( $lang == 'en' || !isset( self::$words[$lang] ) ) ?
            self::$words['en'] :
            array_merge( self::$words['en'], self::$words[$lang] );
    }
 
    public static function efLOParserFunctionsMessages()
    {
        return self::$messages;
    }
}

Listrophy 18:21, 15 November 2007 (UTC)Reply

Wow! How did I forget to include that? I've included the i18n file that I was using during development. It's little more than a copy/paste of the ParserFunctions' i18n file. —Sledged (talk) 19:00, 15 November 2007 (UTC)Reply

Wrong Expr.php[edit]

The Expr.php linked in the page is wrong! It doesn't contain a definition for the function "addMessage", that is requested by LO Parser Functions, as you can see:

        function &getExprParser() {
                if ( !isset( $this->mExprParser ) ) {
                        if ( !class_exists( 'ExprParser' ) ) {
                                require( dirname( __FILE__ ) . '/Expr.php' );
                                ExprParser::addMessages();
                        }
                        $this->mExprParser = new ExprParser;
                }
                return $this->mExprParser;
        }

The correct file I used is this, so please someone should fix this error! --81.208.83.233 21:13, 6 December 2007 (UTC)Reply

I changed the link so it points to an older version (r25357). When I get a chance I'll use the current version of ParserFunctions to update this extension, and change the link to the newest version. —Sledged (talk) 21:48, 6 December 2007 (UTC)Reply