mirror of
https://github.com/silverstripe/silverstripe-reports
synced 2024-10-22 11:05:53 +02:00
Merge branch 'integration'
This commit is contained in:
commit
73a466c927
@ -29,13 +29,6 @@ Director::addRules(1, array(
|
|||||||
'$URLSegment//$Action/$ID/$OtherID' => 'ModelAsController',
|
'$URLSegment//$Action/$ID/$OtherID' => 'ModelAsController',
|
||||||
));
|
));
|
||||||
|
|
||||||
// Register default side reports
|
|
||||||
SS_Report::register("SideReport", "SideReport_EmptyPages");
|
|
||||||
SS_Report::register("SideReport", "SideReport_RecentlyEdited");
|
|
||||||
if (class_exists('SubsiteReportWrapper')) SS_Report::register('ReportAdmin', 'SubsiteReportWrapper("BrokenLinksReport")',-20);
|
|
||||||
else SS_Report::register('ReportAdmin', 'BrokenLinksReport',-20);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the default internal shortcodes.
|
* Register the default internal shortcodes.
|
||||||
*/
|
*/
|
||||||
|
@ -44,6 +44,9 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
|
|||||||
'SiteTreeAsUL',
|
'SiteTreeAsUL',
|
||||||
'getshowdeletedsubtree',
|
'getshowdeletedsubtree',
|
||||||
'batchactions',
|
'batchactions',
|
||||||
|
'ListView',
|
||||||
|
'getListView',
|
||||||
|
'listchildren',
|
||||||
);
|
);
|
||||||
|
|
||||||
public function init() {
|
public function init() {
|
||||||
@ -157,7 +160,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
|
|||||||
function SearchForm() {
|
function SearchForm() {
|
||||||
// get all page types in a dropdown-compatible format
|
// get all page types in a dropdown-compatible format
|
||||||
$pageTypes = SiteTree::page_type_classes();
|
$pageTypes = SiteTree::page_type_classes();
|
||||||
array_unshift($pageTypes, _t('CMSMain.PAGETYPEANYOPT','Any'));
|
|
||||||
$pageTypes = array_combine($pageTypes, $pageTypes);
|
$pageTypes = array_combine($pageTypes, $pageTypes);
|
||||||
asort($pageTypes);
|
asort($pageTypes);
|
||||||
|
|
||||||
@ -456,6 +458,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
|
|||||||
* @return Form
|
* @return Form
|
||||||
*/
|
*/
|
||||||
public function getEditForm($id = null, $fields = null) {
|
public function getEditForm($id = null, $fields = null) {
|
||||||
|
|
||||||
if(!$id) $id = $this->currentPageID();
|
if(!$id) $id = $this->currentPageID();
|
||||||
$form = parent::getEditForm($id);
|
$form = parent::getEditForm($id);
|
||||||
|
|
||||||
@ -528,7 +531,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->extend('updateEditForm', $form);
|
$this->extend('updateEditForm', $form);
|
||||||
|
|
||||||
return $form;
|
return $form;
|
||||||
} else if($id) {
|
} else if($id) {
|
||||||
return new Form($this, "EditForm", new FieldList(
|
return new Form($this, "EditForm", new FieldList(
|
||||||
@ -537,6 +539,95 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pages meet a certain criteria as {@see CMSSiteTreeFilter} or the subpages of a parent page
|
||||||
|
* defaulting to no filter and show all pages in first level.
|
||||||
|
* Doubles as search results, if any search parameters are set through {@link SearchForm()}.
|
||||||
|
*
|
||||||
|
* @return SS_List
|
||||||
|
*/
|
||||||
|
public function getList(&$filterOn) {
|
||||||
|
$list = new DataList($this->stat('tree_class'));
|
||||||
|
|
||||||
|
$request = $this->request;
|
||||||
|
$filter = null;
|
||||||
|
$ids = array();
|
||||||
|
if($filterClass = $request->requestVar('FilterClass')){
|
||||||
|
if(!is_subclass_of($filterClass, 'CMSSiteTreeFilter')) {
|
||||||
|
throw new Exception(sprintf('Invalid filter class passed: %s', $filterClass));
|
||||||
|
}
|
||||||
|
$filter = new $filterClass($request->requestVars());
|
||||||
|
$filterOn = true;
|
||||||
|
foreach($pages=$filter->pagesIncluded() as $pageMap){
|
||||||
|
$ids[] = $pageMap['ID'];
|
||||||
|
}
|
||||||
|
if(count($ids)) $list->where('"'.$this->stat('tree_class').'"."ID" IN ('.implode(",", $ids).')');
|
||||||
|
}else{
|
||||||
|
$parentID = 0;
|
||||||
|
if($this->urlParams['Action'] == 'listchildren' && $this->urlParams['ID']){
|
||||||
|
$parentID = $this->urlParams['ID'];
|
||||||
|
}
|
||||||
|
$list->filter("ParentID", $parentID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getListView(){
|
||||||
|
$filterOn = false;
|
||||||
|
$list = $this->getList($filterOn);
|
||||||
|
$gridFieldConfig = GridFieldConfig::create()->addComponents(
|
||||||
|
new GridFieldSortableHeader(),
|
||||||
|
new GridFieldDataColumns(),
|
||||||
|
new GridFieldPaginator(15)
|
||||||
|
);
|
||||||
|
$gridField = new GridField('Page','Pages', $list, $gridFieldConfig);
|
||||||
|
|
||||||
|
if($filterOn){
|
||||||
|
$gridField->setDisplayFields(array(
|
||||||
|
'getTreeTitle' => _t('SiteTree.PAGETITLE', 'Page Title'),
|
||||||
|
'Created' => _t('SiteTree.CREATED', 'Date Created'),
|
||||||
|
'LastEdited' => _t('SiteTree.LASTUPDATED', 'Last Updated'),
|
||||||
|
));
|
||||||
|
}else{
|
||||||
|
$gridField->setDisplayFields(array(
|
||||||
|
'listChildrenLink' => "",
|
||||||
|
'getTreeTitle' => _t('SiteTree.PAGETITLE', 'Page Title'),
|
||||||
|
'Created' => _t('SiteTree.CREATED', 'Date Created'),
|
||||||
|
'LastEdited' => _t('SiteTree.LASTUPDATED', 'Last Updated'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$gridField->setFieldCasting(array(
|
||||||
|
'Created' => 'Date->Ago',
|
||||||
|
'LastEdited' => 'Date->Ago',
|
||||||
|
));
|
||||||
|
|
||||||
|
$gridField->setFieldFormatting(array(
|
||||||
|
'getTreeTitle' => '<a class=\"cms-panel-link\" href=\"admin/page/edit/show/$ID\">$value</a>'
|
||||||
|
));
|
||||||
|
|
||||||
|
$listview = new Form(
|
||||||
|
$this,
|
||||||
|
'ListView',
|
||||||
|
new FieldList($gridField),
|
||||||
|
new FieldList()
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->extend('updateListView', $listview);
|
||||||
|
|
||||||
|
$listview->disableSecurityToken();
|
||||||
|
return $listview;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getListViewHTML(){
|
||||||
|
return $this->getListView()->forTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ListView() {
|
||||||
|
return $this->getListView();
|
||||||
|
}
|
||||||
|
|
||||||
public function currentPageID() {
|
public function currentPageID() {
|
||||||
$id = parent::currentPageID();
|
$id = parent::currentPageID();
|
||||||
|
|
||||||
@ -550,6 +641,14 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
|
|||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function listchildren(){
|
||||||
|
if(Director::is_ajax()){
|
||||||
|
return $this->getListViewHTML();
|
||||||
|
}else{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------//
|
//------------------------------------------------------------------------------------------//
|
||||||
// Data saving handlers
|
// Data saving handlers
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ class CMSSiteTreeFilter_Search extends CMSSiteTreeFilter {
|
|||||||
switch($name) {
|
switch($name) {
|
||||||
// Match against URLSegment, Title, MenuTitle & Content
|
// Match against URLSegment, Title, MenuTitle & Content
|
||||||
case 'Term':
|
case 'Term':
|
||||||
$where[] = "\"URLSegment\" LIKE '%$val%' OR \"Title\" LIKE '%$val%' OR \"MenuTitle\" LIKE '%$val%' OR \"Content\" LIKE '%$val%'";
|
if($val) $where[] = "\"URLSegment\" LIKE '%$val%' OR \"Title\" LIKE '%$val%' OR \"MenuTitle\" LIKE '%$val%' OR \"Content\" LIKE '%$val%'";
|
||||||
break;
|
break;
|
||||||
// Match against date
|
// Match against date
|
||||||
case 'LastEditedFrom':
|
case 'LastEditedFrom':
|
||||||
|
@ -458,7 +458,7 @@ HTML;
|
|||||||
Email: $username<br />
|
Email: $username<br />
|
||||||
Password: $password<br />
|
Password: $password<br />
|
||||||
</p>
|
</p>
|
||||||
<div style="background:#ddd; border:1px solid #ccc; padding:5px; margin:5px;"><img src="cms/images/dialogs/alert.gif" style="border: none; margin-right: 10px; float: left;" /><p style="color:red;">For security reasons you should now delete the install files, unless you are planning to reinstall later (<em>requires admin login, see above</em>). The web server also now only needs write access to the "assets" folder, you can remove write access from all other folders. <a href="home/deleteinstallfiles" style="text-align: center;">Click here to delete the install files.</a></p></div>
|
<div style="background:#fcf8f2; border-radius:4px; border: 1px solid #ffc28b; padding:5px; margin:5px;"><img src="cms/images/dialogs/alert.gif" style="border: none; margin-right: 10px; float: left; height:48px; width:48px" /><p style="color: #cb6a1c; margin-bottom:0;">For security reasons you should now delete the install files, unless you are planning to reinstall later (<em>requires admin login, see above</em>). The web server also now only needs write access to the "assets" folder, you can remove write access from all other folders. <a href="home/deleteinstallfiles" style="text-align: center;">Click here to delete the install files.</a></p></div>
|
||||||
HTML
|
HTML
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider {
|
|||||||
|
|
||||||
static $url_segment = 'reports';
|
static $url_segment = 'reports';
|
||||||
|
|
||||||
static $url_rule = '/$Action/$ID';
|
static $url_rule = '/$ReportClass/$Action';
|
||||||
|
|
||||||
static $menu_title = 'Reports';
|
static $menu_title = 'Reports';
|
||||||
|
|
||||||
@ -23,9 +23,26 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider {
|
|||||||
|
|
||||||
static $tree_class = 'SS_Report';
|
static $tree_class = 'SS_Report';
|
||||||
|
|
||||||
|
public static $url_handlers = array(
|
||||||
|
'$ReportClass/$Action' => 'handleAction'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable that describes which report we are currently viewing based on the URL (gets set in init method)
|
||||||
|
* @var String
|
||||||
|
*/
|
||||||
|
protected $reportClass;
|
||||||
|
|
||||||
|
protected $reportObject;
|
||||||
|
|
||||||
public function init() {
|
public function init() {
|
||||||
parent::init();
|
parent::init();
|
||||||
|
|
||||||
|
//set the report we are currently viewing from the URL
|
||||||
|
$this->reportClass = (isset($this->urlParams['ReportClass'])) ? $this->urlParams['ReportClass'] : null;
|
||||||
|
$allReports = SS_Report::get_reports();
|
||||||
|
$this->reportObject = (isset($allReports[$this->reportClass])) ? $allReports[$this->reportClass] : null;
|
||||||
|
|
||||||
Requirements::css(CMS_DIR . '/css/screen.css');
|
Requirements::css(CMS_DIR . '/css/screen.css');
|
||||||
|
|
||||||
// Set custom options for TinyMCE specific to ReportAdmin
|
// Set custom options for TinyMCE specific to ReportAdmin
|
||||||
@ -58,12 +75,6 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function currentPageID() {
|
|
||||||
$id = parent::currentPageID();
|
|
||||||
$reports = SS_Report::get_reports('ReportAdmin');
|
|
||||||
return (isset($reports[$id])) ? $reports[$id] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a SS_List of SS_Report subclasses
|
* Return a SS_List of SS_Report subclasses
|
||||||
* that are available for use.
|
* that are available for use.
|
||||||
@ -72,7 +83,7 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider {
|
|||||||
*/
|
*/
|
||||||
public function Reports() {
|
public function Reports() {
|
||||||
$output = new ArrayList();
|
$output = new ArrayList();
|
||||||
foreach(SS_Report::get_reports('ReportAdmin') as $report) {
|
foreach(SS_Report::get_reports() as $report) {
|
||||||
if($report->canView()) $output->push($report);
|
if($report->canView()) $output->push($report);
|
||||||
}
|
}
|
||||||
return $output;
|
return $output;
|
||||||
@ -90,12 +101,39 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider {
|
|||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public static function has_reports() {
|
public static function has_reports() {
|
||||||
return sizeof(SS_Report::get_reports('ReportAdmin')) > 0;
|
return sizeof(SS_Report::get_reports()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatereport() {
|
/**
|
||||||
// FormResponse::load_form($this->EditForm()->forTemplate());
|
* Returns the Breadcrumbs for the ReportAdmin
|
||||||
// return FormResponse::respond();
|
* @return ArrayList
|
||||||
|
*/
|
||||||
|
public function Breadcrumbs() {
|
||||||
|
$items = parent::Breadcrumbs();
|
||||||
|
|
||||||
|
// The root element should explicitly point to the root node.
|
||||||
|
// Uses session state for current record otherwise.
|
||||||
|
$items[0]->Link = singleton('ReportAdmin')->Link();
|
||||||
|
|
||||||
|
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'))))
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the link to the report admin section, or the specific report that is currently displayed
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public function Link($action = null) {
|
||||||
|
$link = parent::Link($action);
|
||||||
|
if ($this->reportObject) $link = $this->reportObject->getLink($action);
|
||||||
|
return $link;
|
||||||
}
|
}
|
||||||
|
|
||||||
function providePermissions() {
|
function providePermissions() {
|
||||||
@ -107,5 +145,74 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEditForm($id = null, $fields = null) {
|
||||||
|
$fields = new FieldList();
|
||||||
|
|
||||||
|
$report = $this->reportObject;
|
||||||
|
|
||||||
|
if($report) {
|
||||||
|
// List all reports
|
||||||
|
$gridFieldConfig = GridFieldConfig::create()->addComponents(
|
||||||
|
new GridFieldToolbarHeader(),
|
||||||
|
new GridFieldSortableHeader(),
|
||||||
|
new GridFieldDataColumns(),
|
||||||
|
new GridFieldPaginator(),
|
||||||
|
new GridFieldPrintButton(),
|
||||||
|
new GridFieldExportButton()
|
||||||
|
);
|
||||||
|
$gridField = new GridField('Report',$report->title(), $report->sourceRecords(array(), null, null), $gridFieldConfig);
|
||||||
|
$displayFields = array();
|
||||||
|
$fieldCasting = array();
|
||||||
|
$fieldFormatting = array();
|
||||||
|
|
||||||
|
// Parse the column information
|
||||||
|
foreach($report->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] = '<a href=\"' . $link . '/$ID\">$value</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$displayFields[$source] = isset($info['title']) ? $info['title'] : $source;
|
||||||
|
}
|
||||||
|
$gridField->setDisplayFields($displayFields);
|
||||||
|
$gridField->setFieldCasting($fieldCasting);
|
||||||
|
$gridField->setFieldFormatting($fieldFormatting);
|
||||||
|
|
||||||
|
$fields->push($gridField);
|
||||||
|
} else {
|
||||||
|
// List all reports
|
||||||
|
$gridFieldConfig = GridFieldConfig::create()->addComponents(
|
||||||
|
new GridFieldToolbarHeader(),
|
||||||
|
new GridFieldSortableHeader(),
|
||||||
|
new GridFieldDataColumns(),
|
||||||
|
new GridFieldPaginator()
|
||||||
|
);
|
||||||
|
$gridField = new GridField('Reports','Reports', $this->Reports(), $gridFieldConfig);
|
||||||
|
$gridField->setDisplayFields(array(
|
||||||
|
'title' => 'Title',
|
||||||
|
'description' => 'Description'
|
||||||
|
));
|
||||||
|
$gridField->setFieldFormatting(array(
|
||||||
|
'title' => '<a href=\"$Link\">$value</a>'
|
||||||
|
));
|
||||||
|
$gridField->addExtraClass('all-reports-gridfield');
|
||||||
|
$fields->push($gridField);
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions = new FieldList();
|
||||||
|
$form = new Form($this, "EditForm", $fields, $actions);
|
||||||
|
$form->addExtraClass('cms-edit-form cms-panel-padded center ' . $this->BaseCSSClasses());
|
||||||
|
|
||||||
|
$this->extend('updateEditForm', $form);
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2476,6 +2476,13 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
|
|||||||
return $this->getTreeTitle();
|
return $this->getTreeTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listChildrenLink(){
|
||||||
|
if($num = $this->numChildren()){
|
||||||
|
$link = singleton('CMSPagesController')->Link('listchildren')."/".$this->ID;
|
||||||
|
return '<a href="'.$link.'" class="list-children-link">'.$num.'</a>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getTreeTitle will return three <span> html DOM elements, an empty <span> with
|
* getTreeTitle will return three <span> html DOM elements, an empty <span> with
|
||||||
* the class 'jstree-pageicon' in front, following by a <span> wrapping around its
|
* the class 'jstree-pageicon' in front, following by a <span> wrapping around its
|
||||||
|
@ -35,19 +35,13 @@
|
|||||||
* Showing reports to the user
|
* Showing reports to the user
|
||||||
* ===========================
|
* ===========================
|
||||||
*
|
*
|
||||||
* Right now, all subclasses of SS_Report will be shown in the ReportAdmin. However, we are planning
|
* Right now, all subclasses of SS_Report will be shown in the ReportAdmin. In SS3 there is only
|
||||||
* on adding an explicit registration mechanism, so that you can decide which reports go in the
|
* one place where reports can go, so this class is greatly simplifed from from its version in SS2.
|
||||||
* report admin, and which go elsewhere (such as the side panel in the CMS).
|
|
||||||
*
|
*
|
||||||
* @package cms
|
* @package cms
|
||||||
* @subpackage reports
|
* @subpackage reports
|
||||||
*/
|
*/
|
||||||
class SS_Report extends ViewableData {
|
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,
|
* This is the title of the report,
|
||||||
* used by the ReportAdmin templates.
|
* used by the ReportAdmin templates.
|
||||||
@ -71,6 +65,22 @@ class SS_Report extends ViewableData {
|
|||||||
*/
|
*/
|
||||||
protected $dataClass = 'SiteTree';
|
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.
|
* Return the title of this report.
|
||||||
*
|
*
|
||||||
@ -93,22 +103,12 @@ class SS_Report extends ViewableData {
|
|||||||
return $this->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.
|
* Return the {@link SQLQuery} that provides your report data.
|
||||||
*/
|
*/
|
||||||
function sourceQuery($params) {
|
function sourceQuery($params) {
|
||||||
if($this->hasMethod('sourceRecords')) {
|
if($this->hasMethod('sourceRecords')) {
|
||||||
$query = new SS_Report_FakeQuery($this, 'sourceRecords', $params);
|
$query = new SS_Report_FakeQuery($this, 'sourceRecords', $params);
|
||||||
$query->setSortColumnMethod('sortColumns');
|
|
||||||
return $query;
|
return $query;
|
||||||
} else {
|
} else {
|
||||||
user_error("Please override sourceQuery()/sourceRecords() and columns() or, if necessary, override getReportField()", E_USER_ERROR);
|
user_error("Please override sourceQuery()/sourceRecords() and columns() or, if necessary, override getReportField()", E_USER_ERROR);
|
||||||
@ -126,28 +126,6 @@ class SS_Report extends ViewableData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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()}
|
|
||||||
*/
|
|
||||||
function columns() {
|
|
||||||
user_error("Please override sourceQuery() and columns() or, if necessary, override getReportField()", E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortColumns() {
|
|
||||||
return array_keys($this->columns());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the number of records in this report with no filters applied.
|
|
||||||
*/
|
|
||||||
function count() {
|
|
||||||
return (int)$this->sourceQuery(array())->unlimitedRowCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the data class for this report
|
* Return the data class for this report
|
||||||
@ -156,6 +134,93 @@ class SS_Report extends ViewableData {
|
|||||||
return $this->dataClass;
|
return $this->dataClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLink($action = null) {
|
||||||
|
return Controller::join_links(
|
||||||
|
'admin/reports/',
|
||||||
|
"$this->class",
|
||||||
|
'/', // trailing slash needed if $action is null!
|
||||||
|
"$action"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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) {
|
||||||
|
Deprecation::notice('3.0', 'All subclasses of SS_Report now appear in the report admin, no need to register');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 3.0
|
||||||
|
* All subclasses of SS_Report now appear in the report admin, no need to register or unregister.
|
||||||
|
*/
|
||||||
|
static function unregister($list, $reportClass) {
|
||||||
|
self::add_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
|
||||||
|
*/
|
||||||
|
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 function get_excluded_reports() {
|
||||||
|
return self::$excluded_reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the SS_Report objects making up the given list.
|
||||||
|
* @return ArrayList an arraylist 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[$report] = $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.
|
* Returns a FieldList with which to create the CMS editing form.
|
||||||
@ -273,72 +338,10 @@ class SS_Report extends ViewableData {
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function TreeTitle() {
|
function TreeTitle() {
|
||||||
return $this->title();/* . ' (' . $this->count() . ')'; - this is too slow atm */
|
return $this->title();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,22 @@
|
|||||||
(function($) {
|
(function($) {
|
||||||
$.entwine('ss', function($){
|
$.entwine('ss', function($){
|
||||||
|
|
||||||
|
$('#pages-controller-cms-content').entwine({
|
||||||
|
/**
|
||||||
|
* we need to check if the current url contains a sub url 'listchildren' and
|
||||||
|
* select its list view if it does, otherwise use the default tabs() call which is
|
||||||
|
* using cookie options
|
||||||
|
*/
|
||||||
|
redrawTabs: function() {
|
||||||
|
if(window.location.href.match(/listchildren/)){
|
||||||
|
this.rewriteHashlinks();
|
||||||
|
this.tabs({ selected: 1 });
|
||||||
|
}else{
|
||||||
|
this._super();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class: #Form_SearchForm
|
* Class: #Form_SearchForm
|
||||||
*
|
*
|
||||||
@ -49,7 +65,9 @@
|
|||||||
|
|
||||||
this.find(':submit[name=action_doSearchTree]').addClass('loading');
|
this.find(':submit[name=action_doSearchTree]').addClass('loading');
|
||||||
|
|
||||||
this._reloadSitetree(this.serializeArray());
|
var params = this.serializeArray();
|
||||||
|
this._reloadSitetree(params);
|
||||||
|
this._reloadListview(params);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
@ -64,8 +82,11 @@
|
|||||||
// TODO Enable checkbox tree controls
|
// TODO Enable checkbox tree controls
|
||||||
this.find('.checkboxAboveTree :checkbox').attr('disabled', 'false');
|
this.find('.checkboxAboveTree :checkbox').attr('disabled', 'false');
|
||||||
|
|
||||||
|
this.resetForm();
|
||||||
|
//the dropdown field wont be reset due to it is applied to chosen.js so need to treated specially
|
||||||
|
this.find('.field.dropdown select').val('').trigger("liszt:updated");
|
||||||
this._reloadSitetree();
|
this._reloadSitetree();
|
||||||
|
this._reloadListview();
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -87,6 +108,45 @@
|
|||||||
errorMessage('Could not filter site tree<br />' + response.responseText);
|
errorMessage('Could not filter site tree<br />' + response.responseText);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_reloadListview: function(params){
|
||||||
|
$('.cms-list').refresh(params);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#cms-content-listview .cms-list').entwine({
|
||||||
|
refresh: function(params){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: this.data('url-list'),
|
||||||
|
data: params,
|
||||||
|
success: function(data, status, xhr) {
|
||||||
|
self.html(data);
|
||||||
|
},
|
||||||
|
error: function(xhr, status, e) {
|
||||||
|
errorMessage(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
replace: function(url){
|
||||||
|
if(window.History.enabled) {
|
||||||
|
var container = $('.cms-container')
|
||||||
|
container.loadPanel(url, '', {selector: '.cms-list form'});
|
||||||
|
} else {
|
||||||
|
window.location = $.path.makeUrlAbsolute(url, $('base').attr('href'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.cms-list .list-children-link').entwine({
|
||||||
|
onclick: function(e) {
|
||||||
|
this.closest('.cms-list').replace(this.attr('href'));
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="cms-content center ss-tabset $BaseCSSClasses" data-layout-type="border">
|
<div id="pages-controller-cms-content" class="cms-content center ss-tabset $BaseCSSClasses" data-layout-type="border">
|
||||||
|
|
||||||
<div class="cms-content-header north">
|
<div class="cms-content-header north">
|
||||||
<div>
|
<div>
|
||||||
@ -11,13 +11,13 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href="#cms-content-treeview" class="content-treeview"><% _t('CMSPagesController.TreeView', 'Tree View') %></a>
|
<a href="#cms-content-treeview" class="content-treeview"><% _t('CMSPagesController.TreeView', 'Tree View') %></a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#cms-content-listview" class="content-listview"><% _t('CMSPagesController.ListView', 'List View') %></a>
|
||||||
|
</li>
|
||||||
<!--
|
<!--
|
||||||
<li>
|
<li>
|
||||||
<a href="#cms-content-galleryview" class="content-galleryview"><% _t('CMSPagesController.GalleryView', 'Gallery View') %></a>
|
<a href="#cms-content-galleryview" class="content-galleryview"><% _t('CMSPagesController.GalleryView', 'Gallery View') %></a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a href="#cms-content-listview" class="content-listview"><% _t('CMSPagesController.ListView', 'List View') %></a>
|
|
||||||
</li>
|
|
||||||
-->
|
-->
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -44,11 +44,16 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--
|
|
||||||
<div id="cms-content-listview">
|
<div id="cms-content-listview">
|
||||||
<i>Not implemented yet</i>
|
<div class="cms-content-toolbar">
|
||||||
</div>
|
<% include CMSPagesController_ContentToolActions %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cms-list" data-url-list="$Link(getListViewHTML)">
|
||||||
|
$ListView
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
<div id="cms-content-galleryview">
|
<div id="cms-content-galleryview">
|
||||||
<i>Not implemented yet</i>
|
<i>Not implemented yet</i>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
<div class="cms-actions-row">
|
||||||
|
<a class="cms-page-add-button ss-ui-button ss-ui-action-constructive cms-panel-link" data-icon="add" href="$AddLink"><% _t('CMSMain.AddNewButton', 'Add new') %></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cms-content-batchactions">
|
||||||
|
$BatchActionsForm
|
||||||
|
</div>
|
@ -11,11 +11,4 @@
|
|||||||
<label for="view-mode-multiselect"><% _t("MULTISELECT","Multi-selection") %></label>
|
<label for="view-mode-multiselect"><% _t("MULTISELECT","Multi-selection") %></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<% include CMSPagesController_ContentToolActions %>
|
||||||
<div class="cms-actions-row">
|
|
||||||
<a class="ss-ui-button ss-ui-action-constructive cms-panel-link" data-icon="add" href="$AddLink"><% _t('CMSMain.AddNewButton', 'Add new') %></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cms-content-batchactions">
|
|
||||||
$BatchActionsForm
|
|
||||||
</div>
|
|
||||||
|
@ -1,13 +1,28 @@
|
|||||||
<div class="cms-content center $BaseCSSClasses" data-layout-type="border">
|
<div class="cms-content center ss-tabset $BaseCSSClasses" data-layout-type="border">
|
||||||
|
|
||||||
<div class="cms-content-header north">
|
<div class="cms-content-header north">
|
||||||
<h2><% _t('REPORTS','Reports') %></h2>
|
<div>
|
||||||
|
<% control EditForm %>
|
||||||
|
<% if Backlink %>
|
||||||
|
<a class="backlink ss-ui-button cms-panel-link" data-icon="back" href="$Backlink">
|
||||||
|
<% _t('Back', 'Back') %>
|
||||||
|
</a>
|
||||||
|
<% end_if %>
|
||||||
|
|
||||||
|
<h2 id="page-title-heading">
|
||||||
|
<% control Controller %>
|
||||||
|
<% include CMSBreadcrumbs %>
|
||||||
|
<% end_control %>
|
||||||
|
</h2>
|
||||||
|
<% end_control %>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
$Tools
|
<div class="cms-content-fields center ui-widget-content" data-layout-type="border">
|
||||||
|
|
||||||
<div class="cms-content-fields center ui-widget-content">
|
|
||||||
$EditForm
|
$EditForm
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
@ -1,11 +0,0 @@
|
|||||||
<div class="cms-content-tools west" id="cms-content-tools-ReportAdmin">
|
|
||||||
|
|
||||||
<ul class="ui-widget-content">
|
|
||||||
<% control Reports %>
|
|
||||||
<li id="record-$ID">
|
|
||||||
<a href="admin/reports/show/$ID" title="$TreeDescription">$TreeTitle</a>
|
|
||||||
</li>
|
|
||||||
<% end_control %>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
85
tests/reports/ReportTest.php
Normal file
85
tests/reports/ReportTest.php
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class ReportTest extends SapphireTest {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
|
||||||
|
$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'));
|
||||||
|
|
||||||
|
$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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReportTest_FakeTest extends SS_Report implements TestOnly {
|
||||||
|
function title() {
|
||||||
|
return 'Report title';
|
||||||
|
}
|
||||||
|
function columns() {
|
||||||
|
return array(
|
||||||
|
"Title" => array(
|
||||||
|
"title" => "Page Title"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function sourceRecords($params, $sort, $limit) {
|
||||||
|
return new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort() {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ReportTest_FakeTest2 extends SS_Report implements TestOnly {
|
||||||
|
function title() {
|
||||||
|
return 'Report title 2';
|
||||||
|
}
|
||||||
|
function columns() {
|
||||||
|
return array(
|
||||||
|
"Title" => array(
|
||||||
|
"title" => "Page Title 2"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function sourceRecords($params, $sort, $limit) {
|
||||||
|
return new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort() {
|
||||||
|
return 98;
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class SSReportTest 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'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SSReportTest_FakeTest extends SS_Report implements TestOnly {
|
|
||||||
function title() {
|
|
||||||
return 'Report title';
|
|
||||||
}
|
|
||||||
function columns() {
|
|
||||||
return array(
|
|
||||||
"Title" => array(
|
|
||||||
"title" => "Page Title"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function sourceRecords($params, $sort, $limit) {
|
|
||||||
return new ArrayList();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user