composer require bowlofsoup/couchbase-access-layer
A simple layer on top of the PHP Couchbase SDK. Basically you get a bucket repository class which acts as a layer between your code and Couchbase.
The repository helps you to:
- Quickly setup a Couchbase connection.
- A handy to use BucketRepository to quickly query a single bucket.
- Create queries with a so called 'query builder', this helps you build maintainable and easy to read N1ql queries.
- Processes the differences in result syntax you can get back from Couchbase into a consistent query result.
- See below for more examples!
Important: When building a query, always try to use parameters.
Incorrect:
$queryBuilder
->where('data.creationDate >= ' . $creationDate);
Correct:
$queryBuilder
->where('data.creationDate >= $creationDate')
->setParameter('creationDate', '2019-01-10');
This will prevent injection.
SELECT
with optionalDISTINCT
andRAW
FROM
with optional alias, subquery also implemented (= mandatory alias)USE
which means:USE KEYS
andUSE INDEX
WHERE
GROUP BY
ORDER BY
LIMIT
OFFSET
Documentation for clauses can be found On the Couchbase site.
<?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.
}
}
}
For a WHERE
clause you can put in logic yourself:
$queryBuilder->where('CONTAINS(SUBSTR(name,0,1),"C")');
For a GROUP BY
clause you can put in logic yourself too:
$queryBuilder->groupBy('city LETTING MinimumThingsToSee = 400 HAVING COUNT(DISTINCT name) > MinimumThingsToSee');
When using a sub select in a FROM
statement with $queryBuilder->fromSubQuery()
and you're using parameters,
put the parameters in the 'master' query builder. More info on this page.
$queryBuilderForSubSelect = new QueryBuilder('bucket_name');
$queryBuilderForSubSelect->where('type = $foo');
$queryBuilder = new QueryBuilder('bucket_name');
$queryBuilder
->select('q1.someFieldOfTheSubSelect')
->fromSubQuery($queryBuilderForSubSelect, 'q1')
->setParameter('foo', 'value1');
In a previous version, the tests used a dummy couchbase instance called CouchbaseMock.jar. This is not compatible with recent Couchbase versions. Therefore, the current situation has a Docker setup with an actual Couchbase instance for the tests. Assuming you have Docker installed, you can run the tests by running the following commands:
docker compose up -d
docker exec -ti couchbase-access-layer-php-1 bash
vendor/bin/phpunit