Compare commits
276 Commits
4.0.0-alph
...
4
Author | SHA1 | Date |
---|---|---|
github-actions | 6942278b41 | |
Guy Sartorelli | c9c6c3ff1e | |
Guy Sartorelli | f5b5daa711 | |
github-actions | aa3d0a3b6a | |
Guy Sartorelli | aa085022a1 | |
Will Rossiter | a25d0432c4 | |
github-actions | 030c56777c | |
Guy Sartorelli | 03869a7535 | |
Steve Boyd | 2c3f2ca64d | |
Guy Sartorelli | 92b5d968da | |
Steve Boyd | f6aee12f07 | |
Guy Sartorelli | 2db20aba1a | |
Guy Sartorelli | cea17947ea | |
Maxime Rainville | 48b103bf97 | |
Steve Boyd | 454a3df1e7 | |
Guy Sartorelli | 4cb8e8f880 | |
Guy Sartorelli | f23076b4cf | |
Guy Sartorelli | 2bf6bc1a9c | |
Guy Sartorelli | e88a56243d | |
Steve Boyd | a75e054b99 | |
Steve Boyd | bd74939c14 | |
Robbie Averill | 01f2663179 | |
Robbie Averill | 213f7167a6 | |
Robbie Averill | c5f42d99a3 | |
Steve Boyd | d21503c88c | |
Steve Boyd | eacecdbb56 | |
Guy Sartorelli | c0bdbc3d3b | |
Steve Boyd | 567124b34a | |
Guy Sartorelli | bd7fb5a45d | |
Guy Sartorelli | f18dd784e5 | |
Guy Sartorelli | 86d338680a | |
Steve Boyd | fca925673f | |
Guy Sartorelli | 8e3d6cb3eb | |
Steve Boyd | 0bceb0903c | |
Guy Sartorelli | 6d565028c8 | |
Maxime Rainville | ede88ee491 | |
Steve Boyd | 013c5d74cf | |
GuySartorelli | 375c31904f | |
Steve Boyd | 0cb265434a | |
Maxime Rainville | 411a98e45b | |
Steve Boyd | cb71f6b7f2 | |
Maxime Rainville | 6dd0627678 | |
Steve Boyd | 1b2a9a8926 | |
Maxime Rainville | 3ab86f3d0a | |
Steve Boyd | 9f76ec2a43 | |
Steve Boyd | 908dc49dca | |
Steve Boyd | 22839ec8c2 | |
Steve Boyd | 8098a7c61f | |
Steve Boyd | 1d9940aab0 | |
Steve Boyd | 27288dc508 | |
Steve Boyd | e101f1e034 | |
Steve Boyd | 90bdc6f3ce | |
Steve Boyd | 82b5059265 | |
Serge Latyntcev | da8bc5c240 | |
Steve Boyd | ee4c391682 | |
Maxime Rainville | b62a6c66d1 | |
Andre Kiste | 466ec19b60 | |
Serge Latyntcev | 3314f95da6 | |
Guy Marriott | 8f40ddb5eb | |
Robbie Averill | 6ed13f7e07 | |
Robbie Averill | 9b9e673e4b | |
Steve Boyd | b0cb0b695e | |
Robbie Averill | 275a1bc7f4 | |
Maxime Rainville | f931dc37df | |
Robbie Averill | cb55795013 | |
Maxime Rainville | 0499717d7c | |
Garion Herman | f681448dbb | |
Robbie Averill | 2a77c2454f | |
Garion Herman | f2deee8fa0 | |
Steve Boyd | 5677d2d61d | |
Garion Herman | 7436e11d4f | |
Robbie Averill | 34474804a2 | |
Serge Latyntcev | 476f7b06f3 | |
Garion Herman | 7f34088211 | |
Serge Latyntcev | f3db5f72aa | |
Serge Latyntcev | d020ed86a1 | |
Serge Latyntsev | 9e95803970 | |
Garion Herman | 8be3660409 | |
Serge Latyntcev | 0bb704decf | |
Ingo Schommer | b5232aa7ab | |
Robbie Averill | 250813f79c | |
Robbie Averill | 1f1278b820 | |
Robbie Averill | 9b89812058 | |
Aaron Carlino | c3c38aa976 | |
Robbie Averill | ed3ffee31e | |
Stéphane Guevremont | 9d94712c04 | |
Aaron Carlino | c797d128a2 | |
Aaron Carlino | 423cc180cd | |
Maxime Rainville | bc70b87721 | |
Robbie Averill | 9270206c3b | |
Maxime Rainville | ebe98f487a | |
Dylan Wagstaff | a344110a10 | |
Aaron Carlino | 5a3bd39609 | |
Maxime Rainville | f074256a16 | |
Guy Marriott | 52a234410d | |
Guy Marriott | d6b1c071b6 | |
Guy Marriott | edecbabe61 | |
Aaron Carlino | dea66bc037 | |
Vagrant Default User | c48cb248dc | |
Aaron Carlino | 9ec437d033 | |
Aaron Carlino | 6e3f8ff982 | |
Robbie Averill | 7d4d7c05e6 | |
Robbie Averill | 9dd2cb35ac | |
Aaron Carlino | f1f0f521b5 | |
Aaron Carlino | 057dc90ebc | |
Maxime Rainville | 67254da185 | |
Robbie Averill | 786446fb67 | |
Maxime Rainville | ee1c77fa7d | |
Dylan Wagstaff | eb7be779f2 | |
Robbie Averill | 62b3f0c74d | |
Robbie Averill | f3230c78d4 | |
Aaron Carlino | 9e4be5b4f6 | |
Daniel Hensby | c316c6bb7e | |
Daniel Hensby | e9e5cdcc22 | |
Maxime Rainville | 3bbcfdde85 | |
Daniel Hensby | e9c73e9332 | |
root | 8c7acb3d24 | |
Daniel Hensby | 46de3d8f19 | |
Daniel Hensby | a3768f5f60 | |
Daniel Hensby | c90f1ed47c | |
Robbie Averill | e1296d4813 | |
Robbie Averill | 693889cb3e | |
Robbie Averill | dce7df600b | |
Maxime Rainville | 650e17b3fd | |
Damian Mooyman | 745fdf87cf | |
Damian Mooyman | fd62136c8f | |
Dylan Wagstaff | 326e19ac8e | |
Damian Mooyman | 9b239fd9a3 | |
Damian Mooyman | 75dfeb2b47 | |
Damian Mooyman | 2a36be9bed | |
Ingo Schommer | 86850eefb7 | |
Damian Mooyman | 7eacd8a3c3 | |
Damian Mooyman | cb14e856ff | |
Damian Mooyman | dee598eb0e | |
Damian Mooyman | ac23686777 | |
Damian Mooyman | 00cff693a6 | |
Daniel Hensby | 4c549d653a | |
Damian Mooyman | 7c0795eb68 | |
Daniel Hensby | 7e927aed74 | |
Daniel Hensby | b7b1b4d024 | |
Daniel Hensby | 2f59965515 | |
Daniel Hensby | 01fd709d74 | |
Daniel Hensby | 5ddb796d15 | |
Damian Mooyman | 8443529646 | |
Robbie Averill | 8a29918ac5 | |
Damian Mooyman | 4d3ad97a69 | |
Damian Mooyman | a9db6dee3a | |
Damian Mooyman | b006a9968a | |
Robbie Averill | b4a3529339 | |
Christopher Joe | 4d8053611d | |
Damian Mooyman | ed16d96842 | |
Christopher Joe | 86f845972f | |
Will Rossiter | 5b335ad511 | |
Damian Mooyman | 6ac1dea913 | |
Damian Mooyman | e575bff1af | |
Daniel Hensby | 14eeb10d31 | |
Daniel Hensby | b406d8724f | |
Damian Mooyman | cd94e99d89 | |
Daniel Hensby | ece79fd2b2 | |
Damian Mooyman | ec40ffb2cf | |
Robbie Averill | 26dc7373ba | |
Daniel Hensby | a548f0290e | |
Damian Mooyman | f7815b52e5 | |
Daniel Hensby | 0f387ad6a1 | |
Christopher Joe | 6fe1e2c5b2 | |
Damian Mooyman | 8020e36409 | |
Damian Mooyman | c5ca89a173 | |
Damian Mooyman | 7a2344117e | |
Chris Joe | 4a80bd9166 | |
Damian Mooyman | ca60b94f2e | |
Damian Mooyman | 418ac59e90 | |
Ingo Schommer | 9ce1eedf2f | |
Chris Joe | 04e4c7d1a4 | |
Damian Mooyman | 9afcf7780a | |
Daniel Hensby | 448955d82f | |
Saophalkun Ponlu | cda78e2d88 | |
Saophalkun Ponlu | 5351ba670f | |
Damian Mooyman | e9c7273bb4 | |
Daniel Hensby | d0f65850fa | |
Daniel Hensby | 6025de29cc | |
Daniel Hensby | e8fef7ebdd | |
Daniel Hensby | 28b79c88ff | |
Marco Hermo | 09bd6fc231 | |
Daniel Hensby | 879ce3086c | |
Daniel Hensby | 36d745ab24 | |
Daniel Hensby | 92ffc87e97 | |
Robbie Averill | 85c79d4e66 | |
Robbie Averill | 4aefa50087 | |
Robbie Averill | c3d2ba06c6 | |
Robbie Averill | f4af1fab77 | |
Christopher Joe | bf4e7224e0 | |
Damian Mooyman | fdbd6015d8 | |
Damian Mooyman | 62419d748d | |
Damian Mooyman | 614ebcfcd9 | |
Chris Joe | e532d01821 | |
Damian Mooyman | b1ec225246 | |
Daniel Hensby | 84fb64bf8f | |
Ingo Schommer | 9e7108420b | |
Sam Minnee | cf5115624d | |
Daniel Hensby | 76b59e7464 | |
Daniel Hensby | 108869841c | |
Saophalkun Ponlu | ab0b3d8a2f | |
Damian Mooyman | 1e386c83f6 | |
Ingo Schommer | a58416b6f6 | |
Ingo Schommer | 19fa5355ce | |
Robbie Averill | 83dae0fbac | |
Ingo Schommer | 179310e457 | |
Damian Mooyman | 7bab717c8d | |
Damian Mooyman | 8dbdc98cc2 | |
Simon Erkelens | 03125b8c6c | |
Daniel Hensby | 2aa6433357 | |
Daniel Hensby | 2e29bf27fe | |
Daniel Hensby | c249173e48 | |
Daniel Hensby | be44c5e7df | |
Daniel Hensby | 63bbc0bae4 | |
Daniel Hensby | d1764ffc08 | |
Daniel Hensby | a0fc3aa86f | |
Daniel Hensby | c2e804ad72 | |
Daniel Hensby | c927870432 | |
Daniel Hensby | 3f112ecfcd | |
Ingo Schommer | c37c69097d | |
Garion Herman | 19974fe1f2 | |
Aaron Carlino | 664fa75a02 | |
Ingo Schommer | 24afd61131 | |
Sam Minnee | 4332d2fa8e | |
Daniel Hensby | 7172eecd08 | |
Loz Calver | c1d2696514 | |
Sam Minnee | e5f51b14a3 | |
Damian Mooyman | 27b2037c68 | |
Sam Minnee | 59a9ff8459 | |
Damian Mooyman | 5dace88830 | |
Ingo Schommer | 02446a47a5 | |
Ingo Schommer | 376d2bfbc1 | |
Damian Mooyman | 4599b2b52c | |
Damian Mooyman | 240723b378 | |
Sam Minnee | c9e2c249c2 | |
Ingo Schommer | 015b400fb7 | |
Damian Mooyman | b4e047b39f | |
Daniel Hensby | 37a7e68f2d | |
Damian Mooyman | 3c8a56f904 | |
Damian Mooyman | 3cadebf595 | |
Paul Clarke | d67aee56fe | |
Paul Clarke | 417fb81ae4 | |
Daniel Hensby | cb06593a65 | |
Daniel Hensby | b10955d985 | |
Daniel Hensby | dcb8024158 | |
Daniel Hensby | 9c5974a13b | |
Daniel Hensby | da4aeda90e | |
Daniel Hensby | 65e0b6ef35 | |
Daniel Hensby | 8e5462794d | |
Damian Mooyman | a0eda1edd1 | |
Daniel Hensby | 804ff7c247 | |
Daniel Hensby | 537f4da88f | |
Damian Mooyman | 43462f1afa | |
Damian Mooyman | 8dd40b3c26 | |
Paul Clarke | 97eac2eb09 | |
Loz Calver | fa7e0825c5 | |
Sam Minnee | c813488412 | |
Daniel Hensby | 2c7846cb72 | |
Sam Minnee | fe0ca63c7a | |
Paul Clarke | 3d144b3afc | |
Damian Mooyman | 8f14b94433 | |
Damian Mooyman | 20f929ba8b | |
Damian Mooyman | 8395a55442 | |
Damian Mooyman | ac0d621d6f | |
Damian Mooyman | f92b83fc45 | |
Damian Mooyman | eb096e869f | |
Daniel Hensby | c1525c8ba6 | |
Daniel Hensby | efa20d2da0 | |
Daniel Hensby | cff2ea9a98 | |
Damian Mooyman | a446714e5e | |
Damian Mooyman | f17fad179f | |
Damian Mooyman | 6c1f17da91 | |
Daniel Hensby | c6fdf440a6 | |
Damian Mooyman | 87477a1e01 | |
Daniel Hensby | ca526b08c3 |
|
@ -14,5 +14,8 @@ trim_trailing_whitespace = true
|
|||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[composer.json]
|
||||
indent_size = 4
|
||||
|
||||
# The indent size used in the package.json file cannot be changed:
|
||||
# https://github.com/npm/npm/pull/3180#issuecomment-16336516
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/tests export-ignore
|
||||
/docs export-ignore
|
||||
/.tx export-ignore
|
||||
/.gitattributes export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.travis.yml export-ignore
|
||||
/.scrutinizer.yml export-ignore
|
||||
/*.dist export-ignore
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: CI
|
||||
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
|
|
@ -0,0 +1,16 @@
|
|||
name: Dispatch CI
|
||||
|
||||
on:
|
||||
# At 11:00 AM UTC, only on Monday and Tuesday
|
||||
schedule:
|
||||
- cron: '0 11 * * 1,2'
|
||||
|
||||
jobs:
|
||||
dispatch-ci:
|
||||
name: Dispatch CI
|
||||
# Only run cron on the silverstripe account
|
||||
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dispatch CI
|
||||
uses: silverstripe/gha-dispatch-ci@v1
|
|
@ -0,0 +1,17 @@
|
|||
name: Keepalive
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# The 4th of every month at 10:50am UTC
|
||||
schedule:
|
||||
- cron: '50 10 4 * *'
|
||||
|
||||
jobs:
|
||||
keepalive:
|
||||
name: Keepalive
|
||||
# Only run cron on the silverstripe account
|
||||
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Keepalive
|
||||
uses: silverstripe/gha-keepalive@v1
|
|
@ -1,9 +0,0 @@
|
|||
inherit: true
|
||||
|
||||
checks:
|
||||
php:
|
||||
code_rating: true
|
||||
duplication: true
|
||||
|
||||
filter:
|
||||
paths: [code/*, tests/*]
|
30
.travis.yml
30
.travis.yml
|
@ -1,30 +0,0 @@
|
|||
# See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details
|
||||
|
||||
sudo: false
|
||||
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
|
||||
env:
|
||||
- DB=MYSQL CORE_RELEASE=master
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.6
|
||||
env: DB=PGSQL CORE_RELEASE=master
|
||||
- php: 7.0
|
||||
env: DB=PGSQL CORE_RELEASE=master
|
||||
|
||||
before_script:
|
||||
- composer self-update || true
|
||||
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support
|
||||
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss
|
||||
- cd ~/builds/ss
|
||||
- composer install
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit reports/tests
|
|
@ -0,0 +1,9 @@
|
|||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[o:silverstripe:p:silverstripe-reports:r:master]
|
||||
file_filter = lang/<lang>.yml
|
||||
source_file = lang/en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
|
@ -6,3 +6,4 @@ mappings:
|
|||
ReportAdmin: SilverStripe\Reports\ReportAdmin
|
||||
SideReportView: SilverStripe\Reports\SideReportView
|
||||
SideReportWrapper: SilverStripe\Reports\SideReportWrapper
|
||||
SideReport: SilverStripe\Reports\SideReportView
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2016, SilverStripe Limited
|
||||
Copyright (c) 2017, SilverStripe Limited
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
23
README.md
23
README.md
|
@ -1,16 +1,17 @@
|
|||
# Reports
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/silverstripe/silverstripe-reports.png?branch=master)](http://travis-ci.org/silverstripe/silverstripe-reports)
|
||||
[![CI](https://github.com/silverstripe/silverstripe-reports/actions/workflows/ci.yml/badge.svg)](https://github.com/silverstripe/silverstripe-reports/actions/workflows/ci.yml)
|
||||
[![Silverstripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
|
||||
|
||||
## Introduction
|
||||
|
||||
This module contains the API's for building Reports that are displayed in the
|
||||
SilverStripe backend. This module replaces the built-in reports API from earlier
|
||||
versions of SilverStripe (2.4 and 3.0).
|
||||
Silverstripe backend. This module replaces the built-in reports API from earlier
|
||||
versions of Silverstripe (2.4 and 3.0).
|
||||
|
||||
## Requirements
|
||||
|
||||
* SilverStripe 3.2
|
||||
* Silverstripe 4.0
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
@ -18,3 +19,17 @@ The reports section will not show up in the CMS if:
|
|||
|
||||
* There are no reports to show
|
||||
* The logged in user does not have permission to view any reports
|
||||
|
||||
For large datasets, the reports section may take a long time to load, since each report is getting a count of the items it contains to display next to the title.
|
||||
|
||||
To mitigate this issue, there is a cap on the number of items that will be counted per report. This is set at 10,000 items by default, but can be configured using the `limit_count_in_overview` configuration variable. Setting this to `null` will result in showing the actual count regardless of how many items there are.
|
||||
|
||||
```yml
|
||||
SilverStripe\Reports\Report:
|
||||
limit_count_in_overview: 500
|
||||
```
|
||||
Note that some reports may have overridden the `getCount` method, and for those reports this may not apply.
|
||||
|
||||
## Links ##
|
||||
|
||||
* [License](./LICENSE)
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<?php
|
||||
|
||||
$path = explode(DIRECTORY_SEPARATOR, dirname(__FILE__));
|
||||
$dir = $path[count($path) - 1];
|
||||
|
||||
define('REPORTS_DIR', $dir);
|
291
code/Report.php
291
code/Report.php
|
@ -2,27 +2,36 @@
|
|||
|
||||
namespace SilverStripe\Reports;
|
||||
|
||||
use ReflectionClass;
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\FormAction;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldButtonRow;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||
use SilverStripe\Forms\GridField\GridFieldDataColumns;
|
||||
use SilverStripe\Forms\GridField\GridFieldExportButton;
|
||||
use SilverStripe\Forms\GridField\GridFieldPaginator;
|
||||
use SilverStripe\Forms\GridField\GridFieldPrintButton;
|
||||
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
|
||||
use SilverStripe\Forms\LiteralField;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\ORM\CMSPreviewable;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\DataQuery;
|
||||
use SilverStripe\ORM\Limitable;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\LiteralField;
|
||||
use SilverStripe\Forms\FormAction;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||
use SilverStripe\Forms\GridField\GridFieldButtonRow;
|
||||
use SilverStripe\Forms\GridField\GridFieldPrintButton;
|
||||
use SilverStripe\Forms\GridField\GridFieldExportButton;
|
||||
use SilverStripe\Forms\GridField\GridFieldToolbarHeader;
|
||||
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
|
||||
use SilverStripe\Forms\GridField\GridFieldDataColumns;
|
||||
use SilverStripe\Forms\GridField\GridFieldPaginator;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\View\ArrayData;
|
||||
use SilverStripe\View\ViewableData;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* Base "abstract" class creating reports on your data.
|
||||
|
@ -51,6 +60,9 @@ use ReflectionClass;
|
|||
*
|
||||
* 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 its version in SS2.
|
||||
*
|
||||
* @method SS_List|DataList sourceRecords($params = [], $sort = null, $limit = null)
|
||||
* List of records to show for this report
|
||||
*/
|
||||
class Report extends ViewableData
|
||||
{
|
||||
|
@ -75,7 +87,7 @@ class Report extends ViewableData
|
|||
* The class of object being managed by this report.
|
||||
* Set by overriding in your subclass.
|
||||
*/
|
||||
protected $dataClass = 'SilverStripe\\CMS\\Model\\SiteTree';
|
||||
protected $dataClass = SiteTree::class;
|
||||
|
||||
/**
|
||||
* A field that specifies the sort order of this report
|
||||
|
@ -85,13 +97,23 @@ class Report extends ViewableData
|
|||
|
||||
/**
|
||||
* Reports which should not be collected and returned in get_reports
|
||||
*
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
public static $excluded_reports = array(
|
||||
'SilverStripe\\Reports\\Report',
|
||||
'SilverStripe\\Reports\\ReportWrapper',
|
||||
'SilverStripe\\Reports\\SideReportWrapper',
|
||||
);
|
||||
private static $excluded_reports = [
|
||||
self::class,
|
||||
ReportWrapper::class,
|
||||
SideReportWrapper::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The maximum number of items to include in the count in the reports overview
|
||||
*
|
||||
* @config
|
||||
* @var int|null
|
||||
*/
|
||||
private static $limit_count_in_overview = 10000;
|
||||
|
||||
/**
|
||||
* Return the title of this report.
|
||||
|
@ -128,36 +150,50 @@ class Report extends ViewableData
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the {@link SQLQuery} that provides your report data.
|
||||
* Return the {@link DataQuery} that provides your report data.
|
||||
*
|
||||
* @param array $params
|
||||
* @return DataQuery
|
||||
*/
|
||||
public function sourceQuery($params)
|
||||
{
|
||||
if ($this->hasMethod('sourceRecords')) {
|
||||
return $this->sourceRecords($params, null, null)->dataQuery();
|
||||
} else {
|
||||
user_error("Please override sourceQuery()/sourceRecords() and columns() or, if necessary, override getReportField()", E_USER_ERROR);
|
||||
if (!$this->hasMethod('sourceRecords')) {
|
||||
throw new \RuntimeException(
|
||||
'Please override sourceQuery()/sourceRecords() and columns() or, '
|
||||
. 'if necessary, override getReportField()'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->sourceRecords($params, null, null)->dataQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a SS_List records for this report.
|
||||
*
|
||||
* @param array $params
|
||||
* @return SS_List
|
||||
*/
|
||||
public function records($params)
|
||||
{
|
||||
if ($this->hasMethod('sourceRecords')) {
|
||||
return $this->sourceRecords($params, null, null);
|
||||
} else {
|
||||
$query = $this->sourceQuery();
|
||||
$results = new ArrayList();
|
||||
$query = $this->sourceQuery($params);
|
||||
$results = ArrayList::create();
|
||||
foreach ($query->execute() as $data) {
|
||||
$class = $this->dataClass();
|
||||
$result = new $class($data);
|
||||
$result = Injector::inst()->create($class, $data);
|
||||
$results->push($result);
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
|
||||
public function columns()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the data class for this report
|
||||
*/
|
||||
|
@ -171,87 +207,107 @@ class Report extends ViewableData
|
|||
{
|
||||
return Controller::join_links(
|
||||
ReportAdmin::singleton()->Link('show'),
|
||||
$this->sanitiseClassName(get_class($this)),
|
||||
$this->sanitiseClassName(static::class),
|
||||
$action
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitise a model class' name for inclusion in a link
|
||||
*
|
||||
* @param string $class
|
||||
* @return string
|
||||
*/
|
||||
protected function sanitiseClassName($class) {
|
||||
return str_replace('\\', '-', $class);
|
||||
}
|
||||
/**
|
||||
* Sanitise a model class' name for inclusion in a link
|
||||
*
|
||||
* @param string $class
|
||||
* @return string
|
||||
*/
|
||||
protected function sanitiseClassName($class)
|
||||
{
|
||||
return str_replace('\\', '-', $class ?? '');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* counts the number of objects returned
|
||||
* @param array $params - any parameters for the sourceRecords
|
||||
* @param int|null $limit - the maximum number of records to count
|
||||
* @return int
|
||||
*/
|
||||
public function getCount($params = array())
|
||||
public function getCount($params = array(), $limit = null)
|
||||
{
|
||||
$sourceRecords = $this->sourceRecords($params, null, null);
|
||||
$sourceRecords = $this->sourceRecords($params, null, $limit);
|
||||
if (!$sourceRecords instanceof SS_List) {
|
||||
user_error($this->class."::sourceRecords does not return an SS_List", E_USER_NOTICE);
|
||||
user_error(static::class . "::sourceRecords does not return an SS_List", E_USER_NOTICE);
|
||||
return "-1";
|
||||
}
|
||||
// Some reports may not use the $limit parameter in sourceRecords since it isn't actually
|
||||
// used anywhere else - so make sure we limit record counts if possible.
|
||||
if ($sourceRecords instanceof Limitable) {
|
||||
$sourceRecords = $sourceRecords->limit($limit);
|
||||
}
|
||||
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
|
||||
* Counts the number of objects returned up to a configurable limit.
|
||||
*
|
||||
* Large datasets can cause performance issues for some reports if allowed to count all records.
|
||||
* To mitigate this, you can set the limit_count_in_overview config variable to the maximum number
|
||||
* of items you wish to count to. Counts will be limited to this value, and any counts that hit
|
||||
* this limit will be displayed with a plus, e.g. "500+"
|
||||
*
|
||||
* The default is to have no limit.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function add_excluded_reports($reportClass)
|
||||
public function getCountForOverview(): string
|
||||
{
|
||||
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;
|
||||
}
|
||||
$limit = $this->config()->get('limit_count_in_overview');
|
||||
$count = $this->getCount([], $limit);
|
||||
if ($limit && $count == $limit) {
|
||||
$count = "$count+";
|
||||
}
|
||||
return "$count";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (array) self::config()->get('excluded_reports');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SS_Report objects making up the given list.
|
||||
* @return Array of SS_Report objects
|
||||
*
|
||||
* @return Report[] Array of 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'
|
||||
$reportsArray = [];
|
||||
if ($reports && count($reports ?? []) > 0) {
|
||||
$excludedReports = static::get_excluded_reports();
|
||||
// Collect reports into array with an attribute for 'sort'
|
||||
foreach ($reports as $report) {
|
||||
if (in_array($report, self::$excluded_reports)) {
|
||||
// Don't use the Report superclass, or any excluded report classes
|
||||
if (in_array($report, $excludedReports ?? [])) {
|
||||
continue;
|
||||
} //don't use the SS_Report superclass
|
||||
}
|
||||
$reflectionClass = new ReflectionClass($report);
|
||||
// Don't use abstract classes
|
||||
if ($reflectionClass->isAbstract()) {
|
||||
continue;
|
||||
} //don't use abstract classes
|
||||
}
|
||||
|
||||
$reportObj = new $report;
|
||||
if (method_exists($reportObj, 'sort')) {
|
||||
/** @var Report $reportObj */
|
||||
$reportObj = $report::create();
|
||||
if ($reportObj->hasMethod('sort')) {
|
||||
// Use the sort method to specify the sort field
|
||||
$reportObj->sort = $reportObj->sort();
|
||||
} //use the sort method to specify the sort field
|
||||
}
|
||||
$reportsArray[$report] = $reportObj;
|
||||
}
|
||||
}
|
||||
|
@ -290,6 +346,7 @@ class Report extends ViewableData
|
|||
|
||||
// Add search fields is available
|
||||
if ($this->hasMethod('parameterFields') && $parameterFields = $this->parameterFields()) {
|
||||
/** @var FormField $field */
|
||||
foreach ($parameterFields as $field) {
|
||||
// Namespace fields for easier handling in form submissions
|
||||
$field->setName(sprintf('filters[%s]', $field->getName()));
|
||||
|
@ -298,7 +355,13 @@ class Report extends ViewableData
|
|||
}
|
||||
|
||||
// Add a search button
|
||||
$fields->push(new FormAction('updatereport', _t('GridField.Filter')));
|
||||
$formAction = FormAction::create(
|
||||
'updatereport',
|
||||
_t('SilverStripe\\Forms\\GridField\\GridField.Filter', 'Filter')
|
||||
);
|
||||
$formAction->addExtraClass('btn-primary mb-4');
|
||||
|
||||
$fields->push($formAction);
|
||||
}
|
||||
|
||||
$fields->push($this->getReportField());
|
||||
|
@ -323,34 +386,33 @@ class Report extends ViewableData
|
|||
* 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
|
||||
* @return \SilverStripe\Forms\FormField subclass
|
||||
*/
|
||||
public function getReportField()
|
||||
{
|
||||
// TODO Remove coupling with global state
|
||||
$params = isset($_REQUEST['filters']) ? $_REQUEST['filters'] : array();
|
||||
$params = $this->getSourceParams();
|
||||
$items = $this->sourceRecords($params, null, null);
|
||||
|
||||
$gridFieldConfig = GridFieldConfig::create()->addComponents(
|
||||
|
||||
new GridFieldButtonRow('before'),
|
||||
new GridFieldPrintButton('buttons-before-left'),
|
||||
new GridFieldExportButton('buttons-before-left'),
|
||||
new GridFieldToolbarHeader(),
|
||||
new GridFieldSortableHeader(),
|
||||
new GridFieldDataColumns(),
|
||||
new GridFieldPaginator()
|
||||
GridFieldButtonRow::create('before'),
|
||||
GridFieldPrintButton::create('buttons-before-left'),
|
||||
GridFieldExportButton::create('buttons-before-left'),
|
||||
GridFieldSortableHeader::create(),
|
||||
GridFieldDataColumns::create(),
|
||||
GridFieldPaginator::create()
|
||||
);
|
||||
$gridField = new GridField('Report', null, $items, $gridFieldConfig);
|
||||
$columns = $gridField->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
|
||||
$displayFields = array();
|
||||
$fieldCasting = array();
|
||||
$fieldFormatting = array();
|
||||
/** @var GridField $gridField */
|
||||
$gridField = GridField::create('Report', null, $items, $gridFieldConfig);
|
||||
/** @var GridFieldDataColumns $columns */
|
||||
$columns = $gridField->getConfig()->getComponentByType(GridFieldDataColumns::class);
|
||||
$displayFields = [];
|
||||
$fieldCasting = [];
|
||||
$fieldFormatting = [];
|
||||
|
||||
// Parse the column information
|
||||
foreach ($this->columns() as $source => $info) {
|
||||
if (is_string($info)) {
|
||||
$info = array('title' => $info);
|
||||
$info = ['title' => $info];
|
||||
}
|
||||
|
||||
if (isset($info['formatting'])) {
|
||||
|
@ -364,14 +426,22 @@ class Report extends ViewableData
|
|||
}
|
||||
|
||||
if (isset($info['link']) && $info['link']) {
|
||||
$fieldFormatting[$source] = function($value, $item) {
|
||||
/** @var CMSPreviewable $item */
|
||||
return sprintf(
|
||||
'<a class="grid-field__link-block" href="%s">%s</a>',
|
||||
Convert::raw2att($item->CMSEditLink()),
|
||||
Convert::raw2xml($value)
|
||||
);
|
||||
};
|
||||
if (is_callable($info['link'])) {
|
||||
$fieldFormatting[$source] = $info['link'];
|
||||
} else {
|
||||
$fieldFormatting[$source] = function ($value, $item) {
|
||||
if ($item instanceof CMSPreviewable) {
|
||||
/** @var CMSPreviewable $item */
|
||||
return sprintf(
|
||||
'<a class="grid-field__link-block" href="%s" title="%s">%s</a>',
|
||||
Convert::raw2att($item->CMSEditLink()),
|
||||
Convert::raw2att($value),
|
||||
Convert::raw2xml($value)
|
||||
);
|
||||
}
|
||||
return $value;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
$displayFields[$source] = isset($info['title']) ? $info['title'] : $source;
|
||||
|
@ -390,7 +460,7 @@ class Report extends ViewableData
|
|||
public function canView($member = null)
|
||||
{
|
||||
if (!$member && $member !== false) {
|
||||
$member = Member::currentUser();
|
||||
$member = Security::getCurrentUser();
|
||||
}
|
||||
|
||||
$extended = $this->extendedCan('canView', $member);
|
||||
|
@ -419,7 +489,9 @@ class Report extends ViewableData
|
|||
$results = $this->extend($methodName, $member);
|
||||
if ($results && is_array($results)) {
|
||||
// Remove NULLs
|
||||
$results = array_filter($results, function ($v) {return !is_null($v);});
|
||||
$results = array_filter($results ?? [], function ($v) {
|
||||
return !is_null($v);
|
||||
});
|
||||
// If there are any non-NULL responses, then return the lowest one of them.
|
||||
// If any explicitly deny the permission, then we don't get access
|
||||
if ($results) {
|
||||
|
@ -431,10 +503,8 @@ class Report extends ViewableData
|
|||
|
||||
|
||||
/**
|
||||
* 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 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
|
||||
*/
|
||||
|
@ -442,4 +512,33 @@ class Report extends ViewableData
|
|||
{
|
||||
return $this->title();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return additional breadcrumbs for this report. Useful when this report is a child of another.
|
||||
*
|
||||
* @return ArrayData[]
|
||||
*/
|
||||
public function getBreadcrumbs()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get source params for the report to filter by
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getSourceParams()
|
||||
{
|
||||
$params = [];
|
||||
if (Injector::inst()->has(HTTPRequest::class)) {
|
||||
/** @var HTTPRequest $request */
|
||||
$request = Injector::inst()->get(HTTPRequest::class);
|
||||
$params = $request->param('filters') ?: $request->requestVar('filters') ?: [];
|
||||
}
|
||||
|
||||
$this->extend('updateSourceParams', $params);
|
||||
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,18 +6,17 @@ use SilverStripe\Admin\LeftAndMain;
|
|||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||
use SilverStripe\Forms\GridField\GridFieldToolbarHeader;
|
||||
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
|
||||
use SilverStripe\Forms\GridField\GridFieldDataColumns;
|
||||
use SilverStripe\Forms\GridField\GridFieldFooter;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
|
||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorConfig;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\PermissionProvider;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\View\ArrayData;
|
||||
use SilverStripe\View\Requirements;
|
||||
|
||||
|
@ -25,7 +24,7 @@ use SilverStripe\View\Requirements;
|
|||
* Reports section of the CMS.
|
||||
*
|
||||
* All reports that should show in the ReportAdmin section
|
||||
* of the CMS need to subclass {@link SS_Report}, and implement
|
||||
* of the CMS need to subclass {@link SilverStripe\Reports\Report}, and implement
|
||||
* the appropriate methods and variables that are required.
|
||||
*/
|
||||
class ReportAdmin extends LeftAndMain implements PermissionProvider
|
||||
|
@ -34,9 +33,11 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider
|
|||
|
||||
private static $menu_title = 'Reports';
|
||||
|
||||
private static $menu_icon_class = 'font-icon-chart-line';
|
||||
|
||||
private static $template_path = null; // defaults to (project)/templates/email
|
||||
|
||||
private static $tree_class = 'SilverStripe\\Reports\\Report';
|
||||
private static $tree_class = Report::class;
|
||||
|
||||
private static $url_handlers = array(
|
||||
'show/$ReportClass/$Action' => 'handleAction'
|
||||
|
@ -63,15 +64,14 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider
|
|||
|
||||
// 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());
|
||||
|
||||
Requirements::javascript(REPORTS_DIR . '/javascript/ReportAdmin.js');
|
||||
Requirements::javascript('silverstripe/reports: javascript/ReportAdmin.js');
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the parent permission checks, but also
|
||||
* makes sure that instantiatable subclasses of
|
||||
* {@link Report} exist. By default, the CMS doesn't
|
||||
* {@link SilverStripe\Reports\Report} exist. By default, the CMS doesn't
|
||||
* include any Reports, so there's no point in showing
|
||||
*
|
||||
* @param Member $member
|
||||
|
@ -80,7 +80,7 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider
|
|||
public function canView($member = null)
|
||||
{
|
||||
if (!$member && $member !== false) {
|
||||
$member = Member::currentUser();
|
||||
$member = Security::getCurrentUser();
|
||||
}
|
||||
|
||||
if (!parent::canView($member)) {
|
||||
|
@ -131,15 +131,16 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider
|
|||
return parent::handleAction($request, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsanitise a model class' name from a URL param
|
||||
*
|
||||
* @param string $class
|
||||
* @return string
|
||||
*/
|
||||
protected function unsanitiseClassName($class) {
|
||||
return str_replace('-', '\\', $class);
|
||||
}
|
||||
/**
|
||||
* Unsanitise a model class' name from a URL param
|
||||
*
|
||||
* @param string $class
|
||||
* @return string
|
||||
*/
|
||||
protected function unsanitiseClassName($class)
|
||||
{
|
||||
return str_replace('-', '\\', $class ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we have reports and need
|
||||
|
@ -154,7 +155,7 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider
|
|||
*/
|
||||
public static function has_reports()
|
||||
{
|
||||
return sizeof(Report::get_reports()) > 0;
|
||||
return sizeof(Report::get_reports() ?? []) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,12 +172,22 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider
|
|||
// Uses session state for current record otherwise.
|
||||
$items[0]->Link = singleton('SilverStripe\\Reports\\ReportAdmin')->Link();
|
||||
|
||||
if ($this->reportObject) {
|
||||
if ($report = $this->reportObject) {
|
||||
$breadcrumbs = $report->getBreadcrumbs();
|
||||
if (!empty($breadcrumbs)) {
|
||||
foreach ($breadcrumbs as $crumb) {
|
||||
$items->push($crumb);
|
||||
}
|
||||
}
|
||||
|
||||
//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'))))
|
||||
)));
|
||||
$items->push(ArrayData::create([
|
||||
'Title' => $report->title(),
|
||||
'Link' => Controller::join_links(
|
||||
$this->Link(),
|
||||
'?' . http_build_query(['q' => $this->request->requestVar('q')])
|
||||
)
|
||||
]));
|
||||
}
|
||||
|
||||
return $items;
|
||||
|
@ -202,10 +213,10 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider
|
|||
{
|
||||
return array(
|
||||
"CMS_ACCESS_ReportAdmin" => array(
|
||||
'name' => _t('CMSMain.ACCESS', "Access to '{title}' section", array(
|
||||
'name' => _t('SilverStripe\\CMS\\Controllers\\CMSMain.ACCESS', "Access to '{title}' section", array(
|
||||
'title' => static::menu_title()
|
||||
)),
|
||||
'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')
|
||||
'category' => _t('SilverStripe\\Security\\Permission.CMS_ACCESS_CATEGORY', 'CMS Access')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -219,20 +230,20 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider
|
|||
// List all reports
|
||||
$fields = new FieldList();
|
||||
$gridFieldConfig = GridFieldConfig::create()->addComponents(
|
||||
new GridFieldToolbarHeader(),
|
||||
new GridFieldSortableHeader(),
|
||||
new GridFieldDataColumns(),
|
||||
new GridFieldFooter()
|
||||
GridFieldSortableHeader::create(),
|
||||
GridFieldDataColumns::create(),
|
||||
GridFieldFooter::create()
|
||||
);
|
||||
$gridField = new GridField('Reports', false, $this->Reports(), $gridFieldConfig);
|
||||
$gridField = GridField::create('Reports', false, $this->Reports(), $gridFieldConfig);
|
||||
/** @var GridFieldDataColumns $columns */
|
||||
$columns = $gridField->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
|
||||
$columns = $gridField->getConfig()
|
||||
->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
|
||||
$columns->setDisplayFields(array(
|
||||
'title' => _t('ReportAdmin.ReportTitle', 'Title'),
|
||||
'title' => _t('SilverStripe\\Reports\\ReportAdmin.ReportTitle', 'Title'),
|
||||
));
|
||||
|
||||
$columns->setFieldFormatting(array(
|
||||
'title' => '<a href=\"$Link\" class=\"grid-field__link-block\">$value ($Count)</a>'
|
||||
'title' => '<a href=\"$Link\" class=\"grid-field__link-block\">$value ($CountForOverview)</a>'
|
||||
));
|
||||
$gridField->addExtraClass('all-reports-gridfield');
|
||||
$fields->push($gridField);
|
||||
|
@ -240,7 +251,9 @@ class ReportAdmin extends LeftAndMain implements PermissionProvider
|
|||
|
||||
$actions = new FieldList();
|
||||
$form = new Form($this, "EditForm", $fields, $actions);
|
||||
$form->addExtraClass('panel panel--padded panel--scrollable cms-edit-form cms-panel-padded' . $this->BaseCSSClasses());
|
||||
$form->addExtraClass(
|
||||
'panel panel--padded panel--scrollable cms-edit-form cms-panel-padded' . $this->BaseCSSClasses()
|
||||
);
|
||||
$form->loadDataFrom($this->request->getVars());
|
||||
|
||||
$this->extend('updateEditForm', $form);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace SilverStripe\Reports;
|
||||
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
|
||||
/**
|
||||
* SS_ReportWrapper is a base class for creating report wappers.
|
||||
*
|
||||
|
@ -21,14 +23,14 @@ abstract class ReportWrapper extends Report
|
|||
|
||||
public function __construct($baseReport)
|
||||
{
|
||||
$this->baseReport = is_string($baseReport) ? new $baseReport : $baseReport;
|
||||
$this->baseReport = is_string($baseReport) ? Injector::inst()->create($baseReport) : $baseReport;
|
||||
$this->dataClass = $this->baseReport->dataClass();
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function ID()
|
||||
{
|
||||
return get_class($this->baseReport) . '_' . get_class($this);
|
||||
return get_class($this->baseReport) . '_' . static::class;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -75,7 +77,9 @@ abstract class ReportWrapper extends Report
|
|||
$this->afterQuery();
|
||||
return $query;
|
||||
} else {
|
||||
user_error("Please override sourceQuery()/sourceRecords() and columns() in your base report", E_USER_ERROR);
|
||||
throw new \RuntimeException(
|
||||
"Please override sourceQuery()/sourceRecords() and columns() in your base report"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace SilverStripe\Reports;
|
||||
|
||||
use TableListField;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
|
@ -11,8 +11,8 @@ use SilverStripe\View\ViewableData;
|
|||
*/
|
||||
class SideReportView extends ViewableData
|
||||
{
|
||||
|
||||
protected $controller, $report;
|
||||
protected $controller;
|
||||
protected $report;
|
||||
protected $parameters;
|
||||
|
||||
public function __construct($controller, $report)
|
||||
|
@ -24,7 +24,7 @@ class SideReportView extends ViewableData
|
|||
|
||||
public function group()
|
||||
{
|
||||
return _t('SideReport.OtherGroupTitle', "Other");
|
||||
return _t('SilverStripe\\Reports\\SideReport.OtherGroupTitle', "Other");
|
||||
}
|
||||
|
||||
public function sort()
|
||||
|
@ -43,7 +43,7 @@ class SideReportView extends ViewableData
|
|||
$columns = $this->report->columns();
|
||||
|
||||
if ($records && $records->Count()) {
|
||||
$result = "<ul class=\"$this->class\">\n";
|
||||
$result = "<ul class=\"" . static::class . "\">\n";
|
||||
|
||||
foreach ($records as $record) {
|
||||
$result .= "<li>\n";
|
||||
|
@ -59,7 +59,7 @@ class SideReportView extends ViewableData
|
|||
} else {
|
||||
$result = "<p class=\"message notice\">" .
|
||||
_t(
|
||||
'SideReport.REPEMPTY',
|
||||
'SilverStripe\\Reports\\SideReport.REPEMPTY',
|
||||
'The {title} report is empty.',
|
||||
array('title' => $this->report->title())
|
||||
)
|
||||
|
@ -70,24 +70,18 @@ class SideReportView extends ViewableData
|
|||
|
||||
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...
|
||||
// Cast value
|
||||
if (!empty($info['casting'])) {
|
||||
$val = TableListField::getCastedValue($val, $info['casting']);
|
||||
$val = DBField::create_field($info['casting'], $record->source)->forTemplate();
|
||||
} else {
|
||||
$val = Convert::raw2xml($record->$source);
|
||||
}
|
||||
|
||||
// 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);
|
||||
$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 . '";');
|
||||
}
|
||||
|
||||
|
@ -96,7 +90,7 @@ class SideReportView extends ViewableData
|
|||
|
||||
$classClause = "";
|
||||
if (isset($info['title'])) {
|
||||
$cssClass = preg_replace('/[^A-Za-z0-9]+/', '', $info['title']);
|
||||
$cssClass = preg_replace('/[^A-Za-z0-9]+/', '', $info['title'] ?? '');
|
||||
$classClause = "class=\"$cssClass\"";
|
||||
}
|
||||
|
|
@ -1,34 +1,48 @@
|
|||
{
|
||||
"name": "silverstripe/reports",
|
||||
"type": "silverstripe-module",
|
||||
"description": "Reports module for SilverStripe CMS",
|
||||
"homepage": "http://silverstripe.org",
|
||||
"license": "BSD-3-Clause",
|
||||
"keywords": ["silverstripe", "cms", "reports"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "SilverStripe",
|
||||
"homepage": "http://silverstripe.com"
|
||||
"name": "silverstripe/reports",
|
||||
"type": "silverstripe-vendormodule",
|
||||
"description": "Reports module for SilverStripe CMS",
|
||||
"homepage": "http://silverstripe.org",
|
||||
"license": "BSD-3-Clause",
|
||||
"keywords": [
|
||||
"silverstripe",
|
||||
"cms",
|
||||
"reports"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "SilverStripe",
|
||||
"homepage": "http://silverstripe.com"
|
||||
},
|
||||
{
|
||||
"name": "The SilverStripe Community",
|
||||
"homepage": "http://silverstripe.org"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"silverstripe/framework": "^4.11",
|
||||
"silverstripe/admin": "^1.6@dev",
|
||||
"silverstripe/versioned": "^1.6@dev",
|
||||
"silverstripe/config": "^1.0@dev",
|
||||
"silverstripe/assets": "^1.6@dev",
|
||||
"silverstripe/vendor-plugin": "^1"
|
||||
},
|
||||
{
|
||||
"name": "The SilverStripe Community",
|
||||
"homepage": "http://silverstripe.org"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"silverstripe/framework": "^4.0"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SilverStripe\\Reports\\": "code/"
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/PHPUnit": "~4.8"
|
||||
}
|
||||
}
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"squizlabs/php_codesniffer": "^3.0"
|
||||
},
|
||||
"extra": {
|
||||
"expose": [
|
||||
"javascript"
|
||||
]
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SilverStripe\\Reports\\": "code/",
|
||||
"SilverStripe\\Reports\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
|
@ -2,17 +2,32 @@
|
|||
* File: ReportAdmin.js
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
$.entwine('ss', function($){
|
||||
$('.ReportAdmin .cms-edit-form').entwine({
|
||||
onsubmit: function(e) {
|
||||
var url = $.path.parseUrl(document.location.href).hrefNoSearch,
|
||||
params = this.find(':input[name^=filters]').serializeArray();
|
||||
params = $.grep(params, function(param) {return (param.value);}); // filter out empty
|
||||
if(params) url = $.path.addSearchParams(url, $.param(params));
|
||||
$('.cms-container').loadPanel(url);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
(function ($) {
|
||||
$.entwine("ss", function ($) {
|
||||
$(".ReportAdmin .cms-edit-form").entwine({
|
||||
onsubmit: function (e) {
|
||||
let url = $.path.parseUrl(document.location.href).hrefNoSearch;
|
||||
let params = this.find(":input[name^=filters]").serializeArray();
|
||||
|
||||
try {
|
||||
params = $.grep(params, function (param) {
|
||||
// filter out empty
|
||||
return param.value;
|
||||
});
|
||||
|
||||
// convert params to a query string
|
||||
params = $.param(params);
|
||||
|
||||
// append query string to url
|
||||
url += "?" + params;
|
||||
|
||||
$(".cms-container").loadPanel(url);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
bg:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Отчети
|
||||
ReportTitle: Заглавие
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Други
|
||||
REPEMPTY: 'Отчетът за {title} е празен.'
|
|
@ -0,0 +1,7 @@
|
|||
cs:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Výkazy
|
||||
ReportTitle: Titulek
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Jiné
|
||||
REPEMPTY: 'Výkaz {title} je prázdný.'
|
|
@ -0,0 +1,7 @@
|
|||
da:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Rapporter
|
||||
ReportTitle: Titel
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Andre
|
||||
REPEMPTY: 'Rapporten {title} er tom.'
|
|
@ -0,0 +1,7 @@
|
|||
de:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Berichte
|
||||
ReportTitle: Titel
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Andere
|
||||
REPEMPTY: 'Der Bericht {title} ist leer.'
|
|
@ -0,0 +1,11 @@
|
|||
en:
|
||||
SilverStripe\CMS\Controllers\CMSPageHistoryController:
|
||||
PREVIEW: 'Website preview'
|
||||
SilverStripe\Forms\GridField\GridField:
|
||||
Filter: Filter
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Reports
|
||||
ReportTitle: Title
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Other
|
||||
REPEMPTY: 'The {title} report is empty.'
|
|
@ -0,0 +1,11 @@
|
|||
eo:
|
||||
SilverStripe\CMS\Controllers\CMSPageHistoryController:
|
||||
PREVIEW: 'Retejon antaŭvidi'
|
||||
SilverStripe\Forms\GridField\GridField:
|
||||
Filter: Filtrilo
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Raportoj
|
||||
ReportTitle: Titoloj
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Aliaj
|
||||
REPEMPTY: 'La raporto {title} estas malplena.'
|
|
@ -0,0 +1,7 @@
|
|||
fi:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Raportit
|
||||
ReportTitle: Otsikko
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Muu
|
||||
REPEMPTY: '{title} raportti on tyhjä.'
|
|
@ -0,0 +1,7 @@
|
|||
fr:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Rapports
|
||||
ReportTitle: Titre
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Autre
|
||||
REPEMPTY: 'Le rapport {title} est vide.'
|
|
@ -0,0 +1,6 @@
|
|||
hr:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Izvještaji
|
||||
ReportTitle: Naslov
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Drugi
|
|
@ -0,0 +1,7 @@
|
|||
it:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Rapporti
|
||||
ReportTitle: Titolo
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Altro
|
||||
REPEMPTY: 'Il rapporto {title} è vuoto.'
|
|
@ -0,0 +1,7 @@
|
|||
nl:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Rapporten
|
||||
ReportTitle: Naam
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Overig
|
||||
REPEMPTY: 'Het {title} rapport is leeg.'
|
|
@ -0,0 +1,7 @@
|
|||
pl:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Raporty
|
||||
ReportTitle: Tytuł
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Inne
|
||||
REPEMPTY: 'Raport {title} jest pusty'
|
|
@ -0,0 +1,7 @@
|
|||
ru:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Отчёты
|
||||
ReportTitle: Заголовок
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Другое
|
||||
REPEMPTY: 'Отчёт {title} пустой.'
|
|
@ -0,0 +1,9 @@
|
|||
sk:
|
||||
SilverStripe\CMS\Controllers\CMSPageHistoryController:
|
||||
PREVIEW: 'Náhľad webovej stránky'
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Správy
|
||||
ReportTitle: Názov
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Iné
|
||||
REPEMPTY: 'Správa {title} je prázdna.'
|
|
@ -0,0 +1,7 @@
|
|||
sl:
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Poročila
|
||||
ReportTitle: Naslov
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Drugo
|
||||
REPEMPTY: 'Poročilo ''{title}'' je prazno.'
|
|
@ -0,0 +1,9 @@
|
|||
sv:
|
||||
SilverStripe\CMS\Controllers\CMSPageHistoryController:
|
||||
PREVIEW: 'Webbplats förhandsvisning'
|
||||
SilverStripe\Reports\ReportAdmin:
|
||||
MENUTITLE: Rapporter
|
||||
ReportTitle: Titel
|
||||
SilverStripe\Reports\SideReport:
|
||||
OtherGroupTitle: Annat
|
||||
REPEMPTY: 'Rapporten {title} är tom.'
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ruleset name="SilverStripe">
|
||||
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
|
||||
|
||||
<file>code</file>
|
||||
<file>tests</file>
|
||||
|
||||
<!-- base rules are PSR-12 -->
|
||||
<rule ref="PSR12" >
|
||||
<!-- Current exclusions -->
|
||||
<exclude name="PSR1.Methods.CamelCapsMethodName.NotCamelCaps" />
|
||||
</rule>
|
||||
</ruleset>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true">
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Default">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist addUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">.</directory>
|
||||
<exclude>
|
||||
<directory suffix=".php">tests/</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
</phpunit>
|
|
@ -1,8 +1,8 @@
|
|||
<div id="reportadmin-cms-content" class="cms-content center cms-tabset $BaseCSSClasses" data-layout-type="border" data-pjax-fragment="Content">
|
||||
<div id="reportadmin-cms-content" class="flexbox-area-grow fill-height cms-content cms-tabset $BaseCSSClasses" data-layout-type="border" data-pjax-fragment="Content">
|
||||
|
||||
<div class="cms-content-header north">
|
||||
<div class="cms-content-header vertical-align-items">
|
||||
<% with $EditForm %>
|
||||
<div class="cms-content-header-info">
|
||||
<div class="cms-content-header-info flexbox-area-grow vertical-align-items">
|
||||
<% include SilverStripe\\Admin\\BackLink_Button %>
|
||||
<% with $Controller %>
|
||||
<% include SilverStripe\\Admin\\CMSBreadcrumbs %>
|
||||
|
@ -11,7 +11,7 @@
|
|||
<% end_with %>
|
||||
</div>
|
||||
|
||||
<div class="cms-content-fields center ui-widget-content" data-layout-type="border">
|
||||
<div class="flexbox-area-grow cms-content-fields ui-widget-content" data-layout-type="border">
|
||||
|
||||
$EditForm
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<div class="cms-preview fill-height flexbox-area-grow" data-layout-type="border">
|
||||
<div class="panel flexbox-area-grow fill-height">
|
||||
<div class="preview-note"><span><!-- --></span><%t SilverStripe\CMS\Controllers\CMSPageHistoryController.PREVIEW 'Website preview' %></div>
|
||||
<div class="preview__device">
|
||||
<div class="preview-device-outer">
|
||||
<div class="preview-device-inner">
|
||||
<iframe src="about:blank" class="center" name="cms-preview-iframe"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toolbar toolbar--south cms-content-controls cms-preview-controls"></div>
|
||||
<div class="cms-preview-overlay ui-widget-overlay-light"></div>
|
||||
</div>
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Reports\Tests;
|
||||
|
||||
use ReflectionClass;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Reports\Report;
|
||||
use SilverStripe\Reports\ReportAdmin;
|
||||
use SilverStripe\Reports\Tests\ReportAdminTest\FakeReport;
|
||||
use SilverStripe\Reports\Tests\ReportAdminTest\FakeReport2;
|
||||
|
||||
class ReportAdminTest extends SapphireTest
|
||||
{
|
||||
public function testBreadcrumbsAreGenerated()
|
||||
{
|
||||
$noExtraCrumbs = FakeReport::create();
|
||||
|
||||
$controller = $this->mockController($noExtraCrumbs);
|
||||
$breadcrumbs = $controller->BreadCrumbs();
|
||||
|
||||
$this->assertCount(2, $breadcrumbs);
|
||||
$map = $breadcrumbs[0]->toMap();
|
||||
$this->assertSame('Reports', $map['Title']);
|
||||
$this->assertSame('admin/reports/', $map['Link']);
|
||||
|
||||
$map = $breadcrumbs[1]->toMap();
|
||||
$this->assertSame('Fake report', $map['Title']);
|
||||
|
||||
$extraCrumbs = FakeReport2::create();
|
||||
$controller = $this->mockController($extraCrumbs);
|
||||
$breadcrumbs = $controller->Breadcrumbs();
|
||||
|
||||
$this->assertCount(3, $breadcrumbs);
|
||||
|
||||
$map = $breadcrumbs[0]->toMap();
|
||||
$this->assertSame('Reports', $map['Title']);
|
||||
$this->assertSame('admin/reports/', $map['Link']);
|
||||
|
||||
$map = $breadcrumbs[1]->toMap();
|
||||
$this->assertSame('Fake report title', $map['Title']);
|
||||
$this->assertSame('admin/reports/show/SilverStripe-Reports-Tests-ReportAdminTest-FakeReport', $map['Link']);
|
||||
|
||||
$map = $breadcrumbs[2]->toMap();
|
||||
$this->assertSame('Fake report two', $map['Title']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Report $report
|
||||
* @return ReportAdmin
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected function mockController(Report $report)
|
||||
{
|
||||
$reflector = new ReflectionClass($controller = ReportAdmin::create());
|
||||
|
||||
$reportClass = $reflector->getProperty('reportClass');
|
||||
$reportClass->setAccessible(true);
|
||||
$reportClass->setValue($controller, get_class($report));
|
||||
|
||||
$reportObject = $reflector->getProperty('reportObject');
|
||||
$reportObject->setAccessible(true);
|
||||
$reportObject->setValue($controller, $report);
|
||||
|
||||
$controller->setRequest(Controller::curr()->getRequest());
|
||||
|
||||
return $controller;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Reports\Tests\ReportAdminTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Reports\Report;
|
||||
|
||||
class FakeReport extends Report implements TestOnly
|
||||
{
|
||||
public function title()
|
||||
{
|
||||
return 'Fake report';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Reports\Tests\ReportAdminTest;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Reports\Report;
|
||||
use SilverStripe\Reports\ReportAdmin;
|
||||
use SilverStripe\View\ArrayData;
|
||||
|
||||
class FakeReport2 extends Report implements TestOnly
|
||||
{
|
||||
public function title()
|
||||
{
|
||||
return 'Fake report two';
|
||||
}
|
||||
|
||||
public function getBreadcrumbs()
|
||||
{
|
||||
return [ArrayData::create([
|
||||
'Title' => 'Fake report title',
|
||||
'Link' => FakeReport::singleton()->getLink()
|
||||
])];
|
||||
}
|
||||
}
|
|
@ -1,19 +1,20 @@
|
|||
<?php
|
||||
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\Reports\Report;
|
||||
use SilverStripe\Control\Session;
|
||||
namespace SilverStripe\Reports\Tests;
|
||||
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\GridField\GridFieldDataColumns;
|
||||
use SilverStripe\Reports\Tests\ReportTest\FakeObject;
|
||||
use SilverStripe\Reports\Tests\ReportTest\FakeTest;
|
||||
use SilverStripe\Reports\Tests\ReportTest\FakeTest2;
|
||||
use SilverStripe\Reports\Report;
|
||||
|
||||
|
||||
/**
|
||||
* @package reports
|
||||
* @subpackage tests
|
||||
*/
|
||||
class ReportTest extends SapphireTest
|
||||
{
|
||||
protected $usesDatabase = true;
|
||||
protected static $extra_dataobjects = [
|
||||
FakeObject::class,
|
||||
];
|
||||
|
||||
public function testGetReports()
|
||||
{
|
||||
|
@ -29,32 +30,35 @@ class ReportTest extends SapphireTest
|
|||
public function testExcludeReport()
|
||||
{
|
||||
$reports = Report::get_reports();
|
||||
$reportNames = array();
|
||||
$reportNames = [];
|
||||
foreach ($reports as $report) {
|
||||
$reportNames[] = $report->class;
|
||||
$reportNames[] = get_class($report);
|
||||
}
|
||||
$this->assertContains('ReportTest_FakeTest', $reportNames, 'ReportTest_FakeTest is in reports list');
|
||||
$this->assertContains(FakeTest::class, $reportNames, 'ReportTest_FakeTest is in reports list');
|
||||
|
||||
//exclude one report
|
||||
Report::add_excluded_reports('ReportTest_FakeTest');
|
||||
// Exclude one report
|
||||
Config::modify()->merge(Report::class, 'excluded_reports', [FakeTest::class]);
|
||||
|
||||
$reports = Report::get_reports();
|
||||
$reportNames = array();
|
||||
foreach ($reports as $report) {
|
||||
$reportNames[] = $report->class;
|
||||
$reportNames[] = get_class($report);
|
||||
}
|
||||
$this->assertNotContains('ReportTest_FakeTest', $reportNames, 'ReportTest_FakeTest is NOT in reports list');
|
||||
$this->assertNotContains(FakeTest::class, $reportNames, 'ReportTest_FakeTest is NOT in reports list');
|
||||
|
||||
//exclude two reports
|
||||
Report::add_excluded_reports(array('ReportTest_FakeTest', 'ReportTest_FakeTest2'));
|
||||
// Exclude two reports
|
||||
Config::modify()->merge(Report::class, 'excluded_reports', [
|
||||
FakeTest::class,
|
||||
FakeTest2::class
|
||||
]);
|
||||
|
||||
$reports = Report::get_reports();
|
||||
$reportNames = array();
|
||||
$reportNames = [];
|
||||
foreach ($reports as $report) {
|
||||
$reportNames[] = $report->class;
|
||||
$reportNames[] = get_class($report);
|
||||
}
|
||||
$this->assertNotContains('ReportTest_FakeTest', $reportNames, 'ReportTest_FakeTest is NOT in reports list');
|
||||
$this->assertNotContains('ReportTest_FakeTest2', $reportNames, 'ReportTest_FakeTest2 is NOT in reports list');
|
||||
$this->assertNotContains(FakeTest::class, $reportNames, 'ReportTest_FakeTest is NOT in reports list');
|
||||
$this->assertNotContains(FakeTest2::class, $reportNames, 'ReportTest_FakeTest2 is NOT in reports list');
|
||||
}
|
||||
|
||||
public function testAbstractClassesAreExcluded()
|
||||
|
@ -62,19 +66,21 @@ class ReportTest extends SapphireTest
|
|||
$reports = Report::get_reports();
|
||||
$reportNames = array();
|
||||
foreach ($reports as $report) {
|
||||
$reportNames[] = $report->class;
|
||||
$reportNames[] = get_class($report);
|
||||
}
|
||||
$this->assertNotContains('ReportTest_FakeTest_Abstract',
|
||||
$this->assertNotContains(
|
||||
'ReportTest_FakeTest_Abstract',
|
||||
$reportNames,
|
||||
'ReportTest_FakeTest_Abstract is NOT in reports list as it is abstract');
|
||||
'ReportTest_FakeTest_Abstract is NOT in reports list as it is abstract'
|
||||
);
|
||||
}
|
||||
|
||||
public function testPermissions()
|
||||
{
|
||||
$report = new ReportTest_FakeTest2();
|
||||
$report = new ReportTest\FakeTest2();
|
||||
|
||||
// Visitor cannot view
|
||||
Session::clear("loggedInAs");
|
||||
$this->logOut();
|
||||
$this->assertFalse($report->canView());
|
||||
|
||||
// Logged in user that cannot view reports
|
||||
|
@ -89,93 +95,39 @@ class ReportTest extends SapphireTest
|
|||
$this->logInWithPermission('ADMIN');
|
||||
$this->assertTrue($report->canView());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package reports
|
||||
* @subpackage tests
|
||||
*/
|
||||
class ReportTest_FakeTest extends Report implements TestOnly
|
||||
{
|
||||
public function title()
|
||||
public function testColumnLink()
|
||||
{
|
||||
return 'Report title';
|
||||
}
|
||||
public function columns()
|
||||
{
|
||||
return array(
|
||||
"Title" => array(
|
||||
"title" => "Page Title"
|
||||
)
|
||||
$report = new ReportTest\FakeTest();
|
||||
/** @var GridField $gridField */
|
||||
$gridField = $report->getReportField();
|
||||
/** @var GridFieldDataColumns $columns */
|
||||
$columns = $gridField->getConfig()->getComponentByType(GridFieldDataColumns::class);
|
||||
|
||||
$page = new ReportTest\FakeObject();
|
||||
$page->Title = 'My Object';
|
||||
$page->ID = 959547;
|
||||
|
||||
$titleContent = $columns->getColumnContent($gridField, $page, 'Title');
|
||||
$this->assertEquals(
|
||||
'<a class="grid-field__link-block" href="dummy-edit-link/959547" title="My Object">My Object</a>',
|
||||
$titleContent
|
||||
);
|
||||
}
|
||||
public function sourceRecords($params, $sort, $limit)
|
||||
{
|
||||
return new ArrayList();
|
||||
}
|
||||
|
||||
public function sort()
|
||||
public function testCountForOverview()
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package reports
|
||||
* @subpackage tests
|
||||
*/
|
||||
class ReportTest_FakeTest2 extends 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package reports
|
||||
* @subpackage tests
|
||||
*/
|
||||
abstract class ReportTest_FakeTest_Abstract extends 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 sort()
|
||||
{
|
||||
return 5;
|
||||
$report = new ReportTest\FakeTest3();
|
||||
|
||||
// Count is limited to 10000 by default
|
||||
$this->assertEquals('10000+', $report->getCountForOverview());
|
||||
|
||||
// Count is limited as per configuration
|
||||
Config::modify()->set(ReportTest\FakeTest3::class, 'limit_count_in_overview', 15);
|
||||
$this->assertEquals('15+', $report->getCountForOverview());
|
||||
|
||||
// A null limit displays the full count
|
||||
Config::modify()->set(ReportTest\FakeTest3::class, 'limit_count_in_overview', null);
|
||||
$this->assertEquals('15000', $report->getCountForOverview());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Reports\Tests\ReportTest;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\CMSPreviewable;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class FakeObject extends DataObject implements CMSPreviewable, TestOnly
|
||||
{
|
||||
private static $table_name = 'ReportTest_FakeObject';
|
||||
|
||||
private static $db = array(
|
||||
'Title' => 'Varchar'
|
||||
);
|
||||
|
||||
/**
|
||||
* @return String Absolute URL to the end-user view for this record.
|
||||
* Example: http://mysite.com/my-record
|
||||
*/
|
||||
public function Link()
|
||||
{
|
||||
return Controller::join_links('dummy-link', $this->ID);
|
||||
}
|
||||
|
||||
public function CMSEditLink()
|
||||
{
|
||||
return Controller::join_links('dummy-edit-link', $this->ID);
|
||||
}
|
||||
|
||||
public function PreviewLink($action = null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getMimeType()
|
||||
{
|
||||
return 'text/html';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Reports\Tests\ReportTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\Reports\Report;
|
||||
|
||||
class FakeTest extends Report implements TestOnly
|
||||
{
|
||||
public function title()
|
||||
{
|
||||
return 'Report title';
|
||||
}
|
||||
|
||||
public function columns()
|
||||
{
|
||||
return array(
|
||||
"Title" => array(
|
||||
"title" => "Page Title",
|
||||
"link" => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function sourceRecords($params, $sort, $limit)
|
||||
{
|
||||
return new ArrayList();
|
||||
}
|
||||
|
||||
public function sort()
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Reports\Tests\ReportTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\Reports\Report;
|
||||
|
||||
class FakeTest2 extends 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Reports\Tests\ReportTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\Reports\Report;
|
||||
|
||||
class FakeTest3 extends Report implements TestOnly
|
||||
{
|
||||
public function sourceRecords($params, $sort, $limit)
|
||||
{
|
||||
return new ArrayList(range(1, 15000));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Reports\Tests\ReportTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\Reports\Report;
|
||||
|
||||
abstract class FakeTestAbstract extends 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 sort()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue