Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP MVC:数据映射器模式:类设计_Php_Oop_Design Patterns_Model View Controller_Data Mapping - Fatal编程技术网

PHP MVC:数据映射器模式:类设计

PHP MVC:数据映射器模式:类设计,php,oop,design-patterns,model-view-controller,data-mapping,Php,Oop,Design Patterns,Model View Controller,Data Mapping,我有一个带有域对象和数据映射器的web MVC应用程序。数据映射器的类方法包含所有数据库查询逻辑。我试图避免镜像任何数据库结构,从而在构造sql语句时实现最大的灵活性。因此,原则上,我尽量不使用任何ORM或ActiveRecord结构/模式 让我举个例子: 通常,我可以让所有特定的数据映射器类继承一个抽象类AbstractDataMapper,比如UserDataMapper类。然后我可以在AbstractDataMapper中定义一个findById()方法,通过给定的id值,例如用户id,来

我有一个带有域对象和数据映射器的web MVC应用程序。数据映射器的类方法包含所有数据库查询逻辑。我试图避免镜像任何数据库结构,从而在构造sql语句时实现最大的灵活性。因此,原则上,我尽量不使用任何ORM或ActiveRecord结构/模式

让我举个例子: 通常,我可以让所有特定的数据映射器类继承一个抽象类
AbstractDataMapper
,比如
UserDataMapper
类。然后我可以在
AbstractDataMapper
中定义一个
findById()
方法,通过给定的
id
值,例如用户id,来获取特定表的记录,比如
users
。但这意味着我总是从单个表中获取记录,不可能使用任何左连接也从与给定的
id
-user id相对应的一些其他表中获取一些其他详细信息

所以,我的问题是: 在这些条件下——我自己也有义务这么做——我应该实现一个抽象的数据映射器类,还是每个数据映射器类都应该包含自己完全“专有”的数据访问层实现

我希望我能把我的想法表达清楚。如果我不清楚或者你有任何问题,请告诉我


非常感谢您的时间和耐心。

如果我理解您的观点

让所有具体的映射程序从一个公共类继承SQL有几个问题您没有注意到:

  • 域对象中的参数名取决于列的名称
  • 映射器中有一种“获取方法”,它没有相应的表
  • 您仍然具有超类所期望的配置(表名)
  • DB架构必须将
    id
    作为所有
    主键
    列的名称
现在,我要把每一个都打开

参数和列名 要创建共享的
findById()
方法,唯一实用的方法是围绕以下内容构建它:

"SELECT * FROM {$this->tableName} WHERE id = :id"
主要问题实际上是通配符
*
符号

使用数据映射器填充实体有两种主要方法:使用setter或使用反射。在这两种情况下,参数/设置器的“名称”都由您选择的列暗示

在普通查询中,您可以执行类似以下操作:
从…
选择名称作为全名,这允许您使用查询来重新命名字段。但如果采用“统一方法”,就没有好的选择

每个映射器都可以通过
id
? 因此,问题是,除非您有一个mapper表结构(在这种情况下,活动记录开始时看起来像是一个实用选项),否则您最终将为您的mapper提供几个(非常常见的)“边缘情况”场景:

  • 仅用于保存数据
  • 处理集合而非单一实体
  • 从多个表聚合数据
  • 使用具有复合键的表
  • 它实际上不是一个表,而是一个SQL视图
  • 。。。或以上两者的组合
您最初的想法在小规模项目中可以很好地发挥作用(一个或两个映射器是“边缘案例”)。但是对于大型项目,使用
findById()
将是一个例外,而不是常态

独立育儿? 要在超类中实际获取这个
findById()
方法,您需要一种与之通信表名的方法。这意味着,在类定义中有类似于
protected$tableName
的内容

您可以通过在抽象映射器类中使用
抽象函数getTableName()
来缓解此问题,该类在实现时返回一个全局常量值

但是,当映射器需要处理多个表时,会发生什么情况呢

对我来说,这似乎是一种代码味道,因为信息实际上跨越了两个界限(因为缺少更好的词)。当此代码中断时,将在超类中显示SQL的错误,而这不是错误的来源(特别是,如果使用常量)

命名主键 这是一个更有争议的观点:)

据我所知,调用所有主列
id
的实践来自各种各样的orm。由此带来的惩罚只适用于可读性(和代码维护)。考虑这两个查询:

SELECT ar.id, ac.id 
  FROM Articles AS ar LEFT JOIN 
       Accounts AS ac ON ac.id = ar.account_id 
 WHERE ar.status = 'published'

SELECT ar.article_id, ac.account_id 
  FROM Articles AS ar LEFT JOIN 
       Accounts AS ac USING(account_id)
 WHERE ar.status = 'published'
随着数据库模式的增长和查询变得越来越复杂,实际跟踪“id”在什么情况下代表什么变得越来越困难

我的建议是,当列是主键时,尝试使用与外键相同的名称(如果可能,因为在某些情况下,如“闭包表,它不可行”)。基本上,存储相同类型ID的所有列都应该具有相同的名称

作为一个小奖励,您可以使用()获得
语法

太长,读不下去了
坏主意。你基本上是在破釜沉舟。

作为一个自己提供了500份赏金的人,这里有一个免费的建议:不要。我不得不要求mods稍后删除那篇帖子,因为我收到的答案都是废话。这会吓跑那些不太自信的人。而且,如果问题不是尽快解决的,你会得到更好的结果在两周内拿到100分的悬赏。见鬼,有了500分的预算,你可以在“悬赏”上贴个帖子“一个多月的时间。”tereško感谢您的评论和善意建议。我不知道。因此,我重新编辑了赏金部分。最后,我的目标是吸引好的答案。我刚刚读了你的答案,我发现我需要更多的时间——现在有点累了。我只想说:非常感谢你,特雷斯科。我以后一定会深入阅读的。我读了你的答案,实际上读了很多遍。哇:-)我想要一个