MongoDB

目前,MongoDB 并没有提供协程版本的 php 客户端,只有同步阻塞版本。

EasySwoole 的协程版客户端已经在排期内。

在实际生产中,直接创建原生的 MongoDB客户端 来进行数据交互,也不是不可。

若希望将同步调用转为协程调用,可以用 Easyswoole 提供的 sync-invoker 组件。

MongoDB客户端 的同步调用转为协程调用具体使用如下:

定义驱动

<?php

namespace App\MongoDb;

use EasySwoole\EasySwoole\Trigger;
use EasySwoole\SyncInvoker\AbstractDriver;
use MongoDB\Client;

class Driver extends AbstractDriver
{
    private $db;

    // 【建议使用】
    // 使用 mongodb/mongodb composer组件包封装的 MongoDB 客户端调用类,作为客户端调用驱动
    // 【前提:需要先使用 `composer require mongodb/mongodb` 安装 mongodb/mongodb composer组件包】
    function getDb(): Client
    {
        if ($this->db == null) {
            // 这里为要连接的 mongodb 的服务端地址【前提是必须先有服务端,且安装 php-mongodb 扩展才可使用】
            $mongoUrl = "mongodb://127.0.0.1:27017";
            $this->db = new Client($mongoUrl);
        }
        return $this->db;
    }

    // 仅使用 php-mongodb 扩展内置类(不使用composer组件包的),作为客户端调用驱动
    /*
    function getDb(): \MongoDB\Driver\Manager
    {
        if ($this->db == null) {
            // 这里为要连接的 mongodb 的服务端地址【前提是必须先有服务端,且安装 php-mongodb 扩展才可使用】
            $mongoUrl = "mongodb://127.0.0.1:27017";
            $this->db = new \MongoDB\Driver\Manager($mongoUrl);

        }
        return $this->db;
    }
    */

    protected function onException(\Throwable $throwable)
    {
        Trigger::getInstance()->throwable($throwable);
        return null;
    }
}

客户端调用类定义

<?php

namespace App\MongoDb;

use EasySwoole\Component\Singleton;
use EasySwoole\SyncInvoker\SyncInvoker;

class MongoClient extends SyncInvoker
{
    use Singleton;
}

注册 Invoker 服务

EasySwoole 全局事件mainServerCreate 事件 中进行服务注册

<?php

namespace EasySwoole\EasySwoole;

use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Swoole\EventRegister;

class EasySwooleEvent implements Event
{
    public static function initialize()
    {
        // TODO: Implement initialize() method.
        date_default_timezone_set('Asia/Shanghai');
    }

    public static function mainServerCreate(EventRegister $register)
    {
        // 配置 Invoker
        $invokerConfig = \App\MongoDb\MongoClient::getInstance()->getConfig();
        $invokerConfig->setDriver(new \App\MongoDb\Driver()); // 配置 MongoDB 客户端协程调用驱动

        // 以下这些配置都是可选的,可以使用组件默认的配置
        /*
        $invokerConfig->setMaxPackageSize(2 * 1024 * 1024); // 设置最大允许发送数据大小,默认为 2M【注意:当使用 MongoDB 客户端查询大于 2M 的数据时,可以修改此参数】
        $invokerConfig->setTimeout(3.0); // 设置 MongoDB 客户端操作超时时间,默认为 3.0 秒;
        */

        // 注册 Invoker
        \App\MongoDb\MongoClient::getInstance()->attachServer(ServerManager::getInstance()->getSwooleServer());
    }
}

在框架中使用 MongoDB 客户端(协程调用)

<?php

namespace App\HttpController;

use App\MongoDb\Driver;
use App\MongoDb\MongoClient;
use EasySwoole\Http\AbstractInterface\Controller;
use EasySwoole\Utility\Random;

class Index extends Controller
{
    public function index()
    {
        // 使用 mongodb/mongodb composer组件包【建议使用,需要先使用composer安装】
        $ret = MongoClient::getInstance()->invoke()->callback(function (Driver $driver) {
            $ret = $driver->getDb()->user->list->insertOne([
                'name' => Random::character(8),
                'sex' => 'man',
            ]);
            if (!$ret) {
                $driver->response(false);
            }
            $driver->response($ret->getInsertedId());
        });
        var_dump($ret);

        $ret = MongoClient::getInstance()->invoke()->callback(function (Driver $driver) {
            $ret = [];
            $collections = $driver->getDb()->user->listCollections();
            foreach ($collections as $collection) {
                $ret[] = (array)$collection;
            }
            $driver->response($ret);
        });
        var_dump($ret);
        /**
         * 输出结果:
         * object(MongoDB\BSON\ObjectId)#109 (1) {
             ["oid"]=>
             string(24) "600da377004c82305a02fb52"
           }
         * array(1) {
             [0]=>
             array(1) {
               ["MongoDB\Model\CollectionInfoinfo"]=>
               array(5) {
                 ["name"]=>
                 string(4) "list"
                 ["type"]=>
                 string(10) "collection"
                 ["options"]=>
                 array(0) {
                 }
                 ["info"]=>
                 array(2) {
                   ["readOnly"]=>
                   bool(false)
                   ["uuid"]=>
                   object(MongoDB\BSON\Binary)#110 (2) {
                     ["data"]=>
                     string(16) "EasySwoole"
                     ["type"]=>
                     int(4)
                   }
                 }
                 ["idIndex"]=>
                 array(4) {
                   ["v"]=>
                   int(2)
                   ["key"]=>
                   array(1) {
                     ["_id"]=>
                     int(1)
                   }
                   ["name"]=>
                   string(4) "_id_"
                   ["ns"]=>
                   string(9) "user.list"
                 }
               }
             }
           } 
        */

        // 使用 php-mongodb 扩展时(不使用 mongodb/mongodb composer组件包)
        /*
        // 插入数据
        $rets = MongoClient::getInstance()->invoke()->callback(function (Driver $driver) {
            $bulk = new \MongoDB\Driver\BulkWrite();

            $bulk->insert([
                'name' => Random::character(8),
                'sex' => 'man',
            ]);

            $bulk->insert(['_id' => 1, 'x' => 1]);
            $bulk->insert(['_id' => 2, 'x' => 2]);

            $bulk->update(['x' => 2], ['$set' => ['x' => 1]], ['multi' => false, 'upsert' => false]);
            $bulk->update(['x' => 3], ['$set' => ['x' => 3]], ['multi' => false, 'upsert' => true]);
            $bulk->update(['_id' => 3], ['$set' => ['x' => 3]], ['multi' => false, 'upsert' => true]);

            $bulk->insert(['_id' => 4, 'x' => 2]);

            $bulk->delete(['x' => 1], ['limit' => 1]);

            $manager = $driver->getDb();
            $writeConcern = new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 100);
            // 查到 user 库的 list 集合中
            $ret = $manager->executeBulkWrite('user.list', $bulk, $writeConcern);

            printf("Inserted %d document(s)\n", $ret->getInsertedCount()); // 插入条数
            printf("Matched  %d document(s)\n", $ret->getMatchedCount()); // 匹配条数
            printf("Updated  %d document(s)\n", $ret->getModifiedCount()); // 修改条数
            printf("Upserted %d document(s)\n", $ret->getUpsertedCount()); // 修改插入条数
            printf("Deleted  %d document(s)\n", $ret->getDeletedCount()); // 删除条数

            foreach ($ret->getUpsertedIds() as $index => $id) {
                printf('upsertedId[%d]: ', $index);
                var_dump($id);
            }

            if (!$ret) {
                return false;
            }

            return true;
        });

        // 查询数据
        $rets = MongoClient::getInstance()->invoke()->callback(function (Driver $driver) {
            $filter = ['x' => ['$gt' => 1]];
            $options = [
                'projection' => ['_id' => 0],
                'sort' => ['x' => -1],
            ];

// 查询数据
            $query = new \MongoDB\Driver\Query($filter, $options);
            $cursor = $driver->getDb()->executeQuery('user.list', $query);
            foreach ($cursor as $document) {
                print_r($document);
            }
        });
        */

    }
}