b2pweb/bdf-prime-mongodb

Bdf prime MongoDB 组件

v2.0.3 2023-10-16 13:50 UTC

This package is auto-updated.

Last update: 2024-09-06 11:54:00 UTC


README

build codecov Packagist Version Total Downloads Type Coverage

MongoDB 驱动程序,用于 Prime

安装

使用 composer 安装

composer require b2pweb/bdf-prime-mongodb

创建连接

<?php
use Bdf\Prime\ConnectionManager;
use Bdf\Prime\MongoDB\Collection\MongoCollectionLocator;
use Bdf\Prime\MongoDB\Mongo;

// declare your connexion manager
$connections = new ConnectionManager();

// Declare connection without username and password
$connections->declareConnection('mongo', 'mongodb://127.0.0.1/my_collection?noAuth=true');
// With credentials
$connections->declareConnection('mongo', 'mongodb://user:password@127.0.0.1/my_database');

// Get the connection locator
$locator = new MongoCollectionLocator($connections);
Mongo::configure($locator); // Configure active record system

使用方法

声明文档

通过扩展 Bdf\Prime\MongoDB\Document\MongoDocument 声明基础文档类。此类声明了 _id 字段。

您可以使用类型属性来生成自动的类型映射。在从 mongo 检索时,未定义的字段将不会被转换。

注意:在字段缺失的情况下,建议将所有字段声明为可空的。

<?php

use Bdf\Prime\MongoDB\Document\MongoDocument;
use \MongoDB\BSON\Binary;

class MyDocument extends MongoDocument
{
    public ?string $name;
    public ?DateTimeInterface $creationDate;
    public ?Binary $data;
}

声明映射器

对于基本使用,只需通过扩展 Bdf\Prime\MongoDB\Document\DocumentMapper 并实现 connection()collection() 方法来声明一个映射器。

<?php

use Bdf\Prime\MongoDB\Document\DocumentMapper;

class MyDocumentMapper extends DocumentMapper
{
    /**
     * {@inheritdoc}
     */
    public function connection(): string
    {
        // The declared connection name 
        return 'mongo';
    }

    /**
     * {@inheritdoc}
     */
    public function collection(): string
    {
        return 'my_collection'; // The storage collection name
    }
}

映射和字段将从文档类自动解析。

查询 MongoDB

查询系统使用 Prime 接口,因此使用方法几乎相同。

<?php
// Get the query
/** @var \Bdf\Prime\MongoDB\Query\MongoQuery $query */
$query = MyDocument::query();

$query
    ->where('name', 'John') // Simple where works as expected
    ->where('value.attr', ':like', 'P%') // "like" operator is converted to a regex
    ->where('value.foo', '$type', 'javascript') // Use mongodb operator
;

// Get all documents which match with filters
$query->all();

// First returns the first matching document or null
$query->first();

测试

使用 Bdf\Prime\MongoDB\Test\MongoTester 创建测试数据。

<?php

use PHPUnit\Framework\TestCase;
use Bdf\Prime\MongoDB\Test\MongoTester;

class MyTest extends TestCase
{
    private MongoTester $tester;

    protected function setUp() : void
    {
        $this->tester = new MongoTester();
        $this->tester
            // Declare given collections. Collections are automatically declared when `push()` on new collection
            ->declare(FooDocument::class, BarDocument::class)
            // Push to mongo given documents with a key for retrieve the value on test
            ->push([
                'doc1' => new MyDocument(),
                'doc2' => new MyDocument(),
            ])
        ;
    }
    
    protected function tearDown() : void
    {
        $this->tester->destroy(); // Drop all declared collections
    }
    
    public function my_test()
    {
        $doc1 = $this->tester->get('doc1'); // get document declared on setUp method
        $this->tester->push($newDoc = new FooDocument()); // Push a single document without a key (cannot be retrieved with `get()`)
        
        // ...
        
        $this->assertNotEquals($doc1, $this->tester->refresh($doc1)); // Retrieve the DB version of the given document
        $this->assertNull($newDoc, $this->tester->refresh($newDoc)); // refresh can be used to check if the document exists on DB
    }
    
    public function with_array_access_test()
    {
        // Array access syntax can also be used instead of "classic" method calls
        $doc1 = $this->tester['doc1']; // get document declared on setUp method
        $this->tester[] = $newDoc = new FooDocument(); // Push a single document without a key (cannot be retrieved with `get()`)
        $this->tester['doc3'] = new MyDocument(); // Push a single document with a key

        // ...

        $this->assertNotEquals($doc1, $this->tester[$doc1]); // Retrieve the DB version of the given document
        $this->assertTrue(isset($this->tester[$newDoc])); // Check if the document exists on DB
        
        unset($this->tester['doc3']); // Deleted a declared document
        unset($this->tester[$newDoc]); // Can also be used to delete a document without key

        $this->assertFalse(isset($this->tester[$newDoc])); // Document is now deleted
    }
}

不区分大小写的搜索和索引

要默认启用不区分大小写的搜索,您可以在表选项中添加默认排序规则。请参阅 不区分大小写的索引

<?php

use Bdf\Prime\MongoDB\Document\DocumentMapper;

class MyDocumentMapper extends DocumentMapper
{
    /**
     * {@inheritdoc}
     */
    public function connection(): string
    {
        // The declared connection name 
        return 'mongo';
    }

    /**
     * {@inheritdoc}
     */
    public function collection(): string
    {
        return 'my_collection'; // The storage collection name
    }
    
    /**
     * {@inheritdoc}
     */
    protected function buildDefinition(\Bdf\Prime\MongoDB\Schema\CollectionDefinitionBuilder $builder) : void
    {
        $builder->collation(['locale' => 'en', 'strength' => 2]);
    }
}

多个文档类

Mongo 是无模式的,因此一个集合可以存储不同格式的文档。您可以通过使用自定义的 Bdf\Prime\MongoDB\Document\Selector\DocumentSelectorInterface 来选择与 DB 字段相对应的文档类,该接口通过 DocumentMapper::createDocumentSelector() 声明。

<?php

// Declare document classes. Note: all documents classes must inherit from a base class 
class BaseDocument extends MongoDocument
{
    public ?string $_type = null; // _type is the default field used by DiscriminatorFieldDocumentSelector
}

class FooDocument extends BaseDocument
{
    public ?string $_type = 'foo';
    public ?string $foo = null;
}

class BarDocument extends BaseDocument
{
    public ?string $_type = 'bar';
    public ?string $bar = null;
}

// Declare a single mapper
class MyDocumentMapper extends DocumentMapper
{
    /**
     * {@inheritdoc}
     */
    public function connection(): string
    { 
        return 'mongo';
    }

    /**
     * {@inheritdoc}
     */
    public function collection(): string
    {
        return 'my_collection';
    }
    
    /**
     * {@inheritdoc}
     */
    protected function createDocumentSelector(string $documentBaseClass): DocumentSelectorInterface
    {
        // Define document class mapping
        return new DiscriminatorFieldDocumentSelector($documentBaseClass, [
            'foo' => FooDocument::class,
            'bar' => BarDocument::class,
        ]);
        
        // If you can't introduce a field for perform discrimination, you can check fields existence :
        return new DiscriminatorFieldDocumentSelector($documentBaseClass, [
            FooDocument::class => ['foo'],
            BarDocument::class => ['bar'],
        ]);
    }
}

// Get the base collection : it handles all document types
$collection = BaseDocument::collection();

$collection->add(new BaseDocument(...));
$collection->add(new FooDocument(...));
$collection->add(new BarDocument(...));

$collection->all(); // Return all documents from all types

// Handle only "FooDocument" document class
$fooCollection = FooDocument::collection();
$fooCollection->all(); // Return only document of type "foo"