bowlofsoup/couchbase-access-layer

简单的 Couchbase 查询构建器。

v2.0.1 2024-07-09 13:46 UTC

This package is auto-updated.

Last update: 2024-09-09 14:09:12 UTC


README

Minimum PHP Version Build Status Coverage Status

安装

composer require bowlofsoup/couchbase-access-layer

Couchbase Access Layer

在 PHP Couchbase SDK 之上提供了一个简单的层。基本上,你得到一个 bucket 仓库类,它充当你的代码和 Couchbase 之间的层。

仓库可以帮助你

  • 快速设置 Couchbase 连接。
  • 一个方便使用的 BucketRepository,可以快速查询一个 单个 bucket。
  • 使用所谓的 '查询构建器' 创建查询,这有助于你构建可维护且易于阅读的 N1ql 查询。
  • 处理从 Couchbase 返回的查询语法差异,将其转换为一致的查询结果。
  • 下面有更多示例!

使用

请使用参数

重要:在构建查询时,始终尝试使用参数。

错误

$queryBuilder
    ->where('data.creationDate >= ' . $creationDate);

正确

$queryBuilder
    ->where('data.creationDate >= $creationDate')
    ->setParameter('creationDate', '2019-01-10');

这将防止注入。

查询构建器支持以下 N1QL 子句

  • SELECT 可选 DISTINCTRAW
  • FROM 可选别名,子查询也实现了(=强制别名)
  • USE 表示:USE KEYSUSE INDEX
  • WHERE
  • GROUP BY
  • ORDER BY
  • LIMIT
  • OFFSET

子句的文档可以在Couchbase 网站上找到

示例

<?php

declare(strict_types=1);

namespace Some\Name\Space;

use BowlOfSoup\CouchbaseAccessLayer\Exception\CouchbaseQueryException;
use BowlOfSoup\CouchbaseAccessLayer\Factory\ClusterFactory;
use BowlOfSoup\CouchbaseAccessLayer\Model\Result;
use BowlOfSoup\CouchbaseAccessLayer\Repository\BucketRepository;

class Foo
{
    public function exampleUsingTheQueryBuilder()
    {
        $result = $this->querySomeBucket();

        foreach ($result as $item) {
            // each $item contains a Couchbase document which matched the query.
        }

        // $result implements the \JsonSerializableInterface.
        $jsonEncoded = json_encode($result);

        // These (can) only differ when query with limit/offset is done.
        $resultCount = $result->getCount();
        $resultTotalCount = $result->getTotalCount();

        // Return just the data you queried
        $justTheData = $result->get();

        // Get only one (or the first) result
        $singleResult = $result->getFirstResult();
    }

    public function exampleUsingDirectCalls()
    {
        $clusterFactory = new ClusterFactory('couchbaseHost', 'couchbaseUsername', 'couchbasePassword');
        $bucketRepository = new BucketRepository('someBucketName', $clusterFactory);

        $bucketRepository->upsert('some document id', 'the content of the document');

        $bucketRepository->remove('some document id);

        $documentContent = $bucketRepository->getByKey('some document id');
    }

    public function exampleExecutingManualQuery()
    {
        $clusterFactory = new ClusterFactory('couchbaseHost', 'couchbaseUsername', 'couchbasePassword');
        $bucketRepository = new BucketRepository('someBucketName', $clusterFactory);

        // Creating an index for a bucket
        $bucketRepository->executeQuery(
            CREATE INDEX i_foo_field_name
            ON `' . $bucketRepository->getBucketName() . '`(`field`, `data.name`)
            WHERE (`documentType` = "foo")
        );

        $result = $bucketRepository->executeQuery(
            'SELECT someField FROM `bucket name` WHERE someOtherField = $someOtherField',
            ['someOtherField' => 'some value']
        );

        // This will only return one result.
        $result = $bucketRepository->executeQueryWithOneResult();
    }

    /**
     * @return \BowlOfSoup\CouchbaseAccessLayer\Model\Result
     */
    private function querySomeBucket(): Result
    {
        $clusterFactory = new ClusterFactory('couchbaseHost', 'couchbaseUsername', 'couchbasePassword');
        $bucketRepository = new BucketRepository('someBucketName', $clusterFactory);

        $queryBuilder = $bucketRepository->createQueryBuilder();

        $queryBuilder
            ->select('data.name')
            // See that you can put in your own logic, like COUNT and such:
            ->select('COUNT(data.name) AS count')
            ->where('foo = $foo')
            ->where('someField = $someField')
            ->where('type = $type');

        $queryBuilder->setParameters([
            'foo' => 'someFooValue',
            'someKey' => 'someKeyValue',
            'type' => 'someDocumentType',
        ]);

        $queryBuilder
            ->where('data.creationDate >= $creationDate')
            ->setParameter('creationDate', '2019-01-10');

        $queryBuilder
            ->groupBy('data.name')
            ->limit(10)
            ->offset(20);

        try {
            return $bucketRepository->getResult($queryBuilder);
        } catch (CouchbaseQueryException $e) {
            // Something went wrong.
        }
    }
}

对于 WHERE 子句,你可以自己添加逻辑

$queryBuilder->where('CONTAINS(SUBSTR(name,0,1),"C")');

对于 GROUP BY 子句,你也可以自己添加逻辑

$queryBuilder->groupBy('city LETTING MinimumThingsToSee = 400 HAVING COUNT(DISTINCT name) > MinimumThingsToSee');

在 FROM 语句中使用子查询

当在 FROM 语句中使用子查询(使用 $queryBuilder->fromSubQuery())并使用参数时,请将参数放在 'master' 查询构建器中。更多信息可以在此页上找到。

$queryBuilderForSubSelect = new QueryBuilder('bucket_name');
$queryBuilderForSubSelect->where('type = $foo');

$queryBuilder = new QueryBuilder('bucket_name');

$queryBuilder
    ->select('q1.someFieldOfTheSubSelect')
    ->fromSubQuery($queryBuilderForSubSelect, 'q1')
    ->setParameter('foo', 'value1');

单元测试

在之前的版本中,测试使用了名为 CouchbaseMock.jar 的虚拟 Couchbase 实例。这与最新的 Couchbase 版本不兼容。因此,当前情况有一个 Docker 设置,包含实际的 Couchbase 实例用于测试。假设你已经安装了 Docker,你可以通过运行以下命令来运行测试

  • docker compose up -d
  • docker exec -ti couchbase-access-layer-php-1 bash
  • vendor/bin/phpunit