careset/zermelo

Zermelo,Laravel的PHP报告引擎

安装次数: 648

依赖者: 1

建议者: 0

安全: 0

星标: 13

关注者: 7

分支: 4

开放问题: 55

语言:JavaScript


README

A PHP reporting engine that works especially well with Laravel, built with love at CareSet Systems

报告方法

在Zermelo中,基本思想是让报告作者只思考SQL SELECT语句,并允许Zermelo处理将查询结果中的数据转换为复杂和丰富的Web界面的翻译。有很多很好的工具可以帮助构建SELECT语句,也有很多优秀的资源可以帮助学习如何在SQL中使用SELECT查询函数。如果你知道如何使用SQL SELECT语句,那么在Zermelo的帮助下,你可以自动创建复杂和交互式的Web报告。

通常,这是通过SQL具有特定变量的别名的功能实现的。对于大多数报告引擎,你可以有一个或多个输出到Zermelo可以理解的特定别名的列的SQL查询。然后报告引擎将自动使用数据输出填充基于Web的数据视图。例如,基于卡的布局引擎允许你将数据行填充到BootStrap Cards中。几乎Bootstrap Card的每个部分都可以通过使用对应于内部支持的css类的列名来填充。bootstrap card component

此方法的例外是表格数据查看器。在这里,你可以从SELECT语句中输出任何你想要的东西,Zermelo将尽力使用DataTables JavaScript项目创建在线自动分页的表格视图。

核心报告功能

  • 编写SQL,自动获取Web报告
  • 用链接、按钮、JS和其他基于Bootstrap的HTML元素装饰报告中的每一行。
  • 使用包含SQL和Web界面装饰的单个PHP文件控制整个Web报告。
  • GET/POST/JSON/URL参数都作为单文件中的本地函数/变量可用。这允许SQL根据传递给特定报告URL的参数进行大量修改。
  • 自动支持服务器端数据分页,允许引擎针对非常大的数据库进行报告
  • 任何报告数据都可以下载为CSV文件
  • 报告自动生成JSON数据源,可用作API
  • 默认支持Laravel的Blade模板引擎(经过更多努力支持任何前端模板引擎)。

如果您想了解我们正在走向何方以及Zermelo报告功能的详细列表,请参阅我们的功能路线图

解释一切的截图

Zermelo Data Flow Diagram

架构

阅读架构图 Zermelo正在执行将“仅仅是SQL”转换为可以一致地且对性能影响最小地加载到单个浏览器会话中的艰巨工作。Zermelo了解如何将这项艰巨的工作推送到MariaDB/MySQL服务器,确保浏览器以涓涓细流的方式获取其数据。后端必须做大量的工作才能实现这一点。

有些查询在后台运行可能需要数小时,即使最终结果只有几百行数据。为了支持这种重负载,Zermelo 理解如何缓存结果。它始终缓存结果,但对于大多数查询,它总是在每次浏览器调用时刷新缓存。

您,作为用户,可以控制其工作方式。查看 控制缓存 文档了解详情。

如何开始使用

先决条件

您需要一个现代的 LAMP 服务器,至少安装了 php 7.2 和至少 Laravel 5.5,请参考 完整先决条件。一旦完成先决条件,您应该在主机系统的浏览器中检查 URL:homestead.test。

安装

请参阅 基本安装 以获取完整的安装说明和数据库设置。

为了快速开始,假设您的 Laravel 实例已经可以访问它需要的数据库

    $ composer require careset/zermelo
    $ php artisan zermelo:install

这将安装和配置 Zermelo,并为您创建一个 app/Reports 目录,以便您可以添加报告。

接下来,您应该测试您的路由...

    $ php artisan route:list | grep Zermelo
|        | GET|HEAD | Zermelo/{report_key}                                 |
|        | GET|HEAD | ZermeloCard/{report_key}                             |
|        | GET|HEAD | ZermeloGraph/{report_key}                            |
|        | GET|HEAD | api/Zermelo/{report_key}/Download/{parameters?}      |
|        | GET|HEAD | api/Zermelo/{report_key}/Summary/{parameters?}       |
|        | GET|HEAD | api/Zermelo/{report_key}/{parameters?}               | 
|        | GET|HEAD | api/ZermeloGraph/{report_key}/Download/{parameters?} |
|        | GET|HEAD | api/ZermeloGraph/{report_key}/{parameters?}          |

运行示例

我们提供了示例报告以及运行这些报告所需的模式和数据。如果您只是刚开始探索系统,这是一个不错的起点。阅读 运行示例

配置说明

  1. 编辑文件 config/zermelo.php 以更改核心 Zermelo 设置,这些值在文件中和 配置文档 中都有解释。
  2. 编辑文件 config/zermelobladetabular.php 以更改特定于 Zermelo Blade 表格视图包的设置。
  3. 在基本安装的早期阶段,您已经创建了 app/Reports 目录。如果您想创建一个不同名称的报告目录,也可以,但您还必须更改命名空间。将 config/zermelo.php 中的 REPORT_NAMESPACE 设置更改为其他内容...
/**
 * Namespace of the report where it will attempt to load from
 */
'REPORT_NAMESPACE' =>env("REPORT_NAMESPACE","app\Reports"),

... 例如 "Zermelo",然后创建一个 ~/code/zermelo-demo/app/Zermelo 目录以放置您的示例报告。注意:如果您更改了 REPORT_NAMESPACE,您还需要将 Northwind*Reports.php 文件的命名空间更改为 "namespace app\Zermelo;"。4. 要配置中间件,您可以在 config/zermelo.php 文件中添加或编辑 MIDDLEWARE 配置设置。这将运行配置的中间件在每个 API 请求上。例如,如果您已启用 Laravel 的身份验证 并希望使用 auth 中间件保护 Zermelo 路由,您可以在 MIDDLEWARE 数组中添加字符串 "auth" 以在每次 API 请求 Zermelo API 时执行 auth 中间件。类似地,对于前端视图包如 zermelobladetabular,您可以在 zermelobladetabular.php 中将 "auth" 字符串添加到 TABULAR_MIDDLEWARE 数组以在路由上启用身份验证。

更新到 Zermelo 的新版本

在项目主目录下

$ composer update careset/zermelo
$ php artisan zermelo:install

当您安装 zermelobladetabular 包时,对“替换”所有这些文件说“不”,除了:“[zermelo/tabular.blade.php] 视图已经存在” Y(替换它!)“[zermelo/layouts/tabular.blade.php] 视图已经存在。” Y(替换它!)

卸载 Zermelo

您可以通过运行 'composer remove' 来卸载 composer 包,以从 composer.json 中删除需求,并从 vendor 目录中删除这些包。在项目主目录下

$ composer remove careset/zermelo 
$ composer clear-cache

创建您的第一个报告

  1. 为了获得您的第一个报告,您需要创建一个报告文件。创建新的报告文件的最简单方法是运行

    php artisan zermelo:make_tabular [您的新的报告名称]

为了了解这是做什么的,请查看下面的示例报告模型。

  1. 编辑新文件 /app/Zermelo/[您的报告名称](或,按照说明中提到的默认设置,/app/Reports/[您的报告名称])。您必须填写一个合理的 GetSQL() 函数,该函数返回单个 SQL 文本字符串或 SQL 文本字符串数组。
  2. 将浏览器指向 https://yourapp.example.com/Zermelo/YourNewReportName
  3. 享受看到数据在自动分页的 Datatables 显示!!
  4. 报告文件中的各种函数和常量可以显著改变报告在前端显示的方式。使用它们来更改报告(一个好的开始是使用 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' => '_zermelo_cache_overload',
    'table' => 'northwind_cust_overload'
];

添加自定义 JavaScript

GetReportJS() 实现此函数以返回一个字符串,该字符串将被放置在报告的结束body标签之前的script标签中。不要包括script标签。此函数应仅返回JS代码。字符串未进行转义,并以原始形式传递给报告。

开启SQL打印视图

isSQLPrintEnabled() 将启用通过/ZermeloSQL/ URL访问报告的功能,而不是运行报告,将显示一个有用的调试屏幕,以美观的格式显示GetSQL()将返回的SQL。这对于调试输入非常有帮助。但是,为了使其工作,需要在/config/zermelo.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

示例报告模型

要查看函数和变量的完整列表,请参阅ZermeloReport模型 - https://github.com/CareSet/Zermelo/blob/master/src/CareSet/Zermelo/Models/ZermeloReport.php

<?php

namespace App\Reports;
use CareSet\Zermelo\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='/Zermelo/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='/Zermelo/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 CareSet</>
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”

$this->getSocket('someWrenchName');

您可以在报告文件中的任何位置调用此函数,但通常是从GetSQL()函数中调用,以便您可以使用结果构建SQL。

将要求用户在与'someWrenchSocket'关联的选项之间进行选择。要使用它,您必须设置'socketwrench'数据库并填充以下表...

--
-- Table structure for table `socketsource`
--

CREATE TABLE `socketsource` (
  `id` int(11) NOT NULL,
  `socketsource_name` varchar(255) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

-- --------------------------------------------------------

--
-- Table structure for table `socket_user`
--

CREATE TABLE `socket_user` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `wrench_id` int(11) NOT NULL,
  `current_chosen_socket_id` int(11) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;



-- --------------------------------------------------------

--
-- Table structure for table `socket`
--

CREATE TABLE `socket` (
  `id` int(10) UNSIGNED NOT NULL,
  `wrench_id` int(11) NOT NULL,
  `socket_value` varchar(1024) COLLATE utf8mb4_unicode_ci NOT NULL,
  `socket_label` varchar(1024) COLLATE utf8mb4_unicode_ci NOT NULL,
  `is_default_socket` tinyint(1) NOT NULL,
  `socketsource_id` int(11) NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


-- --------------------------------------------------------

--
-- Table structure for table `autosocket`
--

CREATE TABLE `autosocket` (
  `id` int(10) UNSIGNED NOT NULL,
  `wrench_id` int(11) NOT NULL,
  `socket_value` varchar(1024) COLLATE utf8mb4_unicode_ci NOT NULL,
  `socket_label` varchar(1024) COLLATE utf8mb4_unicode_ci NOT NULL,
  `is_default_socket` tinyint(1) NOT NULL,
  `socketsource_id` int(11) NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;



-- --------------------------------------------------------

--
-- Table structure for table `wrench`
--

CREATE TABLE `wrench` (
  `id` int(11) NOT NULL,
  `wrench_lookup_string` varchar(200) NOT NULL,
  `wrench_label` varchar(200) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

--
-- 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(他们将只看到socket_label文本)。然后在您的代码中...您可以得到该选择的内容(socket_value),以帮助构建SQL。

查看examples/reports目录中的NorthwindCustomerSocketReport.php以了解影响和示例用例。

这使得您可以编写一个报告,该报告可以在多个底层表上操作,并且最终用户可以选择报告要针对哪些表。

故障排除

请参阅故障排除指南。

为什么是‘Zermelo’?

Zermelo是由CareSet Systems开发的,该公司提供了关于CMS、医疗保险和医疗补助数据的广泛报告。我们开发了Zermelo来简化这项任务。CareSet系统使用集合论、SQL和图技术来数据挖掘医疗保险索赔数据。我们为公司取名“CareSet”是为了突出我们的数据处理方法(我们的标志包含一个图和一组节点,我们认为这是我们的分析方法的良好说明。无论如何,由于我们专注于集合论的数据分析方法,我们认为我们应该以著名集合论数学家的名字来庆祝我们的开源项目。

Ernst Zermelo是两位独立提出著名Russell悖论的数学家之一,另一位是Russell。这个悖论是一个迷人的问题:“包含所有不包含自身的集合的集合,是否包含自身”。这个悖论是Cantor在集合论方面工作的直接结果。所有这些都是19世纪末数学基础工作中的关键章节。

因此,我们认为Zermelo没有得到他在独立发展悖论(以及他的其他工作)方面的足够认可,而且,他有一个很酷的名字,在软件项目中并不常用,除了之前的工作自动化乒乓球锦标赛荷兰学生排课(这两种都是与本项目不同的Zermelo软件解决方案),但这些项目都与数学和数据分析无关。到目前为止,还没有人拥有以这个名字命名的报告引擎,所以我们抓住了庆祝Zermelo对数学和数据分析贡献的机会,用他的名字命名我们的PHP报告引擎!