Refactoring help...
Posted: Sun Jul 31, 2005 6:53 pm
OK, so I've been using TDD (see all my posts in the Unit Test forum) to drive the development of some list formatting classes. These are classes that take a RecordSet and then output a list in a variety of formats. The different classes take ResultSet with different row headers (ie different columns from the DB) and apply the various business logic to the formatting.
After the second class I knew I had substantial code duplication, but didn't see a good way to remove it. I've finished the next pair of classes, hoping to triangulate in on the proper refactoring -- I'm almost positive that there's Strategy or two in here...
There's now four classes all have two methods: formatAsTabbed and formatAsText. (They are likely to gain an formatAsXML and a formatAsLaTeX. I don't expect them to grow past those four total).
The formatAsTabbed are the most similar; I think I can fold most of it up to a superclass.
The formatAsText have enough difference that I'm not sure how to refactor the common elements: the two Competitor based lists need to use look-back to combined matching entries, the CompetitorAffil needs to add subheaders, the EventEntry one needs to use slightly crazy line breaking algorithms compared to the others. Not to mention the knowledge of the different "template" for the output (but that's the esiest piece to addresss). Finally the EventList one needs to lookup data and call the EventEntry to finish its work.
Is there a good way to start unifying these?
Here's the current production code for the classes: [I apologize for the lousy indenting, looks like the PHP tag is eating tabs but not spaces or vice versa)
After the second class I knew I had substantial code duplication, but didn't see a good way to remove it. I've finished the next pair of classes, hoping to triangulate in on the proper refactoring -- I'm almost positive that there's Strategy or two in here...
There's now four classes all have two methods: formatAsTabbed and formatAsText. (They are likely to gain an formatAsXML and a formatAsLaTeX. I don't expect them to grow past those four total).
The formatAsTabbed are the most similar; I think I can fold most of it up to a superclass.
The formatAsText have enough difference that I'm not sure how to refactor the common elements: the two Competitor based lists need to use look-back to combined matching entries, the CompetitorAffil needs to add subheaders, the EventEntry one needs to use slightly crazy line breaking algorithms compared to the others. Not to mention the knowledge of the different "template" for the output (but that's the esiest piece to addresss). Finally the EventList one needs to lookup data and call the EventEntry to finish its work.
Is there a good way to start unifying these?
Here's the current production code for the classes: [I apologize for the lousy indenting, looks like the PHP tag is eating tabs but not spaces or vice versa)
Code: Select all
<?php
/**
* Format lists of competitors into end-user friendly formats.
* This file is part of CompInaBox.
* @copyright CompInaBox Copyright 2001-2005. Eric D. Nielsen, All rights reserverd.
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
* @author Eric D. Nielsen <nielsene@alum.mit.edu>
* @package DataFormatting
* @filesource
*/
/**
* Formats QueryResults for use in outside documentation.
*
* This class handles formatting list of competitors into the
* various layouts needed for people assembling a printed program
* offering choices such as tabbed delimited or pre-formatted text and
* can group the lists by affiliations or not.
* @package DataFormatting
*/
class CompetitorListFormatter {
function CompetitorListFormatter() {
}
/**
* Return the list as tab delimited entries
*
* This format is designed for use by authors who wish to
* do significant data maniupulation on the output.
* @param QueryResult $qr A QueryResult returned from a call to DB::query()
*/
function formatAsTabbed($qr) {
$str = &quote;LIST OF COMPETITORS\n&quote;;
$numRows=$qr->numRows();
if (0==$numRows)
$str.=&quote;none registered\n&quote;;
else {
for ($i=0;$i<$numRows;$i++) {
list($num,$lfname,$llname,$laffil,
$ffname,$flname,$faffil) = $qr->getRowAt($i);
$str.=&quote;$num\t$lfname\t$llname\t$laffil\t$ffname\t$flname\t$faffil\n&quote;;
}
}
return $str;
}
/**
* Return the list as a pre-formatted text list
*
* This format is designed for use by authors who wish to
* simply drop the output directly into thier printed program with
* little to no modifications.
* @param QueryResult $qr A QueryResult returned from a call to DB::query()
*/
function formatAsText($qr) {
$str = &quote;List of Competitors, by Competitor Number\n&quote;;
$numRows=$qr->numRows();
if (0==$numRows)
$str.=&quote;none registered\n&quote;;
else {
$storedNum=-1;
for ($i=0;$i<$numRows;$i++) {
list($num,$lfname,$llname,$laffil,
$ffname,$flname,$faffil) = $qr->getRowAt($i);
if ($storedNum!=$num) {
$storedNum=$num;
$str.=&quote;$num $lfname $llname ($laffil) & $ffname $flname ($faffil)\n&quote;;
} else {
$str.=&quote;\t\t& $ffname $flname ($faffil)\n&quote;;
}
}
}
return $str;
}
}
?>Code: Select all
<?php
/**
* Format lists of competitors into end-user friendly formats.
* This file is part of CompInaBox.
* @copyright CompInaBox Copyright 2001-2005. Eric D. Nielsen, All rights reserverd.
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
* @author Eric D. Nielsen <nielsene@alum.mit.edu>
* @package DataFormatting
* @filesource
*/
/**
* Formats QueryResults for use in outside documentation.
*
* This class handles formatting list of competitors into the
* various layouts needed for people assembling a printed program
* offering choices such as tabbed delimited or pre-formatted text.
* @package DataFormatting
*/
class CompetitorAffilListFormatter {
function CompetitorAffilListFormatter() {
}
/**
* Return the list as tab delimited entries
*
* This format is designed for use by authors who wish to
* do significant data maniupulation on the output.
* @param QueryResult $qr A QueryResult returned from a call to DB::query()
*/
function formatAsTabbed($qr) {
$str = "LIST OF COMPETITORS BY AFFILIATION\n";
$curLeaderAffil=-1;
$numRows=$qr->numRows();
if (0==$numRows)
$str.="none registered\n";
else {
for ($i=0;$i<$numRows;$i++) {
list($num,$lfname,$llname,$laffil,
$ffname,$flname,$faffil) = $qr->getRowAt($i);
if ($curLeaderAffil!=$laffil) {
$str.="$laffil\n";
$curLeaderAffil=$laffil;
}
$str.="$num\t$lfname\t$llname\t$laffil\t$ffname\t$flname\t$faffil\n";
}
}
return $str;
}
/**
* Return the list as a pre-formatted text list
*
* This format is designed for use by authors who wish to
* simply drop the output directly into thier printed program with
* little to no modifications.
* @param QueryResult $qr A QueryResult returned from a call to DB::query()
*/
function formatAsText($qr) {
$str = "List of Competitors, by Affiliation, by Competitor Number\n";
$curLeaderAffil=-1;
$numRows=$qr->numRows();
if (0==$numRows)
$str.="none registered\n";
else {
$storedNum=-1;
for ($i=0;$i<$numRows;$i++) {
list($num,$lfname,$llname,$laffil,
$ffname,$flname,$faffil) = $qr->getRowAt($i);
if ($curLeaderAffil!=$laffil) {
$str.="$laffil\n";
$curLeaderAffil=$laffil;
}
if ($faffil!=$laffil) $faffil=" ($faffil)"; else $faffil="";
if ($storedNum!=$num) {
$storedNum=$num;
$str.="$num $lfname $llname & $ffname $flname$faffil\n";
} else {
$str.="\t\t& $ffname $flname$faffil\n";
}
}
}
return $str;
}
}Code: Select all
<?php
/**
* Format lists of event registrations into end-user friendly formats.
* This file is part of CompInaBox.
* @copyright CompInaBox Copyright 2001-2005. Eric D. Nielsen, All rights reserverd.
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
* @author Eric D. Nielsen <nielsene@alum.mit.edu>
* @package DataFormatting
* @filesource
*/
/**
* Formats QueryResults for use in outside documentation.
*
* This class handles formatting list of registrations into the
* various layouts needed for people assembling a printed program
* offering choices such as tabbed delimited or pre-formatted text.
* @package DataFormatting
*/
class EventListFormatter {
function EventEntryListFormatter() {
}
/**
* Return the list as tab delimited entries
*
* This format is designed for use by authors who wish to
* do significant data maniupulation on the output.
* @param QueryResult $qr A QueryResult returned from a call to DB::query()
*/
function formatAsTabbed($qr,$nestedFormatter) {
$str = "LIST OF EVENTS\n";
$numRows=$qr->numRows();
if (0==$numRows)
$str.="No Events\n";
else {
for ($i=0;$i<$numRows;$i++) {
list($eventID,$progNum,$eventName) = $qr->getRowAt($i);
$str.="$progNum. $eventName\n";
$registry = Registry::instance();
$pb =& $registry->getResource("Export Phrase Book");
$db =& $registry->getResource("Competition Database");
$query = $pb->getQuery("Event Registrations",
array("eventid"=>$eventID));
$subResult = $db->query($query);
$str.= $nestedFormatter->formatAsTabbed($subResult);
$str.="\n";
}
}
return $str;
}
/**
* Return the list as a pre-formatted text list
*
* This format is designed for use by authors who wish to
* simply drop the output directly into thier printed program with
* little to no modifications.
* @param QueryResult $qr A QueryResult returned from a call to DB::query()
*/
function formatAsText($qr,$nestedFormatter) {
$str = "List of Registrations\n";
$numRows=$qr->numRows();
if (0==$numRows)
$str.="No Events\n";
else {
for ($i=0;$i<$numRows;$i++) {
list($eventID,$progNum,$eventName) = $qr->getRowAt($i);
$str.="Event Number $progNum. $eventName\n";
$registry = Registry::instance();
$pb =& $registry->getResource("Export Phrase Book");
$db =& $registry->getResource("Competition Database");
$query = $pb->getQuery("Event Registrations",
array("eventid"=>$eventID));
$subResult = $db->query($query);
$str.= $nestedFormatter->formatAsText($subResult);
$str.="\n";
}
}
return $str;
}
}
?>Code: Select all
<?php
/**
* Format a single event registrations into end-user friendly formats.
* This file is part of CompInaBox.
* @copyright CompInaBox Copyright 2001-2005. Eric D. Nielsen, All rights reserverd.
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
* @author Eric D. Nielsen <nielsene@alum.mit.edu>
* @package DataFormatting
* @filesource
*/
/**
* Formats QueryResults for use in outside documentation.
*
* This class handles formatting list of registrations into the
* various layouts needed for people assembling a printed program
* offering choices such as tabbed delimited or pre-formatted text.
* @package DataFormatting
*/
class EventEntryListFormatter {
function EventEntryListFormatter() {
}
/**
* Return the list as tab delimited entries
*
* This format is designed for use by authors who wish to
* do significant data maniupulation on the output.
* @param QueryResult $qr A QueryResult returned from a call to DB::query()
*/
function formatAsTabbed($qr,$full=FALSE) {
$str = "";
$numRows=$qr->numRows();
if (0==$numRows)
$str.="No one entered.\n";
else {
for ($i=0;$i<$numRows;$i++) {
list($coupleNum,$lfirst,$llast,$laffil,
$ffirst, $flast,$faffil) = $qr->getRowAt($i);
if ($full)
$str.="$coupleNum\t$lfirst\t$llast\t$laffil\t$ffirst\t$flast\t$faffil\n";
else
$str.="$coupleNum\n";
}
}
return $str;
}
/**
* Return the list as a pre-formatted text list
*
* This format is designed for use by authors who wish to
* simply drop the output directly into thier printed program with
* little to no modifications.
* @param QueryResult $qr A QueryResult returned from a call to DB::query()
*/
function formatAsText($qr,$full=FALSE) {
$str = "";
$numRows=$qr->numRows();
if (0==$numRows)
$str.="No one pre-registered.\n";
else {
$lastRow=$numRows-1;
for ($i=0;$i<$numRows;$i++) {
list($num,$lfirst,$llast,$laffil,
$ffirst,$flast,$faffil) = $qr->getRowAt($i);
if ($full) {
$str.="$num $lfirst $llast ($laffil) & $ffirst $flast ($faffil)\n";
} else {
if (($i!=0) && (($i%8)==0)) $str.="\n";
if (($i%8)!=0) $str.=" ";
$str.=$num;
}
}
if (!$full) $str.="\n";
}
$str.="\n1st:______ 2nd:______ 3rd:______ 4th:______ 5th:______ 6th:______ 7th:______\n";
return $str;
}
}
?>