diff --git a/code/Report.php b/code/Report.php index 3c1470ae..a0153404 100644 --- a/code/Report.php +++ b/code/Report.php @@ -29,318 +29,351 @@ * * @package reports */ -class SS_Report extends ViewableData { - /** - * This is the title of the report, - * used by the ReportAdmin templates. - * - * @var string - */ - protected $title = ''; +class SS_Report extends ViewableData +{ + /** + * This is the title of the report, + * used by the ReportAdmin templates. + * + * @var string + */ + protected $title = ''; - /** - * This is a description about what this - * report does. Used by the ReportAdmin - * templates. - * - * @var string - */ - protected $description = ''; - - /** - * The class of object being managed by this report. - * Set by overriding in your subclass. - */ - protected $dataClass = 'SiteTree'; + /** + * This is a description about what this + * report does. Used by the ReportAdmin + * templates. + * + * @var string + */ + protected $description = ''; + + /** + * The class of object being managed by this report. + * Set by overriding in your subclass. + */ + protected $dataClass = 'SiteTree'; - /** - * A field that specifies the sort order of this report - * @var int - */ - protected $sort = 0; + /** + * 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. - * - * You have two ways of specifying the description: - * - overriding description(), which lets you support i18n - * - defining the $description property - */ - public function title() { - return $this->title; - } - - /** - * Allows access to title as a property - * - * @return string - */ - public function getTitle() { - return $this->title(); - } - - /** - * Return the description of this report. - * - * You have two ways of specifying the description: - * - overriding description(), which lets you support i18n - * - defining the $description property - */ - public function description() { - return $this->description; - } - - /** - * Return the {@link SQLQuery} that provides your report data. - */ - public function sourceQuery($params) { - if($this->hasMethod('sourceRecords')) { - return $this->sourceRecords()->dataQuery(); - } else { - user_error("Please override sourceQuery()/sourceRecords() and columns() or, if necessary, override getReportField()", E_USER_ERROR); - } - } - - /** - * Return a SS_List records for this report. - */ - public function records($params) { - if($this->hasMethod('sourceRecords')) { - return $this->sourceRecords($params, null, null); - } else { - $query = $this->sourceQuery(); - $results = new ArrayList(); - foreach($query->execute() as $data) { - $class = $this->dataClass(); - $result = new $class($data); - $results->push($result); - } - return $results; - } - } + /** + * 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. + * + * You have two ways of specifying the description: + * - overriding description(), which lets you support i18n + * - defining the $description property + */ + public function title() + { + return $this->title; + } + + /** + * Allows access to title as a property + * + * @return string + */ + public function getTitle() + { + return $this->title(); + } + + /** + * Return the description of this report. + * + * You have two ways of specifying the description: + * - overriding description(), which lets you support i18n + * - defining the $description property + */ + public function description() + { + return $this->description; + } + + /** + * Return the {@link SQLQuery} that provides your report data. + */ + public function sourceQuery($params) + { + if ($this->hasMethod('sourceRecords')) { + return $this->sourceRecords()->dataQuery(); + } else { + user_error("Please override sourceQuery()/sourceRecords() and columns() or, if necessary, override getReportField()", E_USER_ERROR); + } + } + + /** + * Return a SS_List records for this report. + */ + public function records($params) + { + if ($this->hasMethod('sourceRecords')) { + return $this->sourceRecords($params, null, null); + } else { + $query = $this->sourceQuery(); + $results = new ArrayList(); + foreach ($query->execute() as $data) { + $class = $this->dataClass(); + $result = new $class($data); + $results->push($result); + } + return $results; + } + } - /** - * Return the data class for this report - */ - public function dataClass() { - return $this->dataClass; - } + /** + * Return the data class for this report + */ + public function dataClass() + { + return $this->dataClass; + } - public function getLink($action = null) { - return Controller::join_links( - 'admin/reports/', - "$this->class", - '/', // trailing slash needed if $action is null! - "$action" - ); - } + public function getLink($action = null) + { + return Controller::join_links( + 'admin/reports/', + "$this->class", + '/', // trailing slash needed if $action is null! + "$action" + ); + } - /** - * counts the number of objects returned - * @param Array $params - any parameters for the sourceRecords - * @return Int - */ - public function getCount($params = array()){ - $sourceRecords = $this->sourceRecords($params, null, null); - if(!$sourceRecords instanceOf SS_List){ - user_error($this->class."::sourceRecords does not return an SS_List", E_USER_NOTICE); - return "-1"; - } - return $sourceRecords->count(); - } + /** + * counts the number of objects returned + * @param Array $params - any parameters for the sourceRecords + * @return Int + */ + public function getCount($params = array()) + { + $sourceRecords = $this->sourceRecords($params, null, null); + if (!$sourceRecords instanceof SS_List) { + user_error($this->class."::sourceRecords does not return an SS_List", E_USER_NOTICE); + return "-1"; + } + return $sourceRecords->count(); + } - /** - * Exclude certain reports classes from the list of Reports in the CMS - * @param $reportClass Can be either a string with the report classname or an array of reports classnames - */ - static public function add_excluded_reports($reportClass) { - if (is_array($reportClass)) { - self::$excluded_reports = array_merge(self::$excluded_reports, $reportClass); - } else { - if (is_string($reportClass)) { - //add to the excluded reports, so this report doesn't get used - self::$excluded_reports[] = $reportClass; - } - } - } + /** + * Exclude certain reports classes from the list of Reports in the CMS + * @param $reportClass Can be either a string with the report classname or an array of reports classnames + */ + public static function add_excluded_reports($reportClass) + { + if (is_array($reportClass)) { + self::$excluded_reports = array_merge(self::$excluded_reports, $reportClass); + } else { + if (is_string($reportClass)) { + //add to the excluded reports, so this report doesn't get used + self::$excluded_reports[] = $reportClass; + } + } + } - /** - * Return an array of excluded reports. That is, reports that will not be included in - * the list of reports in report admin in the CMS. - * @return array - */ - static public function get_excluded_reports() { - return self::$excluded_reports; - } + /** + * Return an array of excluded reports. That is, reports that will not be included in + * the list of reports in report admin in the CMS. + * @return array + */ + public static function get_excluded_reports() + { + return self::$excluded_reports; + } - /** - * Return the SS_Report objects making up the given list. - * @return Array of SS_Report objects - */ - static public function get_reports() { - $reports = ClassInfo::subclassesFor(get_called_class()); + /** + * Return the SS_Report objects making up the given list. + * @return Array of SS_Report objects + */ + public 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 - $reflectionClass = new ReflectionClass($report); - if ($reflectionClass->isAbstract()) continue; //don't use abstract classes + $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 + $reflectionClass = new ReflectionClass($report); + if ($reflectionClass->isAbstract()) { + continue; + } //don't use abstract classes - $reportObj = new $report; - if (method_exists($reportObj,'sort')) $reportObj->sort = $reportObj->sort(); //use the sort method to specify the sort field - $reportsArray[$report] = $reportObj; - } - } + $reportObj = new $report; + if (method_exists($reportObj, 'sort')) { + $reportObj->sort = $reportObj->sort(); + } //use the sort method to specify the sort field + $reportsArray[$report] = $reportObj; + } + } - uasort($reportsArray, function($a, $b) { - if($a->sort == $b->sort) return 0; - else return ($a->sort < $b->sort) ? -1 : 1; - }); + uasort($reportsArray, function ($a, $b) { + if ($a->sort == $b->sort) { + return 0; + } else { + return ($a->sort < $b->sort) ? -1 : 1; + } + }); - return $reportsArray; - } + return $reportsArray; + } - /////////////////////// UI METHODS /////////////////////// + /////////////////////// UI METHODS /////////////////////// - /** - * Returns a FieldList with which to create the CMS editing form. - * You can use the extend() method of FieldList to create customised forms for your other - * data objects. - * - * @uses getReportField() to render a table, or similar field for the report. This - * method should be defined on the SS_Report subclasses. - * - * @return FieldList - */ - public function getCMSFields() { - $fields = new FieldList(); + /** + * Returns a FieldList with which to create the CMS editing form. + * You can use the extend() method of FieldList to create customised forms for your other + * data objects. + * + * @uses getReportField() to render a table, or similar field for the report. This + * method should be defined on the SS_Report subclasses. + * + * @return FieldList + */ + public function getCMSFields() + { + $fields = new FieldList(); - if($title = $this->title()) { - $fields->push(new LiteralField('ReportTitle', "

{$title}

")); - } - - if($description = $this->description()) { - $fields->push(new LiteralField('ReportDescription', "

" . $description . "

")); - } - - // Add search fields is available - if($this->hasMethod('parameterFields') && $parameterFields = $this->parameterFields()) { - foreach($parameterFields as $field) { - // Namespace fields for easier handling in form submissions - $field->setName(sprintf('filters[%s]', $field->getName())); - $field->addExtraClass('no-change-track'); // ignore in changetracker - $fields->push($field); - } + if ($title = $this->title()) { + $fields->push(new LiteralField('ReportTitle', "

{$title}

")); + } + + if ($description = $this->description()) { + $fields->push(new LiteralField('ReportDescription', "

" . $description . "

")); + } + + // Add search fields is available + if ($this->hasMethod('parameterFields') && $parameterFields = $this->parameterFields()) { + foreach ($parameterFields as $field) { + // Namespace fields for easier handling in form submissions + $field->setName(sprintf('filters[%s]', $field->getName())); + $field->addExtraClass('no-change-track'); // ignore in changetracker + $fields->push($field); + } - // Add a search button - $fields->push(new FormAction('updatereport', _t('GridField.Filter'))); - } - - $fields->push($this->getReportField()); + // Add a search button + $fields->push(new FormAction('updatereport', _t('GridField.Filter'))); + } + + $fields->push($this->getReportField()); - $this->extend('updateCMSFields', $fields); - - return $fields; - } - - public function getCMSActions() { - // getCMSActions() can be extended with updateCMSActions() on a extension - $actions = new FieldList(); - $this->extend('updateCMSActions', $actions); - return $actions; - } - - /** - * Return a field, such as a {@link GridField} that is - * used to show and manipulate data relating to this report. - * - * Generally, you should override {@link columns()} and {@link records()} to make your report, - * but if they aren't sufficiently flexible, then you can override this method. - * - * @return FormField subclass - */ - public function getReportField() { - // TODO Remove coupling with global state - $params = isset($_REQUEST['filters']) ? $_REQUEST['filters'] : array(); - $items = $this->sourceRecords($params, null, null); + $this->extend('updateCMSFields', $fields); + + return $fields; + } + + public function getCMSActions() + { + // getCMSActions() can be extended with updateCMSActions() on a extension + $actions = new FieldList(); + $this->extend('updateCMSActions', $actions); + return $actions; + } + + /** + * Return a field, such as a {@link GridField} that is + * used to show and manipulate data relating to this report. + * + * Generally, you should override {@link columns()} and {@link records()} to make your report, + * but if they aren't sufficiently flexible, then you can override this method. + * + * @return FormField subclass + */ + public function getReportField() + { + // TODO Remove coupling with global state + $params = isset($_REQUEST['filters']) ? $_REQUEST['filters'] : array(); + $items = $this->sourceRecords($params, null, null); - $gridFieldConfig = GridFieldConfig::create()->addComponents( - new GridFieldToolbarHeader(), - new GridFieldSortableHeader(), - new GridFieldDataColumns(), - new GridFieldPaginator(), - new GridFieldButtonRow('after'), - new GridFieldPrintButton('buttons-after-left'), - new GridFieldExportButton('buttons-after-left') - ); - $gridField = new GridField('Report',$this->title(), $items, $gridFieldConfig); - $columns = $gridField->getConfig()->getComponentByType('GridFieldDataColumns'); - $displayFields = array(); - $fieldCasting = array(); - $fieldFormatting = array(); + $gridFieldConfig = GridFieldConfig::create()->addComponents( + new GridFieldToolbarHeader(), + new GridFieldSortableHeader(), + new GridFieldDataColumns(), + new GridFieldPaginator(), + new GridFieldButtonRow('after'), + new GridFieldPrintButton('buttons-after-left'), + new GridFieldExportButton('buttons-after-left') + ); + $gridField = new GridField('Report', $this->title(), $items, $gridFieldConfig); + $columns = $gridField->getConfig()->getComponentByType('GridFieldDataColumns'); + $displayFields = array(); + $fieldCasting = array(); + $fieldFormatting = array(); - // Parse the column information - foreach($this->columns() as $source => $info) { - if(is_string($info)) $info = array('title' => $info); - - if(isset($info['formatting'])) $fieldFormatting[$source] = $info['formatting']; - if(isset($info['csvFormatting'])) $csvFieldFormatting[$source] = $info['csvFormatting']; - if(isset($info['casting'])) $fieldCasting[$source] = $info['casting']; + // Parse the column information + foreach ($this->columns() as $source => $info) { + if (is_string($info)) { + $info = array('title' => $info); + } + + if (isset($info['formatting'])) { + $fieldFormatting[$source] = $info['formatting']; + } + if (isset($info['csvFormatting'])) { + $csvFieldFormatting[$source] = $info['csvFormatting']; + } + if (isset($info['casting'])) { + $fieldCasting[$source] = $info['casting']; + } - if(isset($info['link']) && $info['link']) { - $link = singleton('CMSPageEditController')->Link('show'); - $fieldFormatting[$source] = '$value'; - } + if (isset($info['link']) && $info['link']) { + $link = singleton('CMSPageEditController')->Link('show'); + $fieldFormatting[$source] = '$value'; + } - $displayFields[$source] = isset($info['title']) ? $info['title'] : $source; - } - $columns->setDisplayFields($displayFields); - $columns->setFieldCasting($fieldCasting); - $columns->setFieldFormatting($fieldFormatting); + $displayFields[$source] = isset($info['title']) ? $info['title'] : $source; + } + $columns->setDisplayFields($displayFields); + $columns->setFieldCasting($fieldCasting); + $columns->setFieldFormatting($fieldFormatting); - return $gridField; - } - - /** - * @param Member $member - * @return boolean - */ - public function canView($member = null) { - if(!$member && $member !== FALSE) { - $member = Member::currentUser(); - } - - return true; - } - - - /** - * Return the name of this report, which - * is used by the templates to render the - * name of the report in the report tree, - * the left hand pane inside ReportAdmin. - * - * @return string - */ - public function TreeTitle() { - return $this->title(); - } + return $gridField; + } + + /** + * @param Member $member + * @return boolean + */ + public function canView($member = null) + { + if (!$member && $member !== false) { + $member = Member::currentUser(); + } + + return true; + } + + /** + * Return the name of this report, which + * is used by the templates to render the + * name of the report in the report tree, + * the left hand pane inside ReportAdmin. + * + * @return string + */ + public function TreeTitle() + { + return $this->title(); + } } /** @@ -358,92 +391,104 @@ class SS_Report extends ViewableData { * * @package reports */ -abstract class SS_ReportWrapper extends SS_Report { - protected $baseReport; +abstract class SS_ReportWrapper extends SS_Report +{ + protected $baseReport; - public function __construct($baseReport) { - $this->baseReport = is_string($baseReport) ? new $baseReport : $baseReport; - $this->dataClass = $this->baseReport->dataClass(); - parent::__construct(); - } + public function __construct($baseReport) + { + $this->baseReport = is_string($baseReport) ? new $baseReport : $baseReport; + $this->dataClass = $this->baseReport->dataClass(); + parent::__construct(); + } - public function ID() { - return get_class($this->baseReport) . '_' . get_class($this); - } + public function ID() + { + return get_class($this->baseReport) . '_' . get_class($this); + } - /////////////////////////////////////////////////////////////////////////////////////////// - // Filtering + /////////////////////////////////////////////////////////////////////////////////////////// + // Filtering - public function parameterFields() { - return $this->baseReport->parameterFields(); - } + public function parameterFields() + { + return $this->baseReport->parameterFields(); + } - /////////////////////////////////////////////////////////////////////////////////////////// - // Columns + /////////////////////////////////////////////////////////////////////////////////////////// + // Columns - public function columns() { - return $this->baseReport->columns(); - } + public function columns() + { + return $this->baseReport->columns(); + } - /////////////////////////////////////////////////////////////////////////////////////////// - // Querying + /////////////////////////////////////////////////////////////////////////////////////////// + // Querying - /** - * Override this method to perform some actions prior to querying. - */ - public function beforeQuery($params) { - } + /** + * Override this method to perform some actions prior to querying. + */ + public function beforeQuery($params) + { + } - /** - * Override this method to perform some actions after querying. - */ - public function afterQuery() {} + /** + * Override this method to perform some actions after querying. + */ + public function afterQuery() + { + } - public function sourceQuery($params) { - if($this->baseReport->hasMethod('sourceRecords')) { - // The default implementation will create a fake query from our sourceRecords() method - return parent::sourceQuery($params); + public function sourceQuery($params) + { + if ($this->baseReport->hasMethod('sourceRecords')) { + // The default implementation will create a fake query from our sourceRecords() method + return parent::sourceQuery($params); + } elseif ($this->baseReport->hasMethod('sourceQuery')) { + $this->beforeQuery($params); + $query = $this->baseReport->sourceQuery($params); + $this->afterQuery(); + return $query; + } else { + user_error("Please override sourceQuery()/sourceRecords() and columns() in your base report", E_USER_ERROR); + } + } - } else if($this->baseReport->hasMethod('sourceQuery')) { - $this->beforeQuery($params); - $query = $this->baseReport->sourceQuery($params); - $this->afterQuery(); - return $query; - - } else { - user_error("Please override sourceQuery()/sourceRecords() and columns() in your base report", E_USER_ERROR); - } - - } - - public function sourceRecords($params = array(), $sort = null, $limit = null) { - $this->beforeQuery($params); - $records = $this->baseReport->sourceRecords($params, $sort, $limit); - $this->afterQuery(); - return $records; - } + public function sourceRecords($params = array(), $sort = null, $limit = null) + { + $this->beforeQuery($params); + $records = $this->baseReport->sourceRecords($params, $sort, $limit); + $this->afterQuery(); + return $records; + } - /////////////////////////////////////////////////////////////////////////////////////////// - // Pass-through + /////////////////////////////////////////////////////////////////////////////////////////// + // Pass-through - public function title() { - return $this->baseReport->title(); - } - - public function group() { - return $this->baseReport->hasMethod('group') ? $this->baseReport->group() : 'Group'; - } - - public function sort() { - return $this->baseReport->hasMethod('sort') ? $this->baseReport->sort() : 0; - } + public function title() + { + return $this->baseReport->title(); + } + + public function group() + { + return $this->baseReport->hasMethod('group') ? $this->baseReport->group() : 'Group'; + } + + public function sort() + { + return $this->baseReport->hasMethod('sort') ? $this->baseReport->sort() : 0; + } - public function description() { - return $this->baseReport->description(); - } + public function description() + { + return $this->baseReport->description(); + } - public function canView($member = null) { - return $this->baseReport->canView($member); - } + public function canView($member = null) + { + return $this->baseReport->canView($member); + } } diff --git a/code/ReportAdmin.php b/code/ReportAdmin.php index 1aa0845f..430aad4a 100644 --- a/code/ReportAdmin.php +++ b/code/ReportAdmin.php @@ -10,180 +10,197 @@ * * @package reports */ -class ReportAdmin extends LeftAndMain implements PermissionProvider { - - private static $url_segment = 'reports'; - - private static $url_rule = '/$ReportClass/$Action'; - - private static $menu_title = 'Reports'; - - private static $template_path = null; // defaults to (project)/templates/email - - private static $tree_class = 'SS_Report'; +class ReportAdmin extends LeftAndMain implements PermissionProvider +{ + + private static $url_segment = 'reports'; + + private static $url_rule = '/$ReportClass/$Action'; + + private static $menu_title = 'Reports'; + + private static $template_path = null; // defaults to (project)/templates/email - private static $url_handlers = array( - '$ReportClass/$Action' => 'handleAction' - ); + private static $tree_class = 'SS_Report'; - /** - * Variable that describes which report we are currently viewing based on - * the URL (gets set in init method). - * - * @var string - */ - protected $reportClass; + private static $url_handlers = array( + '$ReportClass/$Action' => 'handleAction' + ); - protected $reportObject; - - public function init() { - parent::init(); + /** + * Variable that describes which report we are currently viewing based on + * the URL (gets set in init method). + * + * @var string + */ + protected $reportClass; - //set the report we are currently viewing from the URL - $this->reportClass = (isset($this->urlParams['ReportClass']) && $this->urlParams['ReportClass'] !== 'index') - ? $this->urlParams['ReportClass'] - : null; - $allReports = SS_Report::get_reports(); - $this->reportObject = (isset($allReports[$this->reportClass])) ? $allReports[$this->reportClass] : null; + protected $reportObject; + + public function init() + { + parent::init(); - // Set custom options for TinyMCE specific to ReportAdmin - HtmlEditorConfig::get('cms')->setOption('content_css', project() . '/css/editor.css'); - HtmlEditorConfig::get('cms')->setOption('Lang', i18n::get_tinymce_lang()); + //set the report we are currently viewing from the URL + $this->reportClass = (isset($this->urlParams['ReportClass']) && $this->urlParams['ReportClass'] !== 'index') + ? $this->urlParams['ReportClass'] + : null; + $allReports = SS_Report::get_reports(); + $this->reportObject = (isset($allReports[$this->reportClass])) ? $allReports[$this->reportClass] : null; - // Always block the HtmlEditorField.js otherwise it will be sent with an ajax request - Requirements::block(FRAMEWORK_DIR . '/javascript/HtmlEditorField.js'); - Requirements::javascript(REPORTS_DIR . '/javascript/ReportAdmin.js'); - } + // Set custom options for TinyMCE specific to ReportAdmin + HtmlEditorConfig::get('cms')->setOption('content_css', project() . '/css/editor.css'); + HtmlEditorConfig::get('cms')->setOption('Lang', i18n::get_tinymce_lang()); - /** - * Does the parent permission checks, but also - * makes sure that instantiatable subclasses of - * {@link Report} exist. By default, the CMS doesn't - * include any Reports, so there's no point in showing - * - * @param Member $member - * @return boolean - */ - public function canView($member = null) { - if(!$member && $member !== FALSE) $member = Member::currentUser(); + // Always block the HtmlEditorField.js otherwise it will be sent with an ajax request + Requirements::block(FRAMEWORK_DIR . '/javascript/HtmlEditorField.js'); + Requirements::javascript(REPORTS_DIR . '/javascript/ReportAdmin.js'); + } - if(!parent::canView($member)) return false; + /** + * Does the parent permission checks, but also + * makes sure that instantiatable subclasses of + * {@link Report} exist. By default, the CMS doesn't + * include any Reports, so there's no point in showing + * + * @param Member $member + * @return boolean + */ + public function canView($member = null) + { + if (!$member && $member !== false) { + $member = Member::currentUser(); + } - $hasViewableSubclasses = false; - foreach($this->Reports() as $report) { - if($report->canView($member)) return true; - } + if (!parent::canView($member)) { + return false; + } - return false; - } + $hasViewableSubclasses = false; + foreach ($this->Reports() as $report) { + if ($report->canView($member)) { + return true; + } + } - /** - * Return a SS_List of SS_Report subclasses - * that are available for use. - * - * @return SS_List - */ - public function Reports() { - $output = new ArrayList(); - foreach(SS_Report::get_reports() as $report) { - if($report->canView()) $output->push($report); - } - return $output; - } + return false; + } - /** - * Determine if we have reports and need - * to display the "Reports" main menu item - * in the CMS. - * - * The test for an existance of a report - * is done by checking for a subclass of - * "SS_Report" that exists. - * - * @return boolean - */ - public static function has_reports() { - return sizeof(SS_Report::get_reports()) > 0; - } + /** + * Return a SS_List of SS_Report subclasses + * that are available for use. + * + * @return SS_List + */ + public function Reports() + { + $output = new ArrayList(); + foreach (SS_Report::get_reports() as $report) { + if ($report->canView()) { + $output->push($report); + } + } + return $output; + } - /** - * Returns the Breadcrumbs for the ReportAdmin - * @return ArrayList - */ - public function Breadcrumbs($unlinked = false) { - $items = parent::Breadcrumbs($unlinked); - - // The root element should explicitly point to the root node. - // Uses session state for current record otherwise. - $items[0]->Link = singleton('ReportAdmin')->Link(); + /** + * Determine if we have reports and need + * to display the "Reports" main menu item + * in the CMS. + * + * The test for an existance of a report + * is done by checking for a subclass of + * "SS_Report" that exists. + * + * @return boolean + */ + public static function has_reports() + { + return sizeof(SS_Report::get_reports()) > 0; + } - if ($this->reportObject) { - //build breadcrumb trail to the current report - $items->push(new ArrayData(array( - 'Title' => $this->reportObject->title(), - 'Link' => Controller::join_links($this->Link(), '?' . http_build_query(array('q' => $this->request->requestVar('q')))) - ))); - } + /** + * Returns the Breadcrumbs for the ReportAdmin + * @return ArrayList + */ + public function Breadcrumbs($unlinked = false) + { + $items = parent::Breadcrumbs($unlinked); + + // The root element should explicitly point to the root node. + // Uses session state for current record otherwise. + $items[0]->Link = singleton('ReportAdmin')->Link(); - return $items; - } + if ($this->reportObject) { + //build breadcrumb trail to the current report + $items->push(new ArrayData(array( + 'Title' => $this->reportObject->title(), + 'Link' => Controller::join_links($this->Link(), '?' . http_build_query(array('q' => $this->request->requestVar('q')))) + ))); + } - /** - * Returns the link to the report admin section, or the specific report that is currently displayed - * @return String - */ - public function Link($action = null) { - if ($this->reportObject) { - $link = $this->reportObject->getLink($action); - } else { - $link = self::join_links(parent::Link('index'), $action); - } - return $link; - } + return $items; + } - public function providePermissions() { - $title = _t("ReportAdmin.MENUTITLE", LeftAndMain::menu_title_for_class($this->class)); - return array( - "CMS_ACCESS_ReportAdmin" => array( - 'name' => _t('CMSMain.ACCESS', "Access to '{title}' section", array('title' => $title)), - 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access') - ) - ); - } + /** + * Returns the link to the report admin section, or the specific report that is currently displayed + * @return String + */ + public function Link($action = null) + { + if ($this->reportObject) { + $link = $this->reportObject->getLink($action); + } else { + $link = self::join_links(parent::Link('index'), $action); + } + return $link; + } - public function getEditForm($id = null, $fields = null) { - $report = $this->reportObject; - if($report) { - $fields = $report->getCMSFields(); - } else { - // List all reports - $fields = new FieldList(); - $gridFieldConfig = GridFieldConfig::create()->addComponents( - new GridFieldToolbarHeader(), - new GridFieldSortableHeader(), - new GridFieldDataColumns(), - new GridFieldFooter() - ); - $gridField = new GridField('Reports',false, $this->Reports(), $gridFieldConfig); - $columns = $gridField->getConfig()->getComponentByType('GridFieldDataColumns'); - $columns->setDisplayFields(array( - 'title' => _t('ReportAdmin.ReportTitle', 'Title'), - )); + public function providePermissions() + { + $title = _t("ReportAdmin.MENUTITLE", LeftAndMain::menu_title_for_class($this->class)); + return array( + "CMS_ACCESS_ReportAdmin" => array( + 'name' => _t('CMSMain.ACCESS', "Access to '{title}' section", array('title' => $title)), + 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access') + ) + ); + } - $columns->setFieldFormatting(array( - 'title' => '$value ($Count)' - )); - $gridField->addExtraClass('all-reports-gridfield'); - $fields->push($gridField); - } + public function getEditForm($id = null, $fields = null) + { + $report = $this->reportObject; + if ($report) { + $fields = $report->getCMSFields(); + } else { + // List all reports + $fields = new FieldList(); + $gridFieldConfig = GridFieldConfig::create()->addComponents( + new GridFieldToolbarHeader(), + new GridFieldSortableHeader(), + new GridFieldDataColumns(), + new GridFieldFooter() + ); + $gridField = new GridField('Reports', false, $this->Reports(), $gridFieldConfig); + $columns = $gridField->getConfig()->getComponentByType('GridFieldDataColumns'); + $columns->setDisplayFields(array( + 'title' => _t('ReportAdmin.ReportTitle', 'Title'), + )); - $actions = new FieldList(); - $form = new Form($this, "EditForm", $fields, $actions); - $form->addExtraClass('cms-edit-form cms-panel-padded center ' . $this->BaseCSSClasses()); - $form->loadDataFrom($this->request->getVars()); + $columns->setFieldFormatting(array( + 'title' => '$value ($Count)' + )); + $gridField->addExtraClass('all-reports-gridfield'); + $fields->push($gridField); + } - $this->extend('updateEditForm', $form); + $actions = new FieldList(); + $form = new Form($this, "EditForm", $fields, $actions); + $form->addExtraClass('cms-edit-form cms-panel-padded center ' . $this->BaseCSSClasses()); + $form->loadDataFrom($this->request->getVars()); - return $form; - } + $this->extend('updateEditForm', $form); + + return $form; + } } diff --git a/code/SideReport.php b/code/SideReport.php index 61832feb..59ec25b4 100644 --- a/code/SideReport.php +++ b/code/SideReport.php @@ -5,96 +5,105 @@ * * @package reports */ -class SideReportView extends ViewableData { +class SideReportView extends ViewableData +{ - protected $controller, $report; - protected $parameters; - - public function __construct($controller, $report) { - $this->controller = $controller; - $this->report = $report; - parent::__construct(); - } - - public function group() { - return _t('SideReport.OtherGroupTitle', "Other"); - } - - public function sort() { - return 0; - } - - public function setParameters($parameters) { - $this->parameters = $parameters; - } - - public function forTemplate() { - $records = $this->report->records($this->parameters); - $columns = $this->report->columns(); - - if($records && $records->Count()) { - $result = "\n"; - } else { - $result = "

" . - _t( - 'SideReport.REPEMPTY', - 'The {title} report is empty.', - array('title' => $this->report->title()) - ) - . "

"; - } - return $result; - } - - protected function formatValue($record, $source, $info) { - // Field sources - //if(is_string($source)) { - $val = Convert::raw2xml($record->$source); - //} else { - // $val = $record->val($source[0], $source[1]); - //} - - // Casting, a la TableListField. We're deep-calling a helper method on TableListField that - // should probably be pushed elsewhere... - if(!empty($info['casting'])) { - $val = TableListField::getCastedValue($val, $info['casting']); - } - - // Formatting, a la TableListField - if(!empty($info['formatting'])) { - $format = str_replace('$value', "__VAL__", $info['formatting']); - $format = preg_replace('/\$([A-Za-z0-9-_]+)/','$record->$1', $format); - $format = str_replace('__VAL__', '$val', $format); - $val = eval('return "' . $format . '";'); - } + protected $controller, $report; + protected $parameters; + + public function __construct($controller, $report) + { + $this->controller = $controller; + $this->report = $report; + parent::__construct(); + } + + public function group() + { + return _t('SideReport.OtherGroupTitle', "Other"); + } + + public function sort() + { + return 0; + } + + public function setParameters($parameters) + { + $this->parameters = $parameters; + } + + public function forTemplate() + { + $records = $this->report->records($this->parameters); + $columns = $this->report->columns(); + + if ($records && $records->Count()) { + $result = "\n"; + } else { + $result = "

" . + _t( + 'SideReport.REPEMPTY', + 'The {title} report is empty.', + array('title' => $this->report->title()) + ) + . "

"; + } + return $result; + } + + protected function formatValue($record, $source, $info) + { + // Field sources + //if(is_string($source)) { + $val = Convert::raw2xml($record->$source); + //} else { + // $val = $record->val($source[0], $source[1]); + //} - $prefix = empty($info['newline']) ? "" : "
"; + // Casting, a la TableListField. We're deep-calling a helper method on TableListField that + // should probably be pushed elsewhere... + if (!empty($info['casting'])) { + $val = TableListField::getCastedValue($val, $info['casting']); + } + + // Formatting, a la TableListField + if (!empty($info['formatting'])) { + $format = str_replace('$value', "__VAL__", $info['formatting']); + $format = preg_replace('/\$([A-Za-z0-9-_]+)/', '$record->$1', $format); + $format = str_replace('__VAL__', '$val', $format); + $val = eval('return "' . $format . '";'); + } - - $classClause = ""; - if(isset($info['title'])) { - $cssClass = preg_replace('/[^A-Za-z0-9]+/', '', $info['title']); - $classClause = "class=\"$cssClass\""; - } - - if(isset($info['link']) && $info['link']) { - $linkBase = singleton('CMSPageEditController')->Link('show') . '/'; - $link = ($info['link'] === true) ? $linkBase . $record->ID : $info['link']; - return $prefix . "$val"; - } else { - return $prefix . "$val"; - } - } + $prefix = empty($info['newline']) ? "" : "
"; + + + $classClause = ""; + if (isset($info['title'])) { + $cssClass = preg_replace('/[^A-Za-z0-9]+/', '', $info['title']); + $classClause = "class=\"$cssClass\""; + } + + if (isset($info['link']) && $info['link']) { + $linkBase = singleton('CMSPageEditController')->Link('show') . '/'; + $link = ($info['link'] === true) ? $linkBase . $record->ID : $info['link']; + return $prefix . "$val"; + } else { + return $prefix . "$val"; + } + } } /** @@ -104,12 +113,14 @@ class SideReportView extends ViewableData { * * @package reports */ -class SideReportWrapper extends SS_ReportWrapper { - public function columns() { - if($this->baseReport->hasMethod('sideReportColumns')) { - return $this->baseReport->sideReportColumns(); - } else { - return parent::columns(); - } - } -} \ No newline at end of file +class SideReportWrapper extends SS_ReportWrapper +{ + public function columns() + { + if ($this->baseReport->hasMethod('sideReportColumns')) { + return $this->baseReport->sideReportColumns(); + } else { + return parent::columns(); + } + } +} diff --git a/tests/ReportTest.php b/tests/ReportTest.php index dada8a4d..14c85826 100644 --- a/tests/ReportTest.php +++ b/tests/ReportTest.php @@ -4,131 +4,149 @@ * @package reports * @subpackage tests */ -class ReportTest extends SapphireTest { +class ReportTest extends SapphireTest +{ - public function testGetReports() { - $reports = SS_Report::get_reports(); - $this->assertNotNull($reports, "Reports returned"); - $previousSort = 0; - foreach($reports as $report) { - $this->assertGreaterThanOrEqual($previousSort, $report->sort, "Reports are in correct sort order"); - $previousSort = $report->sort; - } - } + public function testGetReports() + { + $reports = SS_Report::get_reports(); + $this->assertNotNull($reports, "Reports returned"); + $previousSort = 0; + foreach ($reports as $report) { + $this->assertGreaterThanOrEqual($previousSort, $report->sort, "Reports are in correct sort order"); + $previousSort = $report->sort; + } + } - public 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'); + public 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'); - //exclude one report - SS_Report::add_excluded_reports('ReportTest_FakeTest'); + //exclude one report + SS_Report::add_excluded_reports('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'); + $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'); - //exclude two reports - SS_Report::add_excluded_reports(array('ReportTest_FakeTest','ReportTest_FakeTest2')); + //exclude two reports + SS_Report::add_excluded_reports(array('ReportTest_FakeTest', 'ReportTest_FakeTest2')); - $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'); - $this->assertNotContains('ReportTest_FakeTest2',$reportNames,'ReportTest_FakeTest2 is NOT in reports list'); - } + $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'); + $this->assertNotContains('ReportTest_FakeTest2', $reportNames, 'ReportTest_FakeTest2 is NOT in reports list'); + } - public function testAbstractClassesAreExcluded() { - $reports = SS_Report::get_reports(); - $reportNames = array(); - foreach($reports as $report) { - $reportNames[] = $report->class; - } - $this->assertNotContains('ReportTest_FakeTest_Abstract', - $reportNames, - 'ReportTest_FakeTest_Abstract is NOT in reports list as it is abstract'); - } + public function testAbstractClassesAreExcluded() + { + $reports = SS_Report::get_reports(); + $reportNames = array(); + foreach ($reports as $report) { + $reportNames[] = $report->class; + } + $this->assertNotContains('ReportTest_FakeTest_Abstract', + $reportNames, + 'ReportTest_FakeTest_Abstract is NOT in reports list as it is abstract'); + } } /** * @package reports * @subpackage tests */ -class ReportTest_FakeTest extends SS_Report implements TestOnly { - public function title() { - return 'Report title'; - } - public function columns() { - return array( - "Title" => array( - "title" => "Page Title" - ) - ); - } - public function sourceRecords($params, $sort, $limit) { - return new ArrayList(); - } +class ReportTest_FakeTest extends SS_Report implements TestOnly +{ + public function title() + { + return 'Report title'; + } + public function columns() + { + return array( + "Title" => array( + "title" => "Page Title" + ) + ); + } + public function sourceRecords($params, $sort, $limit) + { + return new ArrayList(); + } - public function sort() { - return 100; - } + public function sort() + { + return 100; + } } /** * @package reports * @subpackage tests */ -class ReportTest_FakeTest2 extends SS_Report implements TestOnly { - public function title() { - return 'Report title 2'; - } - public function columns() { - return array( - "Title" => array( - "title" => "Page Title 2" - ) - ); - } - public function sourceRecords($params, $sort, $limit) { - return new ArrayList(); - } +class ReportTest_FakeTest2 extends SS_Report implements TestOnly +{ + public function title() + { + return 'Report title 2'; + } + public function columns() + { + return array( + "Title" => array( + "title" => "Page Title 2" + ) + ); + } + public function sourceRecords($params, $sort, $limit) + { + return new ArrayList(); + } - public function sort() { - return 98; - } + public function sort() + { + return 98; + } } /** * @package reports * @subpackage tests */ -abstract class ReportTest_FakeTest_Abstract extends SS_Report implements TestOnly { - - public function title() { - return 'Report title Abstract'; - } +abstract class ReportTest_FakeTest_Abstract extends SS_Report implements TestOnly +{ + + public function title() + { + return 'Report title Abstract'; + } - public function columns() { - return array( - "Title" => array( - "title" => "Page Title Abstract" - ) - ); - } - public function sourceRecords($params, $sort, $limit) { - return new ArrayList(); - } + public function columns() + { + return array( + "Title" => array( + "title" => "Page Title Abstract" + ) + ); + } + public function sourceRecords($params, $sort, $limit) + { + return new ArrayList(); + } - public function sort() { - return 5; - } + public function sort() + { + return 5; + } } -