引导问题:
当我从MongoCursor :: getNext()收到它时,构建我的类T对象的最佳做法是什么?就其而言,MongoCursor的getNext()函数返回一个数组.我希望将该点的结果用作T类型的对象.
我应该为类型T编写自己的构造函数,它接受一个数组吗?是否有任何通用的解决方案,例如当类型T扩展G,并且G以递归方式(对于嵌套文档)以常规方式完成工作.
我是MongoDB的新手,我想用一个漂亮的界面构建我自己的通用映射器.
赏金:
>从PHP的角度来看,哪种方法,模式最适合MongoDB的概念.
这个答案已被重写.
大多数数据映射器通过表示每个类的一个对象来工作,或者“模型”通常是创造的术语.如果您希望允许通过单个对象进行多次加入(即$model-> find()),则通常会对其进行解除限制,以便该方法实际上不会返回自身的实例,而是返回数组或MongoCursor急切加载类的实例进入太空.
这种范例通常与“活动记录”相关联.这是ORM,ODM和框架都以这种或那种方式与数据库进行通信的方法,不仅适用于MongoDB,还适用于SQL和任何其他数据库(Cassandra,CouchDB等).
应该立即注意到,即使活动记录提供了大量功率,也不应该在整个应用程序中覆盖它.有时直接使用驱动程序会更有益.由于这个原因,大多数ORM,ODM和框架都能够快速,轻松地直接访问驱动程序.
正如许多人所说,没有轻量级数据映射器.如果您要将返回的数据映射到类,那么它将消耗资源,结束.这样做的好处是操作对象时获得的力量.
活动记录非常适合在PHP中提供事件和触发器.一个很好的例子是我为Yii制作的ORM:https://github.com/Sammaye/MongoYii它可以为以下内容提供钩子:
> afterConstruct
> beforeFind
> afterFind
> beforeValidate
> afterValidate
> beforeSave
> afterSave
应该注意的是,当遇到像beforeSave和afterSave之类的事件时,MongoDB不具备触发器(https://jira.mongodb.org/browse/SERVER-124),因此应用程序应该处理这个问题是有意义的.除了应用程序处理此问题的明显原因之外,它还可以通过调用本机PHP函数来操作在触摸数据库之前保存的每个文档,从而更好地处理保存函数.
大多数数据映射器都使用PHP自己的类CRUD来表示它们.例如,要创建新记录:
$d=new User();
$d->username='sammaye';
$d->save();
这是一个非常好的方法,因为你创建一个“新”(https://github.com/Sammaye/MongoYii/blob/master/EMongoDocument.php#L46显示我如何准备MongoYii中的新记录)类来创建一个“新”记录.它在语义上很合适.
更新功能通常通过读取功能访问,您无法更新您不知道其中的模型.这将我们带入填充模型的下一步.
为了处理模型不同的ORM,ODM和框架承诺使用不同的方法.例如,我的MongoYii扩展在每个类中使用一个名为model的工厂方法来返回一个新的自身实例,这样我就可以调用动态find和findOne以及其他类似的方法.
一些ORM,ODM和框架提供读取功能作为直接静态函数,使其成为工厂方法本身,而一些使用单例模式,但是,我选择不使用(https://stackoverflow.com/a/4596323/383478).
大多数(如果不是全部)实现某种形式的游标.这用于返回模型的多个并直接包装(通常)MongoCursor以替换current()方法并返回预填充模型.
例如调用:
User::model()->find();
将返回一个EMongoCursor(在MongoYii中),这将使用类用于实例化游标的事实以及调用时如下:
foreach(User::model() as $k=>$v){
var_dump($v);
}
将调用current()方法:https://github.com/Sammaye/MongoYii/blob/master/EMongoCursor.php#L102返回模型的新单个实例.
有一些ORM,ODM和框架实现了急切的数组加载.这意味着他们只需将整个结果作为一系列模型直接加载到RAM中.我个人不喜欢这种方法,它是浪费的,并且当你需要使用活动记录进行更大的更新时,由于在需要添加旧记录的地方添加了一些新功能,这也不是好兆头.
在我继续之前,最后一个话题是MongoDB的无模式特性.将PHP类与MongoDB一起使用的问题在于,您需要PHP的所有功能,但具有MongoDB的可变性质.这很容易在SQL中出现,因为它有一个预定义的模式,你只需查询它和完成的工作;但是,MongoDB没有这样的东西.
这确实使MongoDB中的模式处理非常危险.大多数ORM,ODM和框架要求您使用带有get和set方法的私有变量在现场预定义模式(即Doctrine 2).在MongoYii,使我的生活轻松优雅,我决定通过使用将检测魔法(https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L26是我的__get和https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L47是我的__set)保留MongoDBs无模式的性质,如果属性WA人迹罕至的类,如果该字段是内部_attributes数组,如果没有,则返回null.同样,对于设置属性,我只需在intrernal _attributes变量中设置.
至于处理如何分配这个模式我将内部分配留给了用户,但是,为了处理来自表单等的设置属性,我使用验证规则(https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L236)调用一个名为getSafeAttributeNames()的函数,该函数将返回一个属性列表针对他们的验证规则.如果他们没有验证规则,则不会设置传入的$_POST或$_GET数组中存在的那些属性.因此,这为模式提供了一种安全的模型结构.
所以我们已经介绍了如何实际使用根文档,还要问如何使用数据管理器来处理子文档. Doctrine 2和许多其他人提供了基于完整类的子文档(http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/embedded-mapping.html),但这可能非常有用.相反,我决定提供帮助函数,这将允许灵活使用子文档,而无需将它们加载到模型中,从而消耗RAM.基本上我所做的就是留下它们,因为它们是一个验证器(https://github.com/Sammaye/MongoYii/blob/master/validators/ESubdocumentValidator.php),用于验证它们内部.当然验证器是自生成的,所以如果你在验证器中有一个规则再次使用验证器来发出嵌套子文档的验证,那么它就可以工作了.
所以我认为完成了对ORM,ODM和框架使用数据映射器的非常基本的讨论.当然,我可能会写一篇关于这篇文章的全文,但对于我认为的那一刻,这是一个很好的讨论.