Skip to content

Commit

Permalink
API-CHANGE: SSF-168 initial rearranging the SS_Report class for use i…
Browse files Browse the repository at this point in the history
…n SS3. Deprecating unnecessary methods, moving code around, rewriting get_reports method and writing unit tests
  • Loading branch information
Julian Seidenberg committed Apr 3, 2012
1 parent fe28058 commit ee220bb
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 111 deletions.
179 changes: 78 additions & 101 deletions code/reports/Report.php
Expand Up @@ -35,19 +35,13 @@
* Showing reports to the user
* ===========================
*
* Right now, all subclasses of SS_Report will be shown in the ReportAdmin. However, we are planning
* on adding an explicit registration mechanism, so that you can decide which reports go in the
* report admin, and which go elsewhere (such as the side panel in the CMS).
* Right now, all subclasses of SS_Report will be shown in the ReportAdmin. In SS3 there is only
* one place where reports can go, so this class is greatly simplifed from from its version in SS2.
*
* @package cms
* @subpackage reports
*/
class SS_Report extends ViewableData {
/**
* Report registry populated by {@link SS_Report::register()}
*/
private static $registered_reports = array();

/**
* This is the title of the report,
* used by the ReportAdmin templates.
Expand All @@ -70,6 +64,22 @@ class SS_Report extends ViewableData {
* Set by overriding in your subclass.
*/
protected $dataClass = 'SiteTree';

/**
* A field that specifies the sort order of this report
* @var int
*/
protected $sort = 0;

/**
* Reports which should not be collected and returned in get_reports
* @var array
*/
public static $excluded_reports = array(
'SS_Report',
'SS_ReportWrapper',
'SideReportWrapper'
);

/**
* Return the title of this report.
Expand All @@ -93,22 +103,12 @@ function description() {
return $this->description;
}

/**
* Return a FieldList specifying the search criteria for this report.
*
* Override this method to define search criteria.
*/
function parameterFields() {
return null;
}

/**
* Return the {@link SQLQuery} that provides your report data.
*/
function sourceQuery($params) {
if($this->hasMethod('sourceRecords')) {
$query = new SS_Report_FakeQuery($this, 'sourceRecords', $params);
$query->setSortColumnMethod('sortColumns');
return $query;
} else {
user_error("Please override sourceQuery()/sourceRecords() and columns() or, if necessary, override getReportField()", E_USER_ERROR);
Expand All @@ -126,36 +126,75 @@ function records($params) {
}
}


/**
* Return an map of columns for your report.
* - The map keys will be the source columns for your report (in TableListField dot syntax)
* - The values can either be a string (the column title), or a map containing the following
* column parameters:
* - title: The column title
* - formatting: A formatting string passed to {@link TableListField::setFieldFormatting()}
* Return the data class for this report
*/
function columns() {
user_error("Please override sourceQuery() and columns() or, if necessary, override getReportField()", E_USER_ERROR);
function dataClass() {
return $this->dataClass;
}

function sortColumns() {
return array_keys($this->columns());



/**
* @deprecated 3.0
* All subclasses of SS_Report now appear in the report admin, no need to register or unregister.
*
* Register a report.
* @param $list The list to add the report to: "ReportAdmin" or "SideReports"
* @param $reportClass The class of the report to add.
* @param $priority The priority. Higher numbers will appear furhter up in the reports list.
* The default value is zero.
*/
static function register($list, $reportClass, $priority = 0) {
}

/**
* Return the number of records in this report with no filters applied.
* @deprecated 3.0
* All subclasses of SS_Report now appear in the report admin, no need to register or unregister.
*/
function count() {
return (int)$this->sourceQuery(array())->unlimitedRowCount();
static function unregister($list, $reportClass) {
self::excludeReport($reportClass);
}

/**
* Return the data class for this report
* Exclude a certain report class from the list of Reports in the CMS
* @static
* @param $reportClass
*/
function dataClass() {
return $this->dataClass;
static function excludeReport($reportClass) {
self::$excluded_reports[] = $reportClass; //add to the excluded reports, so this report doesn't get used
}

/**
* Return the SS_Report objects making up the given list.
* @return An array of SS_Report objects
*/
static function get_reports() {
$reports = ClassInfo::subclassesFor(get_called_class());

$reportsArray = array();
if ($reports && count($reports) > 0) {
//collect reports into array with an attribute for 'sort'
foreach($reports as $report) {
if (in_array($report, self::$excluded_reports)) continue; //don't use the SS_Report superclass
$reportObj = new $report;
if (method_exists($reportObj,'sort')) $reportObj->sort = $reportObj->sort(); //use the sort method to specify the sort field
$reportsArray[] = $reportObj;
}
}

//convert array into ArrayList
$list = ArrayList::create($reportsArray);

//sort
$list->sort('sort');

return $list;
}

/////////////////////// UI METHODS ///////////////////////


/**
* Returns a FieldList with which to create the CMS editing form.
Expand Down Expand Up @@ -273,72 +312,10 @@ function canView($member = null) {
* @return string
*/
function TreeTitle() {
return $this->title();/* . ' (' . $this->count() . ')'; - this is too slow atm */
}

/**
* Return the ID of this Report class.
* Because it doesn't have a number, we
* use the class name as the ID.
*
* @return string
*/
function ID() {
return $this->class;
}

/////////////////////////////////////////////////////////////////////////////////////////////

/**
* Register a report.
* @param $list The list to add the report to: "ReportAdmin" or "SideReports"
* @param $reportClass The class of the report to add.
* @param $priority The priority. Higher numbers will appear furhter up in the reports list.
* The default value is zero.
*/
static function register($list, $reportClass, $priority = 0) {
if(strpos($reportClass, '(') === false && (!class_exists($reportClass) || !is_subclass_of($reportClass,'SS_Report'))) {
user_error("SS_Report::register(): '$reportClass' is not a subclass of SS_Report", E_USER_WARNING);
return;
}

self::$registered_reports[$list][$reportClass] = $priority;
}

/**
* Unregister a report, removing it from the list
*/
static function unregister($list, $reportClass) {
unset(self::$registered_reports[$list][$reportClass]);
return $this->title();
}

/**
* Return the SS_Report objects making up the given list.
* @return An array of SS_Report objects
*/
static function get_reports($list) {
$output = array();
if(isset(self::$registered_reports[$list])) {
$listItems = self::$registered_reports[$list];

// Sort by priority, preserving internal order of items with the same priority
$groupedItems = array();
foreach($listItems as $k => $v) {
$groupedItems[$v][] = $k;
}
krsort($groupedItems);
$sortedListItems = call_user_func_array('array_merge', $groupedItems);

foreach($sortedListItems as $report) {
if(strpos($report,'(') === false) $reportObj = new $report;
else $reportObj = eval("return new $report;");

$output[$reportObj->ID()] = $reportObj;
}
}

return $output;
}

}

Expand Down Expand Up @@ -370,7 +347,7 @@ function __construct($obj, $method, $params) {
$this->method = $method;
$this->params = $params;
}

/**
* Provide a method that will return a list of columns that can be used to sort.
*/
Expand Down
36 changes: 26 additions & 10 deletions tests/reports/ReportTest.php
@@ -1,18 +1,34 @@
<?php

class ReportTest extends SapphireTest {

function testCanSortBy() {
$report = new SSReportTest_FakeTest();
$this->assertTrue($report->sourceQuery(array())->canSortBy('Title ASC'));
$this->assertTrue($report->sourceQuery(array())->canSortBy('Title DESC'));
$this->assertTrue($report->sourceQuery(array())->canSortBy('Title'));
}

function testGetReports() {
$reports = SS_Report::get_reports();
$this->assertNotNull($reports, "Reports returned");
Debug::Show($reports);
$previousSort = 0;
foreach($reports as $report) {
$this->assertGreaterThanOrEqual($previousSort, $report->sort, "Reports are in correct sort order");
$previousSort = $report->sort;
}
}

function testExcludeReport() {
$reports = SS_Report::get_reports();
$reportNames = array();
foreach($reports as $report) {
$reportNames[] = $report->class;
}
$this->assertContains('ReportTest_FakeTest',$reportNames,'ReportTest_FakeTest is in reports list');

//excluse one report
SS_Report::excludeReport('ReportTest_FakeTest');

$reports = SS_Report::get_reports();
$reportNames = array();
foreach($reports as $report) {
$reportNames[] = $report->class;
}
$this->assertNotContains('ReportTest_FakeTest',$reportNames,'ReportTest_FakeTest is NOT in reports list');
}
}

Expand All @@ -39,12 +55,12 @@ function sort() {

class ReportTest_FakeTest2 extends SS_Report implements TestOnly {
function title() {
return 'Report title';
return 'Report title 2';
}
function columns() {
return array(
"Title" => array(
"title" => "Page Title"
"title" => "Page Title 2"
)
);
}
Expand Down

0 comments on commit ee220bb

Please sign in to comment.