r80377 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r80376‎ | r80377 | r80378 >
Date:09:41, 15 January 2011
Author:dantman
Status:deferred
Tags:
Comment:
Commit a TableData extension I just created.
Modified paths:
  • /trunk/extensions/TableData (added) (history)
  • /trunk/extensions/TableData/ExtTableData.class.php (added) (history)
  • /trunk/extensions/TableData/ExtTableDataParser.class.php (added) (history)
  • /trunk/extensions/TableData/ExtTableDataParser_csv.class.php (added) (history)
  • /trunk/extensions/TableData/ExtTableDataParser_separated.class.php (added) (history)
  • /trunk/extensions/TableData/TableData.i18n.php (added) (history)
  • /trunk/extensions/TableData/TableData.php (added) (history)

Diff [purge]

Index: trunk/extensions/TableData/ExtTableDataParser_separated.class.php
@@ -0,0 +1,58 @@
 2+<?php
 3+/**
 4+ * ExtTableDataParser_separated class for extension TableData.
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+class ExtTableDataParser_separated extends ExtTableDataParser {
 11+
 12+ static $separators = array(
 13+ 'space' => '/ /',
 14+ 'tab' => '/\t/',
 15+ 'whitespace' => '/\s+/',
 16+ 'comma' => '/,/',
 17+ 'colon' => '/:/',
 18+ 'semicolon' => '/;/',
 19+ 'bar' => '/\|/',
 20+ );
 21+
 22+ public function parse( $contents, $attributes ) {
 23+ $data = array( "headers" => array(), "rows" => array() );
 24+
 25+ if ( !isset($attributes["separator"]) ) {
 26+ return array( "error" => 'noseparator' );
 27+ }
 28+ if ( !isset(self::$separators[$attributes["separator"]]) ) {
 29+ return array( "error" => array( 'invalidseparator', $attributes["separator"] ) );
 30+ }
 31+
 32+ $separator = self::$separators[$attributes["separator"]];
 33+
 34+ $rows = array();
 35+ foreach ( explode( "\n", $contents ) as $line ) {
 36+ $rows[] = preg_split( $separator, $line );
 37+ }
 38+
 39+ if ( count($rows) <= 0 ) {
 40+ return $data;
 41+ }
 42+
 43+ $data["headers"] = array_shift($rows); // the first line should be the header names
 44+
 45+ foreach ( $rows as $row ) {
 46+ $datarow = array();
 47+ foreach ( $data["headers"] as $i => $header ) {
 48+ if ( isset($row[$i]) ) {
 49+ $datarow[$header] = $row[$i];
 50+ }
 51+ }
 52+ $data["rows"][] = $datarow;
 53+ }
 54+
 55+ return $data;
 56+ }
 57+
 58+}
 59+
Property changes on: trunk/extensions/TableData/ExtTableDataParser_separated.class.php
___________________________________________________________________
Added: svn:eol-style
160 + native
Index: trunk/extensions/TableData/ExtTableDataParser_csv.class.php
@@ -0,0 +1,45 @@
 2+<?php
 3+/**
 4+ * ExtTableDataParser_csv class for extension TableData.
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+class ExtTableDataParser_csv extends ExtTableDataParser {
 11+
 12+ public function parse( $contents, $attributes ) {
 13+ $data = array( "headers" => array(), "rows" => array() );
 14+
 15+ $csv = self::parseCSV( $contents );
 16+
 17+ if ( count($csv) <= 0 ) {
 18+ return $data;
 19+ }
 20+
 21+ $data["headers"] = array_shift($csv); // the first line of a CSV should be the header names
 22+
 23+ foreach ( $csv as $csv_row ) {
 24+ $row = array();
 25+ foreach ( $data["headers"] as $i => $header ) {
 26+ if ( isset($csv_row[$i]) ) {
 27+ $row[$header] = $csv_row[$i];
 28+ }
 29+ }
 30+ $data["rows"][] = $row;
 31+ }
 32+
 33+ return $data;
 34+ }
 35+
 36+ public static function parseCSV( $str ) {
 37+ // @todo Implement support for php < 5.3 which has fgetcsv but does not
 38+ // have str_getcsv.
 39+ // @note Extension:DataTransfer does this with a tmp file, however from
 40+ // a php.net comment it looks like it might be possible to do this with
 41+ // some sort of fake memory stream.
 42+ return array_map( "str_getcsv", explode( "\n", $str ) );
 43+ }
 44+
 45+}
 46+
Property changes on: trunk/extensions/TableData/ExtTableDataParser_csv.class.php
___________________________________________________________________
Added: svn:eol-style
147 + native
Index: trunk/extensions/TableData/TableData.i18n.php
@@ -0,0 +1,23 @@
 2+<?php
 3+/**
 4+ * Internationalisation file for extension TableData.
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+$messages = array();
 11+
 12+/** English
 13+ * @author Daniel Friesen
 14+ */
 15+$messages['en'] = array(
 16+ 'tabledata-desc' => "Implements a parser tag that can accept data in a variety of formats such as CSV and format it into a table potentially using templates to format it.",
 17+
 18+ // Errors
 19+ 'datatable-error-formatnotdefined' => 'DataTable Error: A valid format for the input data was not defined.',
 20+ 'datatable-error-invalidformat' => 'DataTable Error: There is no parser for the "$1" format of input data.',
 21+ 'datatable-error-invalidtemplatetitle' => 'DataTable Error: "$2" is not a valid template title to use in the $1 attribute.',
 22+ 'datatable-error-noseparator' => 'DataTable Error: A separator was not defined for the separated input format.',
 23+ 'datatable-error-invalidseparator' => 'DataTable Error: The separator "$1" does not exist.',
 24+);
Property changes on: trunk/extensions/TableData/TableData.i18n.php
___________________________________________________________________
Added: svn:eol-style
125 + native
Index: trunk/extensions/TableData/TableData.php
@@ -0,0 +1,45 @@
 2+<?php
 3+/**
 4+ * @author Daniel Friesen (http://mediawiki.org/wiki/User:Dantman) <mediawiki@danielfriesen.name>
 5+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 6+ *
 7+ * This program is free software; you can redistribute it and/or
 8+ * modify it under the terms of the GNU General Public License
 9+ * as published by the Free Software Foundation; either version 2
 10+ * of the License, or (at your option) any later version.
 11+ *
 12+ * This program is distributed in the hope that it will be useful,
 13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15+ * GNU General Public License for more details.
 16+ *
 17+ * You should have received a copy of the GNU General Public License
 18+ * along with this program; if not, write to the Free Software
 19+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 20+ */
 21+
 22+if( !defined( 'MEDIAWIKI' ) ) die( "This is an extension to the MediaWiki package and cannot be run standalone." );
 23+
 24+$wgExtensionCredits['other'][] = array (
 25+ 'name' => 'Table Data',
 26+ 'url' => 'http://mediawiki.org/wiki/Extension:TableData',
 27+ 'author' => "[http://mediawiki.org/wiki/User:Dantman Daniel Friesen] [mailto:Daniel%20Friesen%20%3Cmediawiki@danielfriesen.name%3E <mediawiki@danielfriesen.name>]",
 28+ 'descriptionmsg' => 'tabledata-desc',
 29+);
 30+
 31+$dir = dirname( __FILE__ ) . '/';
 32+$wgExtensionMessagesFiles['TableData'] = $dir . 'TableData.i18n.php';
 33+
 34+foreach ( array( 'ExtTableData', 'ExtTableDataParser', 'ExtTableDataParser_csv', 'ExtTableDataParser_separated' ) as $className ) {
 35+ $wgAutoloadClasses[$className] = "{$dir}{$className}.class.php";
 36+}
 37+
 38+/**
 39+ * Register parser extensions
 40+ */
 41+$wgHooks['ParserFirstCallInit'][] = array( 'efTableDataRegisterParser' );
 42+function efTableDataRegisterParser( &$parser ) {
 43+ $parser->setFunctionTagHook( 'tabledata', array( 'ExtTableData', 'tag' ), 0 );
 44+ return true;
 45+}
 46+
Property changes on: trunk/extensions/TableData/TableData.php
___________________________________________________________________
Added: svn:eol-style
147 + native
Index: trunk/extensions/TableData/ExtTableDataParser.class.php
@@ -0,0 +1,54 @@
 2+<?php
 3+/**
 4+ * ExtTableData class for extension TableData.
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+abstract class ExtTableDataParser {
 11+
 12+ protected $mFormat;
 13+
 14+ public function __construct( $format ) {
 15+ $this->mFormat = $format;
 16+ }
 17+
 18+ public function getFormat() {
 19+ return $this->mFormat;
 20+ }
 21+
 22+ /**
 23+ * This method must take the $content and parse it according to the format
 24+ * (you can support multiple formats in one class by looking at getFormat()
 25+ * to see what format name created this instance.
 26+ * The return value must be an array containing an array of headers/keys
 27+ * in the "headers" key, and in the "rows" key an array of associative arrays
 28+ * of data.
 29+ * For example this CSV:
 30+ * A,B,C
 31+ * 1,2,3
 32+ * A CSV parser should turn into the following array:
 33+ * array(
 34+ * "headers" => array( "A", "B", "C" ),
 35+ * "rows" => array(
 36+ * array(
 37+ * "A" => "1",
 38+ * "B" => "2",
 39+ * "C" => "3",
 40+ * ),
 41+ * ),
 42+ * );
 43+ * The method is also passed the attributes used in the tag, this can be useful
 44+ * if you ABSOLUTELY NEED to add some formatter specific arguments. However
 45+ * please be sparing in the arguments you take. And understand that the arguments
 46+ * you use could conflict with ones that are being used for other purposes
 47+ * in the tag itself. The best practice is to prefix any argument you use
 48+ * with either the formatter name or "formatter.".
 49+ * You also may return an array with they key "error" pointing to a message name
 50+ * that will be prefixed with "datatable-error-" and printed out to the user.
 51+ */
 52+ abstract public function parse( $content, $attributes );
 53+
 54+}
 55+
Property changes on: trunk/extensions/TableData/ExtTableDataParser.class.php
___________________________________________________________________
Added: svn:eol-style
156 + native
Index: trunk/extensions/TableData/ExtTableData.class.php
@@ -0,0 +1,126 @@
 2+<?php
 3+/**
 4+ * ExtTableData class for extension TableData.
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+class ExtTableData {
 11+
 12+ public function tag( &$parser, $frame, $content, $attributes ) {
 13+
 14+ /** Fetch ourself a data parser for the content, be sure to error out and make this something extensible **/
 15+ if ( !isset($attributes['format']) ) {
 16+ return self::error( 'formatnotdefined' );
 17+ }
 18+
 19+ $dataParser = self::getDataParser( $attributes['format'] );
 20+
 21+ if ( !$dataParser ) {
 22+ return self::error( 'invalidformat', $attributes['format'] );
 23+ }
 24+
 25+ // @todo Consider supporting the extracting of data from another page
 26+ $data = $dataParser->parse( trim($content), $attributes );
 27+ if ( is_array($data) && isset($data["error"]) ) {
 28+ return self::error($data["error"]);
 29+ }
 30+
 31+ /** Build our WikiText here. We support header/row/footer attributes defining templates to use for formatting **/
 32+ $wt = '';
 33+ if ( isset($attributes["header"]) ) {
 34+ // The tag has defined a template to use to format the header
 35+ $tpl = Title::newFromText( $attributes["header"], NS_TEMPLATE );
 36+ if ( !is_object($tpl) ) {
 37+ return self::error( 'invalidtemplatetitle', "header", $attributes["header"] );
 38+ }
 39+ $tplText = $tpl->getPrefixedText();
 40+ $wt .= self::makeTemplateLine( $tplText, null, $data["headers"] );
 41+ $wt .= "\n";
 42+ } else {
 43+ $wt .= "{|\n|-\n";
 44+ foreach ( $data["headers"] as $header ) {
 45+ $wt .= "!| " . wfEscapeWikiText( $header ) . "\n";
 46+ }
 47+ }
 48+ if ( isset($attributes["row"]) ) {
 49+ // The tag has defined a template to use to format rows
 50+ $tpl = Title::newFromText( $attributes["row"], NS_TEMPLATE );
 51+ if ( !is_object($tpl) ) {
 52+ return self::error( 'invalidtemplatetitle', "row", $attributes["row"] );
 53+ }
 54+ $tplText = $tpl->getPrefixedText();
 55+ foreach ( $data["rows"] as $i => $row ) {
 56+ $wt .= self::makeTemplateLine( $tplText, $i, $data["headers"], $row );
 57+ $wt .= "\n";
 58+ }
 59+ } else {
 60+ foreach ( $data["rows"] as $row ) {
 61+ $wt .= "|-\n";
 62+ foreach ( $row as $header => $cell ) {
 63+ $wt .= "|| " . wfEscapeWikiText( $cell ) . "\n";
 64+ }
 65+ }
 66+ }
 67+ if ( isset($attributes["footer"]) ) {
 68+ // The tag has defined a template to use to format the footer
 69+ $tpl = Title::newFromText( $attributes["footer"], NS_TEMPLATE );
 70+ if ( !is_object($tpl) ) {
 71+ return self::error( 'invalidtemplatetitle', "footer", $attributes["footer"] );
 72+ }
 73+ $tplText = $tpl->getPrefixedText();
 74+ $wt .= self::makeTemplateLine( $tplText, null, $data["headers"] );
 75+ } else {
 76+ $wt .= "|}";
 77+ }
 78+
 79+ // Be sure to recursiveTagParse our WikiText
 80+ return trim($parser->recursiveTagParse( $wt, $frame ));
 81+ }
 82+
 83+ static $dataParsers = array();
 84+ protected static function getDataParser( $format ) {
 85+ if ( !array_key_exists( $format, self::$dataParsers ) ) {
 86+ self::$dataParsers[$format] = self::doGetDataParser( $format );
 87+ }
 88+ return self::$dataParsers[$format];
 89+ }
 90+ protected static function doGetDataParser( $format ) {
 91+ // @todo Add hook that other extensions can use to add their own data parsers
 92+ switch($format) {
 93+ case "csv": return new ExtTableDataParser_csv( $format );
 94+ case "separated": return new ExtTableDataParser_separated( $format );
 95+ }
 96+ return false;
 97+ }
 98+
 99+ protected static function makeTemplateLine( $tplText, $i, $headers, $params=null ) {
 100+ $wt = "{{{$tplText}";
 101+ if ( isset($i) ) {
 102+ $wt .= "|#=" . ($i+1);
 103+ }
 104+ foreach ( $headers as $h => $header ) {
 105+ $wt .= "|#" . ($h+1) . "#=" . wfEscapeWikiText( $header );
 106+ }
 107+ if ( isset($params) ) {
 108+ foreach ( $params as $param => $value ) {
 109+ $wt .= "|" . wfEscapeWikiText( $param ) . "=" . wfEscapeWikiText( $value );
 110+ }
 111+ }
 112+ $wt .= "}}\n";
 113+ return $wt;
 114+ }
 115+
 116+ protected static function error( /*...*/ ) {
 117+ $args = func_get_args();
 118+ if ( is_array($args[0]) ) {
 119+ $args = $args[0];
 120+ }
 121+ $args[0] = "datatable-error-{$args[0]}";
 122+ return Html::rawElement( 'p', null,
 123+ Html::rawElement( 'strong', array( 'class' => 'error' ), call_user_func_array( "wfMsgForContent", $args ) ) );
 124+ }
 125+
 126+
 127+}
Property changes on: trunk/extensions/TableData/ExtTableData.class.php
___________________________________________________________________
Added: svn:eol-style
1128 + native

Status & tagging log