258 lines
7.8 KiB
PHP
258 lines
7.8 KiB
PHP
<?php
|
|
/**
|
|
*
|
|
* This file is part of phpFastCache.
|
|
*
|
|
* @license MIT License (MIT)
|
|
*
|
|
* For full copyright and license information, please see the docs/CREDITS.txt file.
|
|
*
|
|
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> http://www.phpfastcache.com
|
|
* @author Georges.L (Geolim4) <contact@geolim4.com>
|
|
*
|
|
*/
|
|
|
|
namespace phpFastCache\Drivers\Couchdb;
|
|
|
|
use Doctrine\CouchDB\CouchDBClient as CouchdbClient;
|
|
use Doctrine\CouchDB\CouchDBException;
|
|
use phpFastCache\Core\Pool\DriverBaseTrait;
|
|
use phpFastCache\Core\Pool\ExtendedCacheItemPoolInterface;
|
|
use phpFastCache\Entities\DriverStatistic;
|
|
use phpFastCache\Exceptions\phpFastCacheDriverCheckException;
|
|
use phpFastCache\Exceptions\phpFastCacheDriverException;
|
|
use phpFastCache\Exceptions\phpFastCacheInvalidArgumentException;
|
|
use phpFastCache\Exceptions\phpFastCacheLogicException;
|
|
use Psr\Cache\CacheItemInterface;
|
|
|
|
/**
|
|
* Class Driver
|
|
* @package phpFastCache\Drivers
|
|
* @property CouchdbClient $instance Instance of driver service
|
|
*/
|
|
class Driver implements ExtendedCacheItemPoolInterface
|
|
{
|
|
use DriverBaseTrait;
|
|
|
|
/**
|
|
* Driver constructor.
|
|
* @param array $config
|
|
* @throws phpFastCacheDriverException
|
|
*/
|
|
public function __construct(array $config = [])
|
|
{
|
|
$this->setup($config);
|
|
|
|
if (!$this->driverCheck()) {
|
|
throw new phpFastCacheDriverCheckException(sprintf(self::DRIVER_CHECK_FAILURE, $this->getDriverName()));
|
|
} else {
|
|
$this->driverConnect();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function driverCheck()
|
|
{
|
|
return class_exists('Doctrine\CouchDB\CouchDBClient');
|
|
}
|
|
|
|
/**
|
|
* @param \Psr\Cache\CacheItemInterface $item
|
|
* @return mixed
|
|
* @throws phpFastCacheDriverException
|
|
* @throws phpFastCacheInvalidArgumentException
|
|
*/
|
|
protected function driverWrite(CacheItemInterface $item)
|
|
{
|
|
/**
|
|
* Check for Cross-Driver type confusion
|
|
*/
|
|
if ($item instanceof Item) {
|
|
try {
|
|
$this->instance->putDocument(['data' => $this->encode($this->driverPreWrap($item))], $item->getEncodedKey(),
|
|
$this->getLatestDocumentRevision($item->getEncodedKey()));
|
|
} catch (CouchDBException $e) {
|
|
throw new phpFastCacheDriverException('Got error while trying to upsert a document: ' . $e->getMessage(), null, $e);
|
|
}
|
|
return true;
|
|
} else {
|
|
throw new phpFastCacheInvalidArgumentException('Cross-Driver type confusion detected');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param \Psr\Cache\CacheItemInterface $item
|
|
* @return null|array
|
|
* @throws phpFastCacheDriverException
|
|
*/
|
|
protected function driverRead(CacheItemInterface $item)
|
|
{
|
|
try {
|
|
$response = $this->instance->findDocument($item->getEncodedKey());
|
|
} catch (CouchDBException $e) {
|
|
throw new phpFastCacheDriverException('Got error while trying to get a document: ' . $e->getMessage(), null, $e);
|
|
}
|
|
|
|
if ($response->status === 404 || empty($response->body[ 'data' ])) {
|
|
return null;
|
|
} else if ($response->status === 200) {
|
|
return $this->decode($response->body[ 'data' ]);
|
|
} else {
|
|
throw new phpFastCacheDriverException('Got unexpected HTTP status: ' . $response->status);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param \Psr\Cache\CacheItemInterface $item
|
|
* @return bool
|
|
* @throws phpFastCacheDriverException
|
|
* @throws phpFastCacheInvalidArgumentException
|
|
*/
|
|
protected function driverDelete(CacheItemInterface $item)
|
|
{
|
|
/**
|
|
* Check for Cross-Driver type confusion
|
|
*/
|
|
if ($item instanceof Item) {
|
|
try {
|
|
$this->instance->deleteDocument($item->getEncodedKey(), $this->getLatestDocumentRevision($item->getEncodedKey()));
|
|
} catch (CouchDBException $e) {
|
|
throw new phpFastCacheDriverException('Got error while trying to delete a document: ' . $e->getMessage(), null, $e);
|
|
}
|
|
return true;
|
|
} else {
|
|
throw new phpFastCacheInvalidArgumentException('Cross-Driver type confusion detected');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
* @throws phpFastCacheDriverException
|
|
*/
|
|
protected function driverClear()
|
|
{
|
|
try {
|
|
$this->instance->deleteDatabase($this->getDatabaseName());
|
|
$this->createDatabase();
|
|
} catch (CouchDBException $e) {
|
|
throw new phpFastCacheDriverException('Got error while trying to delete and recreate the database: ' . $e->getMessage(), null, $e);
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
* @throws phpFastCacheLogicException
|
|
*/
|
|
protected function driverConnect()
|
|
{
|
|
if ($this->instance instanceof CouchdbClient) {
|
|
throw new phpFastCacheLogicException('Already connected to Couchdb server');
|
|
} else {
|
|
$host = isset($this->config[ 'host' ]) ? $this->config[ 'host' ] : '127.0.0.1';
|
|
$ssl = isset($this->config[ 'ssl' ]) ? $this->config[ 'ssl' ] : false;
|
|
$port = isset($this->config[ 'port' ]) ? $this->config[ 'port' ] : 5984;
|
|
$path = isset($this->config[ 'path' ]) ? $this->config[ 'path' ] : '/';
|
|
$username = isset($this->config[ 'username' ]) ? $this->config[ 'username' ] : '';
|
|
$password = isset($this->config[ 'password' ]) ? $this->config[ 'password' ] : '';
|
|
$timeout = isset($this->config[ 'timeout' ]) ? $this->config[ 'timeout' ] : 10;
|
|
|
|
$url = ($ssl ? 'https://' : 'http://');
|
|
if ($username) {
|
|
$url .= "{$username}";
|
|
if ($password) {
|
|
$url .= ":{$password}";
|
|
}
|
|
$url .= '@';
|
|
}
|
|
$url .= $host;
|
|
$url .= ":{$port}";
|
|
$url .= $path;
|
|
|
|
$this->instance = CouchDBClient::create([
|
|
'dbname' => $this->getDatabaseName(),
|
|
'url' => $url,
|
|
'timeout' => $timeout,
|
|
]);
|
|
|
|
$this->createDatabase();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @return string|null
|
|
*/
|
|
protected function getLatestDocumentRevision($docId)
|
|
{
|
|
$path = '/' . $this->getDatabaseName() . '/' . urlencode($docId);
|
|
|
|
$response = $this->instance->getHttpClient()->request(
|
|
'HEAD',
|
|
$path,
|
|
null,
|
|
false
|
|
);
|
|
if (!empty($response->headers[ 'etag' ])) {
|
|
return trim($response->headers[ 'etag' ], " '\"\t\n\r\0\x0B");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function getDatabaseName()
|
|
{
|
|
return isset($this->config[ 'database' ]) ? $this->config[ 'database' ] : 'phpfastcache';
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
protected function createDatabase()
|
|
{
|
|
if (!in_array($this->instance->getDatabase(), $this->instance->getAllDatabases(), true)) {
|
|
$this->instance->createDatabase($this->instance->getDatabase());
|
|
}
|
|
}
|
|
|
|
/********************
|
|
*
|
|
* PSR-6 Extended Methods
|
|
*
|
|
*******************/
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getHelp()
|
|
{
|
|
return <<<HELP
|
|
<p>
|
|
To install the Couchdb HTTP client library via Composer:
|
|
<code>composer require "doctrine/couchdb" "@dev"</code>
|
|
</p>
|
|
HELP;
|
|
}
|
|
|
|
/**
|
|
* @return DriverStatistic
|
|
*/
|
|
public function getStats()
|
|
{
|
|
$info = $this->instance->getDatabaseInfo();
|
|
|
|
return (new DriverStatistic())
|
|
->setSize($info[ 'sizes' ][ 'active' ])
|
|
->setRawData($info)
|
|
->setData(implode(', ', array_keys($this->itemInstances)))
|
|
->setInfo('Couchdb version ' . $this->instance->getVersion() . "\n For more information see RawData.");
|
|
}
|
|
} |