CakePHP 2:只读模型(useTable = false)+自定义查询(内连接)+分页
CakePHP 2: read-only model (useTable = false) + custom query (inner join) + pagination
我是 CakePHP 的新手。目前使用cake 2.5。另外,我是这个伟大社区的新手。我希望我以正确的方式提出问题 ;)
在 Internet 和这个社区上阅读和阅读后,我仍然没有找到解决问题的方法。
问题:
(如果您赶时间,请只阅读本节。如果您不赶时间,您可以在以上部分 "Additional Info").
我正在开发一个用于报告目的的 Cake 应用程序,它使用 2 个数据库:一个遗留的 MS SQL 服务器数据库,用作获取数据的只读(这是必须的)。还有一个常规 MySQL 数据库,Cake 应用程序将使用它来存储报告、用户偏好以及与只读数据库的某些记录相关的一些数据。抱歉,我不能 post 任何代码或数据库项目的真实名称,因为我签署了保密协议。
重点:
我有一个没有 table(即:$useTable = false
)的模型,它使用与只读数据库的连接。让我们说 ReadOnlyModel.
ReadOnlyModel 通过 运行 自定义查询获取数据(这是必须的)。我通过使用 $this->query($sql);
.
实现了这一点
假设 ReadOnlyModel 的硬编码 MS SQL 服务器查询是:
SELECT
TABLE_A.A_ID, TABLE_A.ONE_STRING,
TABLE_B.PK_COL1, TABLE_B.PK_COL2, TABLE_B.PK_COL3,
TABLE_B.AN_EXTERNAL_ID, TABLE_B.ONE_CODE, TABLE_B.ONE_DATE,
TABLE_B.ONE_NUMBER, TABLE_B.ANOTHER_EXTERNAL_ID,
TABLE_C.OTHER_EXTERNAL_ID
FROM SCHEMA_NAME.dbo.TABLE_A TABLE_A, SCHEMA_NAME.dbo.TABLE_B TABLE_B,
SCHEMA_NAME.dbo.TABLE_C TABLE_C
WHERE TABLE_A.A_ID = TABLE_C.A_ID AND TABLE_A.PK_COL1 = TABLE_B.PK_COL1
AND TABLE_A.PK_COL2 = TABLE_B.PK_COL2
ORDER BY TABLE_B.PK_COL1, TABLE_B.PK_COL2
查询 运行 正常并且正在正确获取所有数据。尽管有 three 涉及 tables,为了简单起见,我将只使用 one Cake 模型来封装数据,因为来自从我的 Cake 应用程序的角度来看,单独与 TABLE_A、TABLE_B 或 TABLE_C 进行交互是没有意义的。这样的"joined records"在Cake应用端可以认为是"unique entities"。
那时,我需要实现这个 ReadOnlyModel 在处理常见的 "reading" 操作时表现得像一个传统的常规 Cake 模型,即:我需要能够使用有关查找、过滤、按 ID 实例化模型等的所有 Cake 功能。
这可能吗?什么是正确的方法?看过Cake官方书的Models and Paginator部分,没找到方法
如果不可能,是否可以以 CakePHP 预期的方式调整 运行 查询和重新构造检索到的数据数组?例如:像这样的东西:
Array (
[ReadOnlyModel] => Array (
[id] => id_value1
[field1] => value1
[field2] => value2
[field3] => value3
...
)
[ReadOnlyModel] => Array (
[id] => id_value2
[field1] => value4
[field2] => value5
[field3] => value6
...
)
...
)
然后将该数组分配给 $data
模型 属性。这样做,是否会将 Cake 核心作为 ReadOnlyModel 是一个正常且常规的 useTable=true
模型?在那种情况下,Paginator 会正常且正确地工作吗?
如果不可能,是否有任何方法可以覆盖或破解某些 CakePHP 核心以获得上述行为?
如果不是或者那不是正确的方法,我可以采用哪些替代方法?实现自定义数据源是否是获得成功的可能方式?
提前致谢!
PS:抱歉,我知道我的问题很笼统,而且没有提供代码示例(因为上面提到的 NDA)。但是,我的问题更多是关于编码技术或与 CakePHP 2.5 功能和限制有关的特定编程问题。对不起,因为我的英语水平。
其他信息 - 澄清我的背景和需求:
(如果您不着急,您可以在下面找到关于我的系统的更多详细信息,它的上下文和要求以及我做出的许多设计决策的原因已经被迫做了。也许,你可以在这里找到你的问题或疑惑的答案)
生产中有一个非常庞大、成熟、经过全面测试、高度优化、大规模且复杂的遗留系统。事实上,这是我遇到过的最大的系统。该系统将充当只读 "master",作为一个巨大的只读数据提供者。
我正在开发一个 Cake 外部应用程序,它只从 "master" 系统中提取一些数据,主要用于报告目的。
根据要求,不可能以任何方式改变"master"系统。所以我不能在那里包含我自己的 tables。因此,我的 Cake 应用程序将拥有自己的 mysql 数据库,用于存储报告、用户首选项,并且在 4-5 种情况下,存储与所需的 "master" 系统数据库的某些记录相关的一些数据在一些报告任务中。
那个"master"系统的核心是一个巨大的MSSQL服务器数据库,有超过500个tables。其中一些 table 非常大和宽(例如:大约 100K 条记录和 120 列)。所有 table 名称和列名称都不是 "cake-friendly"(即:到处都是大写字母和下划线)。此外,一些 table 具有复合主键。
那个 "master" 数据库是高度规范化的,所以 table 之间有很多关系,很多层次的多对多关系。例如:A hasManyAndBelongsTo B,B hasManyAndBelongsTo C,C hasManyAndBelongsTo D 和 D hasManyAndBelongsTo E,4 个级别。此外,A、B、C、D 和 E table 中的每一个都与许多其他 table 有额外的 belongsTo/HasMany/hasManyAndBelongsTo 关系。
我的 Cake 应用程序将仅用于数据提取。它不允许任何类型的操作最终可以在 "master" 系统的状态中引入任何修改。 DELETE 或 UPDATE 查询被禁止。
"master" 系统的管理员将允许我的 Cake 应用程序执行一组我必须向他详细说明的以前已知的查询。我将向他提供我的 Cake 应用程序将使用的查询 "signatures" 的集合,然后他会施展某种魔法将这些查询包含在 "white-list" 中,以允许在 "master" 中执行它们】 系统数据库。此外,他将执行许多针对每个查询的优化任务,以加快查询速度。
因此,"white-list" 将是 "master" 系统和我的 Cake 应用程序之间的唯一连接点。
"master" 系统的管理员要我根据以下规则指定我的查询签名列表:
- 第 1 步:我必须 select 每个查询需要哪些 table
- 第二:我必须 select 每个查询中将使用哪些现有架构列。 “*”运算符将不允许作为列 selector.
- 3rd:我可以随意使用查询中需要的任何其他类型的 SQL 内容,例如聚合函数、"on-the-fly" 或计算列、条件子句、使用文字值等。
4:所有previus元素都将被授权。其余否认。
例如:SELECT A.C1, B.C2 FROM A INNER JOIN B ON A.C3 = B.C4
。
这个签名让我只能操作 A 和 B tables 以及 C1、C2、C3 和 C4 列。此外,还可以使用聚合函数、"on-the-fly" 列等。
例如:SELECT A.C1, B.C2, A.C1 + B.C2 AS 'NEW_COLUMN' FROM A INNER JOIN B ON A.C3 = B.C4
将是一个有效的查询。 "NEW_COLUMN" 可以使用。
例如:SELECT * FROM A INNER JOIN B ON A.C3 = B.C4
将被拒绝
一旦我定义了签名查询,其余未按需要声明的数据库方案将无法用于我的 Cake 应用程序。任何试图访问任何未在白名单中声明的 table 或列的未来操作都将被拒绝。并且任何其他不包含在白名单中的查询都将被拒绝。
结论:我必须限制 CakePHP 的 "automagically" 查询创建能力,以避免 CakePHP 尝试执行 "unauthorized" 查询。因此,必须对 "master" 数据库执行的查询进行硬编码(尽管 WHERE 子句中的文字或注入值将被接受)。
useTable = false
不适用于只读模型。听起来您真正想要的是围绕您要视为单个概念对象的表格的视图。
如果您无法说服 'master' 数据库创建所需的视图,那么您的另一个选择是创建一个模型来执行您需要的非常具体的 SQL。限制 CakePHP 生成的查询的最简单方法是不使用为您创建查询的框架功能。在我看来,您似乎有非常具体的要求,这些要求远远超出了框架可以轻松帮助解决的常规路径。
我是 CakePHP 的新手。目前使用cake 2.5。另外,我是这个伟大社区的新手。我希望我以正确的方式提出问题 ;)
在 Internet 和这个社区上阅读和阅读后,我仍然没有找到解决问题的方法。
问题:
(如果您赶时间,请只阅读本节。如果您不赶时间,您可以在以上部分 "Additional Info").
我正在开发一个用于报告目的的 Cake 应用程序,它使用 2 个数据库:一个遗留的 MS SQL 服务器数据库,用作获取数据的只读(这是必须的)。还有一个常规 MySQL 数据库,Cake 应用程序将使用它来存储报告、用户偏好以及与只读数据库的某些记录相关的一些数据。抱歉,我不能 post 任何代码或数据库项目的真实名称,因为我签署了保密协议。
重点:
我有一个没有 table(即:$useTable = false
)的模型,它使用与只读数据库的连接。让我们说 ReadOnlyModel.
ReadOnlyModel 通过 运行 自定义查询获取数据(这是必须的)。我通过使用 $this->query($sql);
.
假设 ReadOnlyModel 的硬编码 MS SQL 服务器查询是:
SELECT
TABLE_A.A_ID, TABLE_A.ONE_STRING,
TABLE_B.PK_COL1, TABLE_B.PK_COL2, TABLE_B.PK_COL3,
TABLE_B.AN_EXTERNAL_ID, TABLE_B.ONE_CODE, TABLE_B.ONE_DATE,
TABLE_B.ONE_NUMBER, TABLE_B.ANOTHER_EXTERNAL_ID,
TABLE_C.OTHER_EXTERNAL_ID
FROM SCHEMA_NAME.dbo.TABLE_A TABLE_A, SCHEMA_NAME.dbo.TABLE_B TABLE_B,
SCHEMA_NAME.dbo.TABLE_C TABLE_C
WHERE TABLE_A.A_ID = TABLE_C.A_ID AND TABLE_A.PK_COL1 = TABLE_B.PK_COL1
AND TABLE_A.PK_COL2 = TABLE_B.PK_COL2
ORDER BY TABLE_B.PK_COL1, TABLE_B.PK_COL2
查询 运行 正常并且正在正确获取所有数据。尽管有 three 涉及 tables,为了简单起见,我将只使用 one Cake 模型来封装数据,因为来自从我的 Cake 应用程序的角度来看,单独与 TABLE_A、TABLE_B 或 TABLE_C 进行交互是没有意义的。这样的"joined records"在Cake应用端可以认为是"unique entities"。
那时,我需要实现这个 ReadOnlyModel 在处理常见的 "reading" 操作时表现得像一个传统的常规 Cake 模型,即:我需要能够使用有关查找、过滤、按 ID 实例化模型等的所有 Cake 功能。
这可能吗?什么是正确的方法?看过Cake官方书的Models and Paginator部分,没找到方法
如果不可能,是否可以以 CakePHP 预期的方式调整 运行 查询和重新构造检索到的数据数组?例如:像这样的东西:
Array (
[ReadOnlyModel] => Array (
[id] => id_value1
[field1] => value1
[field2] => value2
[field3] => value3
...
)
[ReadOnlyModel] => Array (
[id] => id_value2
[field1] => value4
[field2] => value5
[field3] => value6
...
)
...
)
然后将该数组分配给 $data
模型 属性。这样做,是否会将 Cake 核心作为 ReadOnlyModel 是一个正常且常规的 useTable=true
模型?在那种情况下,Paginator 会正常且正确地工作吗?
如果不可能,是否有任何方法可以覆盖或破解某些 CakePHP 核心以获得上述行为?
如果不是或者那不是正确的方法,我可以采用哪些替代方法?实现自定义数据源是否是获得成功的可能方式?
提前致谢!
PS:抱歉,我知道我的问题很笼统,而且没有提供代码示例(因为上面提到的 NDA)。但是,我的问题更多是关于编码技术或与 CakePHP 2.5 功能和限制有关的特定编程问题。对不起,因为我的英语水平。
其他信息 - 澄清我的背景和需求:
(如果您不着急,您可以在下面找到关于我的系统的更多详细信息,它的上下文和要求以及我做出的许多设计决策的原因已经被迫做了。也许,你可以在这里找到你的问题或疑惑的答案)
生产中有一个非常庞大、成熟、经过全面测试、高度优化、大规模且复杂的遗留系统。事实上,这是我遇到过的最大的系统。该系统将充当只读 "master",作为一个巨大的只读数据提供者。
我正在开发一个 Cake 外部应用程序,它只从 "master" 系统中提取一些数据,主要用于报告目的。
根据要求,不可能以任何方式改变"master"系统。所以我不能在那里包含我自己的 tables。因此,我的 Cake 应用程序将拥有自己的 mysql 数据库,用于存储报告、用户首选项,并且在 4-5 种情况下,存储与所需的 "master" 系统数据库的某些记录相关的一些数据在一些报告任务中。
那个"master"系统的核心是一个巨大的MSSQL服务器数据库,有超过500个tables。其中一些 table 非常大和宽(例如:大约 100K 条记录和 120 列)。所有 table 名称和列名称都不是 "cake-friendly"(即:到处都是大写字母和下划线)。此外,一些 table 具有复合主键。
那个 "master" 数据库是高度规范化的,所以 table 之间有很多关系,很多层次的多对多关系。例如:A hasManyAndBelongsTo B,B hasManyAndBelongsTo C,C hasManyAndBelongsTo D 和 D hasManyAndBelongsTo E,4 个级别。此外,A、B、C、D 和 E table 中的每一个都与许多其他 table 有额外的 belongsTo/HasMany/hasManyAndBelongsTo 关系。
我的 Cake 应用程序将仅用于数据提取。它不允许任何类型的操作最终可以在 "master" 系统的状态中引入任何修改。 DELETE 或 UPDATE 查询被禁止。
"master" 系统的管理员将允许我的 Cake 应用程序执行一组我必须向他详细说明的以前已知的查询。我将向他提供我的 Cake 应用程序将使用的查询 "signatures" 的集合,然后他会施展某种魔法将这些查询包含在 "white-list" 中,以允许在 "master" 中执行它们】 系统数据库。此外,他将执行许多针对每个查询的优化任务,以加快查询速度。
因此,"white-list" 将是 "master" 系统和我的 Cake 应用程序之间的唯一连接点。
"master" 系统的管理员要我根据以下规则指定我的查询签名列表:
- 第 1 步:我必须 select 每个查询需要哪些 table
- 第二:我必须 select 每个查询中将使用哪些现有架构列。 “*”运算符将不允许作为列 selector.
- 3rd:我可以随意使用查询中需要的任何其他类型的 SQL 内容,例如聚合函数、"on-the-fly" 或计算列、条件子句、使用文字值等。
4:所有previus元素都将被授权。其余否认。
例如:
SELECT A.C1, B.C2 FROM A INNER JOIN B ON A.C3 = B.C4
。 这个签名让我只能操作 A 和 B tables 以及 C1、C2、C3 和 C4 列。此外,还可以使用聚合函数、"on-the-fly" 列等。例如:
SELECT A.C1, B.C2, A.C1 + B.C2 AS 'NEW_COLUMN' FROM A INNER JOIN B ON A.C3 = B.C4
将是一个有效的查询。 "NEW_COLUMN" 可以使用。例如:
SELECT * FROM A INNER JOIN B ON A.C3 = B.C4
将被拒绝
一旦我定义了签名查询,其余未按需要声明的数据库方案将无法用于我的 Cake 应用程序。任何试图访问任何未在白名单中声明的 table 或列的未来操作都将被拒绝。并且任何其他不包含在白名单中的查询都将被拒绝。
结论:我必须限制 CakePHP 的 "automagically" 查询创建能力,以避免 CakePHP 尝试执行 "unauthorized" 查询。因此,必须对 "master" 数据库执行的查询进行硬编码(尽管 WHERE 子句中的文字或注入值将被接受)。
useTable = false
不适用于只读模型。听起来您真正想要的是围绕您要视为单个概念对象的表格的视图。
如果您无法说服 'master' 数据库创建所需的视图,那么您的另一个选择是创建一个模型来执行您需要的非常具体的 SQL。限制 CakePHP 生成的查询的最简单方法是不使用为您创建查询的框架功能。在我看来,您似乎有非常具体的要求,这些要求远远超出了框架可以轻松帮助解决的常规路径。