CakePHP 2:只读模型(useTable=false)+自定义查询(内部联接)+分页



我是CakePHP的新手。目前使用蛋糕2.5。此外,我还是这个伟大社区的新手。我希望我以正确的方式提问;)

在互联网和这个社区上读了又读之后,我仍然没有找到解决我问题的方法。

问题是:

(如果你很着急,只阅读本节。如果你不着急,你可以在上面的"附加信息"一节中找到关于我的问题的确切背景的附加信息)

我正在开发一个用于报告目的的Cake应用程序,它使用两个数据库:一个旧的MSSQLServer数据库,它被用作只读(这是必须的)来获取数据。Cake应用程序将使用一个常规MySQL数据库来存储报告、用户偏好以及与只读数据库的某些记录相关的一些数据。很抱歉,我不能发布任何代码或数据库项目的真实名称,因为我签署了保密协议。

关键点:我有一个没有表的模型(即:$useTable = false),使用到只读数据库的连接。比方说ReadOnlyModel

ReadOnlyModel通过运行自定义查询来获取数据(这是必须的)。我通过使用$this->query($sql);来实现这一点。

假设ReadOnlyModel的硬编码MS SQL Server查询是:


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

查询运行正常,并且正在正确获取所有数据。尽管有三个涉及的表,为了简单起见,我将只使用一个Cake模型来封装数据,因为从我的Cake应用程序的角度来看,单独与TABLE_A、TABLE_b或TABLE_C交互是没有意义的。在Cake应用程序端,这样的"连接记录"可以被视为"唯一实体"。

在这一点上,我需要实现这个ReadOnlyModel在处理常见的"读取"操作时表现为传统和常规的Cake模型,即:我需要能够使用关于查找、过滤、通过ID实例化模型等的所有Cake功能

这可能吗?什么是正确的方式?我读过官方蛋糕书的模特和传呼机部分,但我不知道该怎么办。

如果不可能,是否可以运行查询并以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模型?在这种情况下,传呼机能正常工作吗?

如果这是不可能的,有没有任何方法可以覆盖或破解CakePHP核心以获得上述行为?

如果不是,或者这不是正确的方式,我可以采取什么替代方法?实现自定义数据源是获得成功的可能途径吗?

提前谢谢!

PS:很抱歉,因为我知道我的问题很一般,而且没有提供代码样本(因为上面提到的NDA)。然而,我的问题更多的是关于CakePHP 2.5功能和限制的编码技术或特定编程问题。对不起,因为我的英语水平。


其他信息-澄清我的背景和需求:

(如果你不着急,你可以在下面找到关于我的系统、it上下文和it要求的更多细节,以及我被迫做出的许多设计决定的原因。也许,你可以在此找到你的问题或疑虑的答案)

  • 生产中有一个非常大、成熟、经过充分测试、超优化、高规模和复杂的遗留系统。事实上,这是我所面对过的最大的系统。该系统将充当只读的"主机",作为一个巨大的只读数据提供者。

  • 我正在开发一个Cake外部应用程序,它只从"主"系统中提取几个数据,主要用于报告目的。

  • 根据要求,根本不可能以任何方式更改"主"系统。所以我不能在那里包括我自己的桌子。正因为如此,我的Cake应用程序将拥有自己的mysql数据库,用于存储报告、用户偏好,在4-5种情况下,还将存储与某些报告任务所需的"主"系统数据库的一些记录相关的一些数据。

  • 这个"主"系统的核心是一个巨大的MSSQLServer数据库,它有500多个表。其中一些表非常大和宽(例如:大约100K条记录和120列)。所有的表名和列名都不是"蛋糕友好型"的(即:到处都是大写字母和下划线)。此外,有些表具有复合主键。

  • 这个"主"数据库是高度规范化的,所以表之间有很多关系,很多级别的多对多关系。例如:A有ManyAndBelongsTo B,B有ManyAandBelongsToC,C有ManyAnd BelongsTo-D,D有ManyAAndBelongsToPoE,4个级别。此外,A、B、C、D和E表中的每一个都有额外的BelongTo/HasMany/hasManyAndBelongsTo与许多其他表的关系。

  • 我的Cake应用程序将仅用于数据提取。它不允许任何可能最终对"主"系统状态进行任何修改的操作。DELETE或UPDATE查询被禁止。

  • "主"系统的管理员将允许我的Cake应用程序执行一组以前已知的查询,我必须向他详细说明这些查询。我会为他提供一组我的Cake应用程序将使用的查询"签名",然后他会做出一些魔术,将这些查询包括在"白名单"中,以便在"主"系统数据库中执行它们。此外,他还将针对每个查询执行许多优化任务,以加快查询速度。

  • 因此,"白名单"将是"主"系统和我的Cake应用程序之间的唯一连接点。

  • "主"系统的管理员希望我根据以下规则指定查询签名列表:

    • 第一:我必须选择每个查询中需要哪些表
    • 第二:我必须选择在每个查询中使用哪些现有的模式列。不允许将"*"运算符用作列选择器
    • 第三:我可以在查询中随意使用任何其他类型的SQL,如聚合函数、"动态"或计算列、条件子句、使用文字值等
    • 第四:所有先前的元素都将被授权。其他人否认了。

      例如:SELECT A.C1, B.C2 FROM A INNER JOIN B ON A.C3 = B.C4。此签名使我只能操作A和B表以及C1、C2、C3和C4列。此外,还可以使用聚合函数、"动态"列等等

      例如: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应用程序。将来尝试访问白名单中未声明的任何表或列的任何操作都将被拒绝。任何其他未包含在白名单中的查询都将被拒绝。

结论:我必须限制CakePHP的"自动"查询创建能力,以避免CakePHP试图执行"未经授权"的查询。因此,对"master"数据库执行的查询必须进行硬编码(尽管WHERE子句中的文字或注入值将被接受)。

useTable = false不适用于只读模型。听起来,你真正想要的是一个围绕表的视图,你想把这些表视为单个概念对象。

如果您无法说服您的"master"数据库创建所需的视图,那么您的另一个选择是创建一个执行所需特定SQL的模型。限制CakePHP生成的查询的最简单方法是不使用为您创建查询的框架功能。对我来说,听起来你有一些非常具体的需求,这些需求远远超出了框架可以轻松帮助解决的路径。

最新更新