mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
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:
parent
8d89050618
commit
db42713e1c
@ -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 "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
?>
|
?>
|
Loading…
Reference in New Issue
Block a user