owlookit / quickrep
Quickrep,一个为Laravel设计的PHP报表引擎
Requires
- php: >=8.1.0
- components/jquery: ^3.6
- datatables/datatables: 1.10.21
- doctrine/sql-formatter: ^1.2
- fortawesome/font-awesome: ^6.5
- moment/moment: ^2.30
- phpoffice/phpspreadsheet: ^1.29
- twbs/bootstrap: 4.1.3
This package is auto-updated.
Last update: 2024-09-02 04:26:36 UTC
README
一个与Laravel配合得很好的PHP报表引擎
报表方法
Quickrep的基本思想是让报表作者只考虑SQL SELECT语句,并允许Quickrep处理查询结果数据到复杂和丰富的Web界面的转换。有许多优秀的工具可以帮助构建SELECT语句,也有成千上万的资源可以学习如何在SQL中使用SELECT查询函数。如果你知道如何使用SQL SELECT语句,那么借助Quickrep,你可以自动创建复杂和交互式的Web报表。
通常,这可以通过SQL具有特定变量的别名功能来实现。对于大多数报表引擎,你可以有一个或多个SQL查询输出到Quickrep理解的特定别名列。然后,报表引擎将自动用数据输出填充基于Web的数据视图。例如,基于卡的布局引擎允许你将数据行填充到BootStrap Cards中。几乎Bootstrap Card的每个部分都可以通过使用对应于内部支持的css类的列名来填充。
这个方法的例外是表格数据查看器。在这里,你可以从SELECT语句输出任何内容,Quickrep将尽最大努力使用DataTables JavaScript项目创建在线自动分页的表格视图。
核心报表功能
- 编写SQL,自动获取Web报表
- 使用链接、按钮、JS和其他基于Bootstrap的HTML元素装饰报表中的每一行。
- 使用包含SQL和Web界面装饰的单个PHP文件控制整个Web报表。
- GET/POST/JSON/URL参数在单个文件中作为本地函数/变量可用。这允许SQL根据传递给特定报表URL的参数进行大量修改。
- 自动支持服务器端数据分页,允许引擎对非常大的数据库进行报表
- 任何报表数据都可以下载为CSV文件
- 报表自动生成JSON数据源,可用于作为API
- 开箱即支持Laravel的Blade模板引擎(需要更多努力支持任何前端模板引擎)。
截图解释一切
架构
阅读架构图 Quickrep负责将“单纯的SQL”转换为可以一致地加载到单个浏览器会话中的东西,同时对性能的影响最小。Quickrep理解如何将繁重的工作推送到MariaDB/MySQL服务器,确保浏览器以涓涓细流的方式获取数据。后端必须进行大量工作才能实现这一点。
某些查询可能会让后端运行数小时,即使结果是几百行数据。为了支持这些繁重的工作,Quickrep理解如何缓存结果。它总是缓存结果,但对于大多数查询,它总是在每次浏览器调用时刷新缓存。
您,作为用户,可以控制其工作方式。请参阅控制缓存文档以了解如何操作。
如何开始使用它
先决条件
您需要一个具有至少php 7.2和至少Laravel 5.5的现代LAMP服务器 完整先决条件 完成先决条件后,您应该在URL:homestead.test上在主机系统的浏览器中检查URL。
安装
请参阅基本安装以获取完整的安装说明和数据库设置。
为了快速开始,假设您的Laravel实例已经可以访问所需的数据库
$ composer require owlookit/quickrep $ php artisan quickrep:install
这将安装和配置quickrep,并在app/Reports中为您创建一个添加报告的地方。
接下来,您应该测试您的路由...
$ php artisan route:list | grep Quickrep
| | GET|HEAD | Quickrep/{report_key} |
| | GET|HEAD | QuickrepCard/{report_key} |
| | GET|HEAD | QuickrepGraph/{report_key} |
| | GET|HEAD | api/Quickrep/{report_key}/Download/{parameters?} |
| | GET|HEAD | api/Quickrep/{report_key}/Summary/{parameters?} |
| | GET|HEAD | api/Quickrep/{report_key}/{parameters?} |
| | GET|HEAD | api/QuickrepGraph/{report_key}/Download/{parameters?} |
| | GET|HEAD | api/QuickrepGraph/{report_key}/{parameters?} |
运行示例
我们提供示例报告以及运行这些报告所需的模式和数据。如果您只是探索系统,这是一个很好的起点。请参阅运行示例
配置说明
- 编辑文件
config/quickrep.php
以更改核心quickrep设置,这些值在文件中以及配置文档中有解释 - 编辑文件
config/quickrepbladetabular.php
以更改针对quickrep blade tabular视图包的特定设置。 - 在基本安装的早期,您已经创建了app/Reports目录。如果需要,您可以创建一个不同名称的报告目录,但您也必须更改命名空间。将config/quickrep.php中的REPORT_NAMESPACE设置更改为其他...
/**
* Namespace of the report where it will attempt to load from
*/
'REPORT_NAMESPACE' =>env("REPORT_NAMESPACE","app\Reports"),
... 例如 "Quickrep",然后创建一个 ~/code/quickrep-demo/app/Quickrep 目录以放置您的示例报告。注意:如果您更改REPORT_NAMESPACE,您还需要将Northwind*Reports.php文件的命名空间更改为"namespace app\Quickrep;"。 4. 要配置中间件,您可以在config/quickrep.php文件中添加或编辑MIDDLEWARE配置设置。这将在每个API请求上运行配置的中间件。例如,如果您已启用Laravel的认证并希望使用auth中间件保护Quickrep路由,则可以将字符串"auth"添加到MIDDLEWARE数组中,以便在Quickrep API的每个API请求上执行auth中间件。类似地,对于像quickrepbladetabular这样的前端视图包,您可以在quickrepbladetabular.php中将字符串"auth"添加到TABULAR_MIDDLEWARE数组中,以在路由上启用认证。
升级到quickrep的新版本
在项目主目录下
$ composer update owlookit/quickrep
$ php artisan quickrep:install
当您安装quickrepbladetabular包时,对“替换”所有这些文件说“不”,除了:“[quickrep/tabular.blade.php]视图已存在” Y(替换它!)“[quickrep/layouts/tabular.blade.php]视图已存在。” Y(替换它!)
卸载Quickrep
您可以通过运行'composer remove'来卸载composer包,以从composer.json中删除需求,并从vendor目录中删除这些包。在项目主目录下
$ composer remove owlookit/quickrep
$ composer clear-cache
创建您的第一个报告
-
为了获取您的第一个报告,您需要创建一个报告文件。创建新报告文件的最简单方法是运行
php artisan quickrep:make_tabular [您的报告名称]
要了解这做什么,请查看下面的示例报告模型。
- 编辑新文件
/app/Quickrep/[您的报告名称]
(或,按照说明中提到的默认值,/app/Reports/[您的报告名称]
)您必须填写一个合理的GetSQL()函数,该函数返回单个SQL文本字符串或SQL文本字符串数组。 - 将您的浏览器指向https://yourapp.example.com/Quickrep/YourNewReportName
- 享受看到您的数据在自动分页的 Datatables 显示中!!
- 报告文件中的各种功能和常量可以显著改变报告在客户端的显示方式。使用它们来更改报告(一个很好的入门技巧是使用 MapRow 函数将一个报告链接到另一个报告)
功能 / 函数参考
基础
GetSQL() 这是报告的核心。在您的报告子类中实现此函数,添加 SQL 查询以填充报告。默认情况下,您的 SELECT 语句中的列名成为报告的标题。
GetReportName() 实现此函数以返回报告的标题。
GetReportDescription() 实现此函数,返回的字符串将打印在标题下方报告描述块中。字符串不会被转义,并且是原始传递给报告的,因此可以打印 HTML(例如表单元素)
GetReportFooter() 实现此函数以返回将在报告布局底部显示的脚注标签内的字符串。字符串不会被转义,并且是原始传递给报告的,因此可以打印 HTML(例如表单元素)
GetReportFooterClass() 实现此类以向您的脚注添加特定类。添加 "fixed" 以使脚注固定到底部,添加 "centered" 以居中脚注内容。例如,实现此函数以返回 "fixed centered" 以使脚注固定,并使其内容居中。
行和标题操作
MapRow(array $row, int $row_number) 实现此方法以修改表格单元格内容。在显示表格视图时,您的报告子类可以选择修改每个行单元格的内容。
OverrideHeader(array &$format, array &$tags) 实现此方法以覆盖默认列格式或添加要发送回前端的后置列标记
缓存配置
isCacheEnabled() 打开或关闭缓存。默认返回 false,表示缓存关闭。如果您将此函数设置为返回 true,则将启用缓存。始终会 创建 缓存表,但启用缓存时,将使用缓存来回答后续查询,而不是重新运行原始查询。这可能会导致混乱的结果(即,更改底层数据不会在缓存使用时更改报告的内容),因此默认情况下是关闭的。但对于许多大型且慢速的查询,缓存是必要的。
howLongToCacheInSeconds() 如果启用了缓存,我们使用此设置来配置在重新运行原始查询之前希望保留缓存报告的时间长度。
getCacheDatabaseSource() 指定我们希望报告指向的位置,覆盖自动生成的缓存表名。使用此属性,报告开发人员可以指定缓存数据库的源。如果您希望数据出现在特定的、已知的位置,并且希望报告指向它,则可能需要使用此属性。您可以在报告中实现此函数,或使用此结构设置属性 $CACHE_DATABASE_SOURCE
protected $CACHE_DATABASE_SOURCE = [
'database' => '_quickrep_cache_overload',
'table' => 'northwind_cust_overload'
];
添加自定义 JavaScript
GetReportJS() 实现此函数以返回将在报告关闭 body 标签之前放置的字符串。不要包含脚本标签。此函数应仅返回 JS 代码。字符串不会被转义,并且是原始传递给报告的。
开启 SQL 打印视图
isSQLPrintEnabled() 该函数将启用使用 /QuickrepSQL/ URL 访问报告的能力,而不是运行报告,而是会显示一个有用的调试界面,以格式化的方式显示 GetSQL() 会返回的 SQL 语句。这对于调试输入非常有帮助。但是,要使其正常工作,需要在 /config/quickrep.php 文件中启用 SQL 视图。
GetSQL() 中可用的 API 函数
getInput($key = null) 使用此函数获取传递给报告的 GET 参数的值。您可以在 GetSQL() 函数中使用此功能,根据请求查询字符串中传递的附加参数来影响查询。
setInput($key, $new_value) 这是一个有用但危险的函数,允许特定报告在用户使用之前覆盖输入。请谨慎使用,因为这将导致更改用户界面中的设置无法正常工作。TODO(UX 提示设置已被冻结)
setDefaultInput($key, $new_value) 这将设置一个输入变量为起始值,直到 UX 中重置值。(与 setInput 不同,它不会覆盖用户值)
setDefaultSortOrder($sort_array) 这是一个用于 setInput() 的辅助函数,允许在 UI 上设置表格(以及表格派生)视图的默认排序顺序。sort_array 参数的形式如下:$sort_order = [['order_count' => 'desc'], ['name' => 'asc']];
这将导致按订单数量最多的行显示在最上面,当多行具有相同的订单数量时,将按字母顺序列出。
pushViewVariable($key, $value) 使用此函数将变量传递给视图,而无需通过请求/响应周期。key 参数是一个字符串,将作为 php 变量在视图模板中可用。例如,如果您在 GetSQL() 函数中有以下内容
$this->pushViewVariable('extra_var',true)
那么您的变量将在视图中作为 $extra_var 可用,值为 'true'。
@if ($extra_var === true)
<p>ExtraVar Is True!</p>
@endif
示例报告模型
要查看函数和变量的完整列表,请参阅 QuickrepReport 模型 - https://github.com/Owlookit/Quickrep/blob/master/src/Owlookit/Quickrep/Models/QuickrepReport.php
namespace App\Reports; use Owlookit\Quickrep\Reports\Tabular\AbstractTabularReport; class ExampleReport extends AbstractTabularReport { /* * Get the Report Name */ public function GetReportName(): string { return("Enter your report name here"); } /* * Get the Report Description, bootstrap styled html is OK */ public function GetReportDescription(): ?string { $desc = "This is your report description <b> HTML is fine here </b>"; return($desc); } /** * This is what builds the report. It will accept a SQL statement or an Array of sql statements. * Can be used in conjunction with Inputs to determine different output based on URI parameters * Additional URI parameters are passed as * $this->getCode() - which will give the first url segment after the report name * $this->getParameters() - which will give an array of every later url segment after the getCode value * $this->getInput() - which will give _GET and _POST parameters. Should also get values inside JSON that is posted... a unified view of user input * $this->quote($something_you_got_from_the_user) - This wrapper to the PDO quote function is good for preventing SQL injection * $this->setInput($key,$new_value) - a way to override _GET parameters (i.e. for initializing a sort for instance) * For instance $this->setInput('order',[0 => ['order_by_me' => 'asc']]); will order the report, to start by the order_by_me column ASC. * This replicates what is being passed from the front end data tables to the backend to make sorting work.. **/ public function GetSQL() { //replace with your own SQL $sql = "SELECT * FROM information_schema.TABLES"; return $sql; } /** * Each row content will be passed to MapRow. * Values and header names can be changed. * Columns cannot be added or removed * You can decorate fields with html, with bootstrap css styling * */ public function MapRow(array $row, int $row_number) :array { /* //this logic would ensure that every cell in the TABLE_NAME column, was converted to a link to //a table drilldown report $table_name = $row['TABLE_NAME']; $row['TABLE_NAME'] = "Gotta Love Those Row Decorations: $table_name"; //this will make table name a link to another report //$row['TABLE_NAME'] = "<a href='/Quickrep/TableDrillDownReport/$table_name/'>$table_name</a>"; //this will do the same thing, but styling the link as a bootstrap button. //$row['TABLE_NAME'] = "<a class='btn btn-primary btn-sm' href='/Quickrep/TableDrillDownReport/$table_name/'>$table_name</a>"; */ return $row; } /** * If a column needs to be forced to a certain format (i.e.ear auto-detection gets it wrong), it can be changed here * Tags can also be applied to each header column */ public function OverrideHeader(array &$format, array &$tags): void { //$tags['field_to_bold_in_report_display'] = ['BOLD']; //$tags['field_to_hide_by_default'] = ['HIDDEN']; //$tags['field_to_italic_in_report_display'] = ['ITALIC']; //$tags['field_to_right_align_in_report'] = ['RIGHT']; //How to set the format of the display //$format['numeric_field'] = 'NUMBER'; // Formats number in table using commas, and right-aligns //$format['decimal_field'] = 'DECIMAL'; // Formats decimal to 4 places, and right-aligns //$format['currency_field'] = 'CURRENCY'; // adds $ or Eurosign and right align //$format['percent_field'] = 'PERCENT'; // adds % in the right place and right align //$format['url_field'] = 'URL'; // auto-link using <a href='$url_field'>$url_field</a> //$format['date_field'] = 'DATE'; // future date display //$format['datetime_field'] = 'DATETIME'; //future date time display //$format['time_field'] = 'TIME'; // future time display //$format['row_summary_field'] = ['DETAIL']; // this field will be shown with a + sign in the column. //pressing the plus will create a new row in the table //that shows the actual contents of this column. } /** * Header Format 'auto-detection' can be changed per report. * it is based on seeing the strings below in a field name... it will then assume it should be styled accordingly * So it a column label is 'very_good_num' or 'this num' will be matched by 'num' but 'number' will not work. * so it is matched on ignore case on a column name segment, not on substring... * By default, these are the column formats - * public $DETAIL = ['Sentence']; * public $URL = ['URL']; * public $CURRENCY = ['Amt','Amount','Paid','Cost']; * public $NUMBER = ['id','#','Num','Sum','Total','Cnt','Count']; * public $DECIMAL = ['Avg','Average']; * public $PERCENT = ['Percent','Ratio','Perentage']; * * It detects the column by using 'word' matching, separated white spaces or _. * Example: TABLE_ROWS - ['TABLE','ROWS'] * It will also check the full column name */ public $NUMBER = ['ROWS','AVG','LENGTH','DATA_FREE']; /* * By Default, any numeric field will have statistical information will be passed on. AVG/STD/MIN/MAX/SUM * Any Text column will have distinct count information passed on. * Any Date will have MIN/MAX/AVG * This field will add a "NO_SUMMARY" field to the column header to suggest the data not be displayed */ public $SUGGEST_NO_SUMMARY = ['ID']; /** * Want to use your own blade file for the report front-end? * You can customize the report view based on the report * When this is set to null, the report will use the view defined in the configuration file. * */ public $REPORT_VIEW = null; /* * Get Indexes for cache table * Because results are saved to a cache table, and then exported from there later searching, using the front end... can be very slow * This returns an array of Index commands that will be run against the cache table * because we do not know the name of the cache table in advance, these index commands must use the string '{{_CACHE_TABLE_}}' instead of * the name of a specific table... */ public function GetIndexSQL(): ?array { $index_sql = [ "ALTER TABLE {{_CACHE_TABLE_}} ADD INDEX(`COLUMN_NAME`);", "ALTER TABLE {{_CACHE_TABLE_}} ADD INDEX(`TABLE_NAME`);", "ALTER TABLE {{_CACHE_TABLE_}} ADD INDEX(`database_name`);", "ALTER TABLE {{_CACHE_TABLE_}} ADD PRIMARY KEY( `database_name`, `TABLE_NAME`, `COLUMN_NAME`); " ]; // you can uncomment this line to enable the default report to automatically index the resulting cached table // return($index_sql); //returning null here results in no indexing happening on the cached results table return(null); } /** * @return null|string * * Return the footer of the report. This string will be placed in the footer element * at the bottom of the page. */ public function GetReportFooter(): ?string { $footer = <<<FOOTER <p>Made with love by Owlookit</> FOOTER; return $footer; } /** * @return null|string * * Add a string here to put in the class of the footer element of the report layout */ public function GetReportFooterClass(): ?string { // Add "fixed centered" to have your footer fixed to the bottom, and/or centered // This will be put in the class= attribute of the footer return ""; } /** * @return null|string * * This will place the enclosed Javascript in a <script> tag just before * the body of your view. Note, there is no need to include a script tag * in this string. The content of this string is not HTML encoded, and is passed * raw to the view. */ public function GetReportJS(): ?string { $javascript = <<<JS alert("place javascript code here"); JS; return $javascript; } /** * If the cache is not enabled, then every time the page is reloaded the entire report is re-processed and put into the cache table * So if you want to just run the report one time, and then load subsequent data from the cache, set this to return 'true'; */ public function isCacheEnabled(){ return(false); } /** * This function does nothing if isCacheEnabled is returning false * But if the cache is enabled, then this will detail how long the report will be reloaded from the cache before the cache is regenerated by re-running the report SQL */ public function howLongToCacheInSeconds(){ return(1200); //twenty minutes by default } public function isSQLPrintEnabled(): bool{ return(false); } }
高级功能
其中最先进的功能之一是在报告中使用 "socket/wrench" 的概念。
基本上,您在报告中请求的每个 "wrench" 都会要求用户在关联 'someWrenchSocket' 的选项之间进行选择。
$this->getSocket('someWrenchName');
您可以在报告文件中的任何地方调用此函数,但通常是从 GetSQL() 函数中调用,以便您可以使用结果来构建 SQL。
为了使用它,您必须设置 'socketwrench' 数据库,并用以下表填充它...
--
-- Table structure for table socketsource
--
CREATE TABLE socketsource (
id int NOT NULL,
socketsource_name varchar(255) NOT NULL,
created_at timestamp NOT NULL, updated_at timestamp NOT NULL
);
-- --------------------------------------------------------
--
-- Table structure for table socket_user
--
CREATE TABLE socket_user (
id int NOT NULL,
user_id int NOT NULL,
wrench_id int NOT NULL,
current_chosen_socket_id int NOT NULL,
created_at timestamp NOT NULL,
updated_at timestamp NOT NULL
);
-- --------------------------------------------------------
--
-- Table structure for table socket
--
CREATE TABLE socket (
id int NOT NULL,
wrench_id int NOT NULL,
socket_value varchar(1024) NOT NULL,
socket_label varchar(1024) NOT NULL,
is_default_socket smallint NOT NULL,
socketsource_id int NOT NULL,
created_at timestamp NULL DEFAULT NULL,
updated_at timestamp NULL DEFAULT NULL
);
-- --------------------------------------------------------
--
-- Table structure for table autosocket
--
CREATE TABLE autosocket (
id int NOT NULL,
wrench_id int NOT NULL,
socket_value varchar(1024) NOT NULL,
socket_label varchar(1024) NOT NULL,
is_default_socket smallint NOT NULL,
socketsource_id int NOT NULL,
created_at timestamp NULL DEFAULT NULL,
updated_at timestamp NULL DEFAULT NULL
);
-- --------------------------------------------------------
--
-- Table structure for table wrench
--
CREATE TABLE wrench (
id int NOT NULL,
wrench_lookup_string varchar(200) NOT NULL,
wrench_label varchar(200) NOT NULL,
created_at timestamp NOT NULL,
updated_at timestamp NOT NULL
);
--
-- Indexes for dumped tables
--
--
-- Indexes for table socket
--
ALTER TABLE socket
ADD PRIMARY KEY (id),
ADD UNIQUE KEY wrench_value (socket_value,socket_label),
ADD KEY wrench_id (wrench_id);
--
-- Indexes for table autosocket
--
ALTER TABLE autosocket
ADD PRIMARY KEY (id),
ADD UNIQUE KEY wrench_value (socket_value,socket_label),
ADD KEY wrench_id (wrench_id);
--
-- Indexes for table socketsource
--
ALTER TABLE socketsource
ADD PRIMARY KEY (id);
--
-- Indexes for table socket_user
--
ALTER TABLE socket_user
ADD PRIMARY KEY (id);
--
-- Indexes for table wrench
--
ALTER TABLE wrench
ADD PRIMARY KEY (id),
ADD UNIQUE KEY wrench_lookup_string (wrench_lookup_string),
ADD UNIQUE KEY wrench_label (wrench_label);
然后您通过将选项放入 socket 数据库中,链接到正确的 wrench_id 来确定每个 "wrench" 的可用选项。用户可以选择他们想要的插座(他们将只看到 socket_label 文本)。然后,在您的代码中...您将能够获得该选择的内容(socket_value),以帮助构建 SQL。
查看 examples/reports 目录中的 NorthwindCustomerSocketReport.php 以了解其影响和示例用例。
这使您可以编写一个报告,该报告可以在多个底层表上操作,并且最终用户可以选择他们想要的报告目标表。
故障排除
请参阅 故障排除 指南。
为什么是 'Quickrep'?
Quickrep 由 Owlookit Systems 开发,该公司提供 LMS、CMS、Medicare 和 Medicaid 数据的广泛报告。我们开发了 Quickrep 以使这项任务更容易。Owlookit systems 使用集合论、SQL 和图技术来数据挖掘 Medicare 索赔数据。