tequila / mongodb-driver-wrapper
包装MongoDB驱动类以访问其内部结构
此包的官方仓库似乎已丢失,因此该包已被冻结。
Requires
- php: >=5.6
- ext-mongodb: >=1.1.0
This package is auto-updated.
Last update: 2024-08-15 04:02:01 UTC
README
此库在新的官方PHP MongoDB驱动周围提供了一个轻量级的包装。这可能对您有所帮助
- 如果您不想使用围绕PHP MongoDB驱动的高层抽象,例如Tequila MongoDB PHP库或官方的MongoDB PHP库,而您打算使用本地驱动类,请阅读以下内容,了解使用此库可能带来的好处。
- 如果您正在编写围绕新PHP MongoDB驱动的抽象,例如替代的高层驱动库。
如果这不符合您的需求,您可以尝试使用高级工具,例如基于此库的Tequila MongoDB PHP库。
通过包装驱动类,此库允许您执行一些仅使用原生驱动时无法完成的功能。以下是一些功能。
安装
此库需要PHP 5.6或更高版本,PHP 7.0或更高版本。它可能与MongoDB 2.4+一起工作,但将仅提供MongoDB 3.0+的支持。由于此库包装了官方PHP MongoDB驱动,因此需要安装此驱动。
$ pecl install mongodb
应使用Composer安装此库
$ composer require tequila/mongodb-driver-wrapper
为何要使用此库
您的代码变得可测试
假设您正在编写使用MongoDB驱动类与MongoDB服务器通信的代码。您需要为您的代码编写测试。由于MongoDB驱动有自己的测试,因此您不需要通过向数据库发出真实查询来重复它们。您想做的,是编写针对您的代码的测试,并检查您的代码是否正确调用MongoDB\Driver\Manager
方法,因为此类是PHP与MongoDB通信的唯一入口。
让我们假设您想测试以下代码
<?php class Database { public function __construct(\MongoDB\Driver\Manager $manager, $databaseName) { // ... } public function createCollection($collectionName, array $options = []) { // ... } } $db = new Database(new \MongoDB\Driver\Manager(), 'myapp'); $db->createCollection('logs', ['capped' => true, 'size' => 1000000]);
要确保此代码正常工作,您实际上需要检查MongoDB\Driver\Manager::executeCommand()
是否以适当的参数调用。在这种情况下,您将需要使用mocks
。但是这里有一个问题 - 您无法模拟MongoDB\Driver\Manager
以检查其方法executeCommand()
是否被调用,因为此类是最终的。您也无法模拟MongoDB\Driver\Command
和其他驱动器的原生类。因此,您有两种测试代码的方式,这取决于驱动器。
- 创建功能测试,实际上会对MongoDB发出调用,然后在MongoDB服务器上检查结果。这不是最佳解决方案,因为您的测试将依赖于已安装和启用的MongoDB服务器。此外,您还将做额外的工作 - 测试整个链而不是仅测试您的代码。
- 不要测试代码的行为——例如测试你的
Database
实例在向其构造函数传递正确参数时不会抛出异常,但不要测试它的createCollection()
方法,因为这个方法实际上会执行一些操作。但这也不太好,因为你将无法确定你的代码是否真正经过测试和稳定。
这就是这个库可以提供帮助的地方:它定义了具有与驱动类几乎相同接口的类。你可以使用这些类来代替原生驱动类,模拟它们,从而使你的代码可测试。例如,Tequila\MongoDB\Manager
类封装了原生的 MongoDB\Driver\Manager
类,Tequila\MongoDB\Manager::executeQuery()
接受 Tequila\MongoDB\Query
实例而不是 MongoDB\Driver\Query
。这允许你调用 Tequila\MongoDB\Query::getFilter()
方法并检查你是否正在执行预期的查询。这可以使你的代码更可测试和稳定。
你的代码变得更加灵活
这个库是以高级代码为前提编写的。目前,每个应用程序都需要有能力来分析发送到数据库服务器的请求。并且,分析工具的主要目标之一是在尽可能低的级别拦截对数据库的请求。假设你正在使用官方的 MongoDB PHP Library。要分析请求,你可以扩展 MongoDB\Collection
类,并像这样装饰对其 MongoDB\Driver\Manager
实例的调用
<?php namespace MyApplication; use MongoDB\Collection; class ProfilerAwareCollection extends Collection { private $profiler; public function setProfiler(Profiler $profiler) { $this->profiler = $profiler; } public function findOneAndUpdate($filter, $update, array $options = []) { $profilerEntry = [ 'command' => 'findOneAndUpdate', 'filter' => $filter, 'update' => $update, 'options' => $options, ]; $response = parent::findOneAndUpdate($filter, $update, $options); $profilerEntry['response'] = $response; $this->profiler->addEntry($profilerEntry); return $response; } }
看起来不错,但问题是,与分析器条目一起保存的 $options
数组并不是实际发送到 MongoDB 服务器的选项。这是因为 FindOneAndReplace
命令将其输入选项转换为 FindAndModify
命令可以接受的格式,而 FindAndModify
命令又将其输入选项转换为 MongoDB 服务器可以接受的格式。结果——你的分析器将仅保存命令的输入选项,而你将不知道实际发送到 MongoDB 服务器的请求是什么。
当然,你可以装饰每个单独的命令或编写自己的命令。但如果你需要自己编写一切,使用这个库就没有意义了。这太困难了,并且会导致错误:如果你更改分析器,你必须修复每个命令中的使用。因此,最好的解决方案是能够在请求发送到数据库之前添加你的逻辑。通过在你的方法中接受 Tequila\MongoDB\Manager
,你可以非常容易地实现这个目标:只需扩展 Tequila\MongoDB\Manager
类并装饰它的一到三个主要方法以拦截数据库请求
<?php namespace MyApplication; use MongoDB\Driver\ReadPreference; use Tequila\MongoDB\Manager; use Tequila\MongoDB\CommandInterface; class ProfilerAwareManager extends Manager { private $profiler; public function setProfiler(Profiler $profiler) { $this->profiler = $profiler; } public function executeCommand($databaseName, CommandInterface $command, ReadPreference $readPreference) { $server = $this->selectServer($readPreference); $profilerEntry = $command->getOptions($server); $response = parent::executeCommand($databaseName, $command, $readPreference); $profilerEntry['response'] = $response; $this->profiler->addEntry($profilerEntry); return $response; } }
这个库是 MIT 许可的。如果你认为这个库可以针对你的需求进行改进,请创建一个问题。我们非常欢迎贡献。