mlanthaler: Bugfix: Class created invalid HTML (<td>...</t>).

(merged from branches/gsoc)


git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@42020 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2007-09-16 01:50:07 +00:00
parent 8d89050618
commit db42713e1c

View File

@ -1,4 +1,6 @@
<?php <?php
/** /**
* Displays complex reports based on the list of tables and fields provided to * Displays complex reports based on the list of tables and fields provided to
* the object. * the object.
@ -24,63 +26,67 @@ class ReportField extends FormField{
function __construct($name, $title, $tables, $fields, $hideByDefault = null, $defaultSort = null, $form = null) { function __construct($name, $title, $tables, $fields, $hideByDefault = null, $defaultSort = null, $form = null) {
parent::__construct( $name, $title, "", $form ); parent::__construct( $name, $title, "", $form );
if( !is_array( $tables ) ) if( !is_array( $tables ) )
user_error( "Third parameter must be an array. Table Name => Primary Key Column", E_USER_ERROR ); user_error( "Third parameter must be an array. Table Name => Primary Key Column", E_USER_ERROR );
else { else {
$this->tables = array_keys( $tables ); $this->tables = array_keys( $tables );
$this->primaryKeys = $tables; $this->primaryKeys = $tables;
$this->primaryClass = $this->tables[0]; $this->primaryClass = $this->tables[0];
} }
if( !is_array( $fields ) ) if( !is_array( $fields ) )
$this->fields = array( $fields ); $this->fields = array( $fields );
else else
$this->fields = $this->expandWildcards( $fields ); $this->fields = $this->expandWildcards( $fields );
} }
public function setExport($export){ public function setExport($export){
$this->export = $export; $this->export = $export;
} }
protected function expandWildcards( $fields ) { protected function expandWildcards( $fields ) {
$newFields = array(); $newFields = array();
foreach( $fields as $field ) foreach( $fields as $field )
if( preg_match( '/.*\.\*/', $field ) ) if( preg_match( '/.*\.\*/', $field ) )
$newFields = $newFields + $this->expandWildcard( $field ); $newFields = $newFields + $this->expandWildcard( $field );
else else
$newFields[] = $field; $newFields[] = $field;
return $newFields; return $newFields;
} }
protected function expandWildcard( $field ) { protected function expandWildcard( $field ) {
list( $table, $column ) = $this->parseField( $field ); list( $table, $column ) = $this->parseField( $field );
foreach( $this->getColumnsInTable( $table ) as $newColumn ) foreach( $this->getColumnsInTable( $table ) as $newColumn )
$columns[] = $table.'.'.$newColumn; $columns[] = $table.'.'.$newColumn;
return $columns; return $columns;
} }
function exportToCSV( $fileName ) { function exportToCSV( $fileName ) {
$fileData = $this->columnheaders( 'csvRow', 'csvCell' ) . $this->datacells( 'csvRow', 'csvCell' ); $fileData = $this->columnheaders( 'csvRow', 'csvCell' ) . $this->datacells( 'csvRow', 'csvCell' );
header("Content-Type: text/csv; name=\"" . addslashes($fileName) . "\""); header("Content-Type: text/csv; name=\"" . addslashes($fileName) . "\"");
header("Content-Disposition: attachment; filename=\"" . addslashes($fileName) . "\""); header("Content-Disposition: attachment; filename=\"" . addslashes($fileName) . "\"");
header("Content-length: " . strlen($fileData)); header("Content-length: " . strlen($fileData));
echo $fileData; echo $fileData;
exit(); exit();
} }
function FieldHolder() { function FieldHolder() {
Requirements::javascript("sapphire/javascript/ReportField.js"); Requirements::javascript("sapphire/javascript/ReportField.js");
$headerHTML = $this->columnheaders(); $headerHTML = $this->columnheaders();
$dataCellHTML = $this->datacells(); $dataCellHTML = $this->datacells();
$id = $this->id() . '_exportToCSV'; $id = $this->id() . '_exportToCSV';
@ -92,7 +98,7 @@ HTML
}else{ }else{
$exportButton = ""; $exportButton = "";
} }
// display the table of results // display the table of results
$html = <<<HTML $html = <<<HTML
<div style="width: 98%; overflow: auto"> <div style="width: 98%; overflow: auto">
@ -104,232 +110,249 @@ HTML
<tbody> <tbody>
$dataCellHTML $dataCellHTML
</tbody> </tbody>
</table> </table>
</div> </div>
HTML; HTML;
return $html; return $html;
} }
/** /**
* Returns the HTML for the data cells for the current report. * Returns the HTML for the data cells for the current report.
* This can be used externally via ajax as the report might be filtered per column. * This can be used externally via ajax as the report might be filtered per column.
* It is also used internally to display the data cells. * It is also used internally to display the data cells.
*/ */
public function datacells( $rowCallBack = 'htmlTableRow', $cellCallBack = 'htmlTableCell' ) { public function datacells( $rowCallBack = 'htmlTableRow', $cellCallBack = 'htmlTableCell' ) {
// get the primary records in the database, sorted according to the current sort // get the primary records in the database, sorted according to the current sort
// this will need to be corrected later on // this will need to be corrected later on
$primaryRecords = $this->getRecords(); $primaryRecords = $this->getRecords();
/*echo "ERROR:"; /*echo "ERROR:";
Debug::show( $primaryRecords ); Debug::show( $primaryRecords );
die();*/ die();*/
$html = ""; $html = "";
foreach( $primaryRecords as $record ) { foreach( $primaryRecords as $record ) {
$rowOutput = ""; $rowOutput = "";
foreach( $this->fields as $field ) { foreach( $this->fields as $field ) {
if( $field{0} == '!' ) $field = substr( $field, 1 ); if( $field{0} == '!' ) $field = substr( $field, 1 );
list( $table, $column ) = $this->parseField( $field ); list( $table, $column ) = $this->parseField( $field );
if( $this->filter && !$this->filter->showColumn( $table, $column ) ) if( $this->filter && !$this->filter->showColumn( $table, $column ) )
continue; continue;
$rowOutput .= $this->$cellCallBack( $record[$field], $table, $column ); $rowOutput .= $this->$cellCallBack( $record[$field], $table, $column );
} }
$html .= $this->$rowCallBack( $rowOutput, $table, null ); $html .= $this->$rowCallBack( $rowOutput, $table, null );
} }
return $html; return $html;
} }
/** /**
* Returns the HTML for the headers of the columns. * Returns the HTML for the headers of the columns.
* Can also be called via ajax to reload the headers. * Can also be called via ajax to reload the headers.
*/ */
public function columnheaders( $rowCallBack = 'htmlTableRow', $cellCallBack = 'htmlHeaderCell' ) { public function columnheaders( $rowCallBack = 'htmlTableRow', $cellCallBack = 'htmlHeaderCell' ) {
foreach( $this->fields as $field ) { foreach( $this->fields as $field ) {
list( $table, $column ) = $this->parseField( $field ); list( $table, $column ) = $this->parseField( $field );
if( $this->filter && !$this->filter->showColumn( $table, $column ) ) if( $this->filter && !$this->filter->showColumn( $table, $column ) )
continue; // replace this with some code to show a 'hidden' column continue; // replace this with some code to show a 'hidden' column
/*if( $column == '*' ) /*if( $column == '*' )
foreach( $this->getColumnsInTable( $table ) as $extraColumn ) foreach( $this->getColumnsInTable( $table ) as $extraColumn )
$html .= $this->$cellCallBack( $extraColumn, $table, $extraColumn ); $html .= $this->$cellCallBack( $extraColumn, $table, $extraColumn );
else */ else */
$html .= $this->$cellCallBack( $column, $table, $column ); $html .= $this->$cellCallBack( $column, $table, $column );
} }
return $this->$rowCallBack( $html, null, null ); return $this->$rowCallBack( $html, null, null );
} }
protected function getColumnsInTable( $table ) { protected function getColumnsInTable( $table ) {
$result = DB::query( "SELECT * FROM `$table` LIMIT 1" ); $result = DB::query( "SELECT * FROM `$table` LIMIT 1" );
return array_keys( $result->next() ); return array_keys( $result->next() );
} }
protected function parseField( $field ) { protected function parseField( $field ) {
if( $field{0} == '!' ) if( $field{0} == '!' )
$field = substr( $field, 1 ); $field = substr( $field, 1 );
if( strpos( $field, '.' ) !== FALSE ) if( strpos( $field, '.' ) !== FALSE )
return explode( '.', $field ); return explode( '.', $field );
else else
return $field; return $field;
} }
/** /**
* Joins the given record together with the extra information in the other tables. * Joins the given record together with the extra information in the other tables.
* This is only used in a situation in which the database can't do the join and I'll * This is only used in a situation in which the database can't do the join and I'll
* correct it when I figure out how to use buildSQL * correct it when I figure out how to use buildSQL
*/ */
protected function joinRecord( $object ) { protected function joinRecord( $object ) {
return $object; return $object;
// split the list of fields into table, column and group by table. // split the list of fields into table, column and group by table.
/*$tableColumns = array(); /*$tableColumns = array();
foreach( $this->fields as $field ) { foreach( $this->fields as $field ) {
list( $table, $column ) = $this->parseField( $field ); list( $table, $column ) = $this->parseField( $field );
$tableColumns[$table][] = $column; $tableColumns[$table][] = $column;
} }
$primaryKey = $this->primaryKeys[$object->class]; $primaryKey = $this->primaryKeys[$object->class];
if( !$primaryKey ) foreach( ClassInfo::ancestry( $object->class ) as $baseClass ) if( !$primaryKey ) foreach( ClassInfo::ancestry( $object->class ) as $baseClass )
$primaryKey = $this->primaryKeys[$baseClass]; $primaryKey = $this->primaryKeys[$baseClass];
$primaryKeyValue = $object->$primaryKey; $primaryKeyValue = $object->$primaryKey;
// get the fields from the object // get the fields from the object
$completeRecord = $this->joinFields( $object, $tableColumn[$this->primaryClass] ); $completeRecord = $this->joinFields( $object, $tableColumn[$this->primaryClass] );
foreach( $tableColumns as $className => $classFields ) { foreach( $tableColumns as $className => $classFields ) {
$joinKey = $this->primaryKeys[$className]; $joinKey = $this->primaryKeys[$className];
// get the all the extra fields. // get the all the extra fields.
$recordObj = DataObject::get_one( $className, "`$className`.`$joinKey`='$primaryKeyValue'" ); $recordObj = DataObject::get_one( $className, "`$className`.`$joinKey`='$primaryKeyValue'" );
$completeRecord = $completeRecord + $this->joinFields( $recordObj, $fields ); $completeRecord = $completeRecord + $this->joinFields( $recordObj, $fields );
} }
return $completeRecord;*/ return $completeRecord;*/
} }
protected function joinFields( $object, $fields ) { protected function joinFields( $object, $fields ) {
$partialRecord = array(); $partialRecord = array();
foreach( $fields as $field ) foreach( $fields as $field )
$partialRecord[$object->class.'.'.$field] = $object->$field; $partialRecord[$object->class.'.'.$field] = $object->$field;
return $partialRecord; return $partialRecord;
} }
/** /**
* Sort the data in the cells * Sort the data in the cells
*/ */
public function sortdata() { public function sortdata() {
} }
/** /**
* Get the primary set of records for the cells. This returns a data object set. * Get the primary set of records for the cells. This returns a data object set.
*/ */
protected function getRecords() { protected function getRecords() {
// $_REQUEST['showqueries'] = 1; // $_REQUEST['showqueries'] = 1;
$tableColumns = array(); $tableColumns = array();
$selectFields = array(); $selectFields = array();
$joins = array( "`{$this->primaryClass}`" ); $joins = array( "`{$this->primaryClass}`" );
foreach( $this->fields as $field ) { foreach( $this->fields as $field ) {
if( $field{0} == '!' ) if( $field{0} == '!' )
continue; continue;
list( $table, $column ) = $this->parseField( $field ); list( $table, $column ) = $this->parseField( $field );
$tableColumns[$table][] = $column; $tableColumns[$table][] = $column;
if( $column == '*' ) if( $column == '*' )
$selectFields[] = "`$table`.*"; $selectFields[] = "`$table`.*";
else else
$selectFields[] = "`$table`.`$column` AS '$table.$column'"; $selectFields[] = "`$table`.`$column` AS '$table.$column'";
} }
foreach( array_keys( $tableColumns ) as $table ) { foreach( array_keys( $tableColumns ) as $table ) {
$tableKey = $this->primaryKeys[$table]; $tableKey = $this->primaryKeys[$table];
$primaryKey = $this->primaryKeys[$this->primaryClass]; $primaryKey = $this->primaryKeys[$this->primaryClass];
if( $table != $this->primaryClass ) if( $table != $this->primaryClass )
$joins[] = "LEFT JOIN `$table` ON `$table`.`$tableKey`=`{$this->primaryClass}`.`$primaryKey`"; $joins[] = "LEFT JOIN `$table` ON `$table`.`$tableKey`=`{$this->primaryClass}`.`$primaryKey`";
} }
$query = new SQLQuery( $selectFields, $joins ); $query = new SQLQuery( $selectFields, $joins );
return $query->execute(); return $query->execute();
} }
function htmlHeaderCell( $value, $table, $column ) { function htmlHeaderCell( $value, $table, $column ) {
return "<th>" . htmlentities( $value ) . "</th>"; return "<th>" . htmlentities( $value ) . "</th>";
} }
function htmlTableCell( $value, $table, $column ) { function htmlTableCell( $value, $table, $column ) {
return "<td>" . htmlentities( $value ) . "</t>"; return "<td>" . htmlentities( $value ) . "</td>";
} }
function htmlTableRow( $value, $table, $column ) { function htmlTableRow( $value, $table, $column ) {
return "<tr>" . $value . "</tr>"; return "<tr>" . $value . "</tr>";
} }
function csvCell( $value, $table, $column ) { function csvCell( $value, $table, $column ) {
return '"' . str_replace( '"', '""', $value ) . '",'; return '"' . str_replace( '"', '""', $value ) . '",';
} }
function csvRow( $value, $table, $column ) { function csvRow( $value, $table, $column ) {
return substr( $value, 0, strlen( $value ) - 1 )."\n"; return substr( $value, 0, strlen( $value ) - 1 )."\n";
} }
} }
/** /**
* Assisting class. Determines whether or not a column is hidden. * Assisting class. Determines whether or not a column is hidden.
* Not so helpful here, but we could overload it in other classes. * Not so helpful here, but we could overload it in other classes.
*/ */
class ReportField_SimpleFilter extends Object { class ReportField_SimpleFilter extends Object {
protected $hiddenFields; protected $hiddenFields;
function __construct( $hiddenColumns ) { function __construct( $hiddenColumns ) {
$this->hiddenFields = $hiddenColumns; $this->hiddenFields = $hiddenColumns;
} }
function columnIsVisible( $table, $column ) { function columnIsVisible( $table, $column ) {
return !isset( $this->hiddenFields[$table.'.'.$column] ); return !isset( $this->hiddenFields[$table.'.'.$column] );
} }
function showColumn( $table, $column ) { function showColumn( $table, $column ) {
unset( $this->hiddenFields[$table.'.'.$column] ); unset( $this->hiddenFields[$table.'.'.$column] );
} }
function hideColumn( $table, $column ) { function hideColumn( $table, $column ) {
$this->hiddenFields[$table.'.'.$column] = 1; $this->hiddenFields[$table.'.'.$column] = 1;
} }
} }
/** /**
* This class instantiates an instance of the report field and receives ajax requests * This class instantiates an instance of the report field and receives ajax requests
* to the report field. * to the report field.
*/ */
class ReportField_Controller extends Controller { class ReportField_Controller extends Controller {
function exporttocsv() { function exporttocsv() {
if( $this->urlParams['Type'] != 'ReportField' && ClassInfo::exists( $this->urlParams['Type'].'_Controller' ) ) { if( $this->urlParams['Type'] != 'ReportField' && ClassInfo::exists( $this->urlParams['Type'].'_Controller' ) ) {
$type = $this->urlParams['Type'].'_Controller'; $type = $this->urlParams['Type'].'_Controller';
$controller = new $type(); $controller = new $type();
@ -337,28 +360,31 @@ class ReportField_Controller extends Controller {
} }
$pageID = $this->urlParams['ID']; $pageID = $this->urlParams['ID'];
if( !$pageID ) if( !$pageID )
return "ERROR:Page does not exist"; return "ERROR:Page does not exist";
$page = DataObject::get_by_id( 'SiteTree', $pageID ); $page = DataObject::get_by_id( 'SiteTree', $pageID );
if( !$page ) if( !$page )
return "ERROR:Page does not exist"; return "ERROR:Page does not exist";
$formName = substr( $this->urlParams['OtherID'], 0, -4 ); $formName = substr( $this->urlParams['OtherID'], 0, -4 );
$reportField = $page->getReportField( $formName ); $reportField = $page->getReportField( $formName );
// apply filters // apply filters
$fileName = $page->URLSegment . "-report.csv"; $fileName = $page->URLSegment . "-report.csv";
$reportField->exportToCSV( $fileName ); $reportField->exportToCSV( $fileName );
} }
function Link() { function Link() {
return ""; return "";
} }
} }
?> ?>