diff --git a/composer.json b/composer.json
index c1c4d86..2787916 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,7 @@
{
"name": "ostico/phporient",
"description": "Good enough PHP binary client for OrientDB.",
- "version": "v1.1.7",
+ "version": "v1.1.8",
"keywords": [
"orientdb",
"orient db",
diff --git a/src/PhpOrient/Configuration/Constants.php b/src/PhpOrient/Configuration/Constants.php
index 7b8fd66..9758c99 100644
--- a/src/PhpOrient/Configuration/Constants.php
+++ b/src/PhpOrient/Configuration/Constants.php
@@ -17,7 +17,7 @@ class Constants {
const VERSION = "v1.1.7";
const ID = "1";
const NAME = "PhpOrient - PHP binary client for OrientDB";
- const SUPPORTED_PROTOCOL = 28;
+ const SUPPORTED_PROTOCOL = 29;
public static $LOGGING = false;
public static $LOG_FILE_PATH = false;
diff --git a/src/PhpOrient/Protocols/Binary/Data/Bag.php b/src/PhpOrient/Protocols/Binary/Data/Bag.php
index b1947f9..50ccbfc 100644
--- a/src/PhpOrient/Protocols/Binary/Data/Bag.php
+++ b/src/PhpOrient/Protocols/Binary/Data/Bag.php
@@ -11,7 +11,7 @@
*
* @package OrientDB\Records
*/
-class Bag implements \Countable, \ArrayAccess, \Iterator {
+class Bag implements \Countable, \ArrayAccess, \Iterator, \JsonSerializable {
const EMBEDDED = 0;
const TREE = 1;
@@ -19,12 +19,12 @@ class Bag implements \Countable, \ArrayAccess, \Iterator {
/**
* @var string The base64 encoded representation of the bag.
*/
- protected $serialized;
+ protected $base64Content;
/**
* @var string The base64 decoded stream of bytes.
*/
- protected $deserialized;
+ protected $binaryContent;
/**
* @var int The bag type, either embedded or tree.
@@ -84,10 +84,10 @@ class Bag implements \Countable, \ArrayAccess, \Iterator {
/**
* # RIDBag Constructor
*
- * @param string $serialized the base64 encoded bag
+ * @param string $base64Content the base64 encoded bag
*/
- public function __construct( $serialized ) {
- $this->serialized = $serialized;
+ public function __construct( $base64Content ) {
+ $this->base64Content = $base64Content;
}
/**
@@ -114,12 +114,52 @@ public function getSize() {
return $this->size;
}
+ /**
+ * Get the list of contained RIDs
+ * @return array
+ */
+ public function getRids(){
+ if( empty( $this->items ) ){
+ foreach ( $this as $idx => $rid ){
+ //NOP
+ //Call this cycle to decode the bag
+ }
+ }
+ return $this->items;
+ }
+
+ /**
+ * Get the original raw content for the Bag
+ *
+ * @return string
+ */
+ public function getRawBagContent(){
+ return "%" . $this->base64Content . ";";
+ }
+
+ /**
+ * (PHP 5 >= 5.4.0)
+ * Specify data which should be serialized to JSON
+ * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
+ * @return mixed data which can be serialized by json_encode,
+ * which is a value of any type other than a resource.
+ */
+ public function jsonSerialize(){
+ return $this->getRids();
+ }
+
/**
* Parse the bag header.
*/
protected function parse() {
- $this->deserialized = base64_decode( $this->serialized );
- $mode = ord( $this->deserialized[ 0 ] );
+
+ if( !empty( $this->binaryContent ) ){
+ //Already parsed
+ return;
+ }
+
+ $this->binaryContent = base64_decode( $this->base64Content );
+ $mode = ord( $this->binaryContent[ 0 ] );
if ( ( $mode & 1 ) === 1 ) {
$this->type = self::EMBEDDED;
@@ -128,7 +168,7 @@ protected function parse() {
}
if ( ( $mode & 2 ) === 2 ) {
- $this->uuid = substr( $this->deserialized, 1, 16 );
+ $this->uuid = substr( $this->binaryContent, 1, 16 );
$this->ReaderOffset = 17;
} else {
$this->ReaderOffset = 1;
@@ -145,7 +185,7 @@ protected function parse() {
* Parse the header for an embedded bag.
*/
protected function parseEmbedded() {
- $this->size = Reader::unpackInt( substr( $this->deserialized, $this->ReaderOffset, 4 ) );
+ $this->size = Reader::unpackInt( substr( $this->binaryContent, $this->ReaderOffset, 4 ) );
$this->ReaderOffset += 4;
$this->baseOffset = $this->ReaderOffset;
}
@@ -154,19 +194,19 @@ protected function parseEmbedded() {
* Parse the header for a tree bag.
*/
protected function parseTree() {
- $this->fileId = Reader::unpackLong( substr( $this->deserialized, $this->ReaderOffset, 8 ) );
+ $this->fileId = Reader::unpackLong( substr( $this->binaryContent, $this->ReaderOffset, 8 ) );
$this->ReaderOffset += 8;
- $this->pageIndex = Reader::unpackLong( substr( $this->deserialized, $this->ReaderOffset, 8 ) );
+ $this->pageIndex = Reader::unpackLong( substr( $this->binaryContent, $this->ReaderOffset, 8 ) );
$this->ReaderOffset += 8;
- $this->pageOffset = Reader::unpackInt( substr( $this->deserialized, $this->ReaderOffset, 4 ) );
+ $this->pageOffset = Reader::unpackInt( substr( $this->binaryContent, $this->ReaderOffset, 4 ) );
$this->ReaderOffset += 4;
- $this->size = Reader::unpackInt( substr( $this->deserialized, $this->ReaderOffset, 4 ) );
+ $this->size = Reader::unpackInt( substr( $this->binaryContent, $this->ReaderOffset, 4 ) );
$this->ReaderOffset += 4;
- $this->changeSize = Reader::unpackInt( substr( $this->deserialized, $this->ReaderOffset, 4 ) );
+ $this->changeSize = Reader::unpackInt( substr( $this->binaryContent, $this->ReaderOffset, 4 ) );
$this->ReaderOffset += 4;
}
@@ -259,14 +299,14 @@ public function offsetGet( $offset ) {
if ( $this->type === self::EMBEDDED ) {
$start = $this->baseOffset + ( $offset * 10 );
- $chunk = substr( $this->deserialized, $start, 2 );
+ $chunk = substr( $this->binaryContent, $start, 2 );
if( $chunk === false ){
$this->items[ $offset ] = false;
return $this->items[ $offset ];
}
- $cluster = Reader::unpackShort( substr( $this->deserialized, $start, 2 ) );
- $position = Reader::unpackLong( substr( $this->deserialized, $start + 2, 8 ) );
+ $cluster = Reader::unpackShort( substr( $this->binaryContent, $start, 2 ) );
+ $position = Reader::unpackLong( substr( $this->binaryContent, $start + 2, 8 ) );
$this->items[ $offset ] = new ID( $cluster, $position );
} else {
$this->items[ $offset ] = false;
diff --git a/src/PhpOrient/Protocols/Binary/Operations/DbOpen.php b/src/PhpOrient/Protocols/Binary/Operations/DbOpen.php
index 7ce21f0..055ecab 100644
--- a/src/PhpOrient/Protocols/Binary/Operations/DbOpen.php
+++ b/src/PhpOrient/Protocols/Binary/Operations/DbOpen.php
@@ -139,7 +139,6 @@ protected function _read() {
}
- //TODO: Try with a cluster instance
# cluster config string ( -1 )
# cluster release
$cluster_list = [
diff --git a/src/PhpOrient/Protocols/Binary/Serialization/CSV.php b/src/PhpOrient/Protocols/Binary/Serialization/CSV.php
index 0434455..a93d99b 100644
--- a/src/PhpOrient/Protocols/Binary/Serialization/CSV.php
+++ b/src/PhpOrient/Protocols/Binary/Serialization/CSV.php
@@ -2,6 +2,7 @@
namespace PhpOrient\Protocols\Binary\Serialization;
+use PhpOrient\Configuration\Constants;
use PhpOrient\Protocols\Binary\Abstracts\SerializableInterface;
use PhpOrient\Protocols\Binary\Data\Bag;
use PhpOrient\Protocols\Binary\Data\ID;
@@ -514,6 +515,29 @@ public static function serialize( $value, $embedded = false ) {
return $value->getTimestamp() . 't';
} elseif ( $value instanceof ID ) {
return $value->__toString();
+ } elseif ( $value instanceof Bag ){
+ /*
+ * This line works the same, but transforms the edges list to a linkSet
+ * // return self::serializeArray( $value->getRids() );
+ *
+ * From:
+ *
+ * ----+-----+------+------+--------+---------
+ * # |@RID |@CLASS|script|out_ |in_
+ * ----+-----+------+------+--------+---------
+ * 0 |#9:0 |V |true |[size=1]|[size=1]
+ * ----+-----+------+------+--------+---------
+ *
+ * To:
+ *
+ * ----+-----+------+------+--------+---------
+ * # |@RID |@CLASS|script|out_ |in_
+ * ----+-----+------+------+--------+---------
+ * 0 |#9:0 |V |true |[1] |[1]
+ * ----+-----+------+------+--------+---------
+ *
+ */
+ return $value->getRawBagContent();
} else {
return '';
}
diff --git a/src/PhpOrient/Protocols/Binary/SocketTransport.php b/src/PhpOrient/Protocols/Binary/SocketTransport.php
index 6f74fee..89216e6 100644
--- a/src/PhpOrient/Protocols/Binary/SocketTransport.php
+++ b/src/PhpOrient/Protocols/Binary/SocketTransport.php
@@ -279,9 +279,9 @@ public function hexDump( $message ){
if( Constants::$LOGGING ){
$_msg = self::_hexDump( $message );
$rows = explode( "\n", $_msg );
- self::$_logger->debug( "\n" );
+ $this->_logger->debug( "\n" );
foreach( $rows as $row ){
- self::$_logger->debug( $row );
+ $this->_logger->debug( $row );
}
}
}
diff --git a/src/PhpOrient/Protocols/Common/AbstractTransport.php b/src/PhpOrient/Protocols/Common/AbstractTransport.php
index c84cb6b..128d2ff 100644
--- a/src/PhpOrient/Protocols/Common/AbstractTransport.php
+++ b/src/PhpOrient/Protocols/Common/AbstractTransport.php
@@ -38,22 +38,33 @@ abstract class AbstractTransport implements TransportInterface {
/**
* @var LoggerInterface
*/
- protected static $_logger;
+ protected $_logger;
/**
* Class Constructor
+ *
+ * @throws PhpOrientException
*/
public function __construct() {
+ $this->setLogger();
+ }
+
+ /**
+ * Set the client Logger
+ *
+ * @throws PhpOrientException
+ */
+ public function setLogger(){
if ( ClientConstants::$LOGGING ) {
- if ( self::$_logger === null ) {
+ if ( $this->_logger === null ) {
if( !class_exists( '\Monolog\Logger', true ) ){
throw new PhpOrientException( "No development environment installed from composer. Try 'composer update' or remove logging from client constants ( \\PhpOrient\\Configuration\\Constants::\$LOGGING )" );
}
- self::$_logger = new \Monolog\Logger( get_class( $this ) );
+ $this->_logger = new \Monolog\Logger( get_class( $this ) );
$file_path = "php://stdout";
if ( ClientConstants::$LOG_FILE_PATH ) {
@@ -62,18 +73,36 @@ public function __construct() {
$handler = new \Monolog\Handler\StreamHandler( $file_path, \Monolog\Logger::DEBUG );
$handler->setFormatter( new \Monolog\Formatter\LineFormatter( null, null, false, true ) );
- self::$_logger->pushHandler( $handler );
+ $this->_logger->pushHandler( $handler );
}
} else {
- self::$_logger = new NullLogger();
+ $this->_logger = new NullLogger();
}
}
+ /**
+ * Get the Logger from transport
+ *
+ * @return LoggerInterface
+ * @throws PhpOrientException
+ */
+ public function getLogger(){
+ if( empty( $this->_logger ) ) {
+ $this->setLogger();
+ }
+ return $this->_logger;
+ }
+
+ /**
+ * Debug method
+ *
+ * @param $message
+ */
public function debug( $message ){
- self::$_logger->debug( $message );
+ $this->_logger->debug( $message );
}
/**
diff --git a/src/PhpOrient/Protocols/Common/ClusterMap.php b/src/PhpOrient/Protocols/Common/ClusterMap.php
index bae86af..dcc436b 100644
--- a/src/PhpOrient/Protocols/Common/ClusterMap.php
+++ b/src/PhpOrient/Protocols/Common/ClusterMap.php
@@ -59,6 +59,21 @@ class ClusterMap implements ConfigurableInterface, \ArrayAccess, \Countable, \It
*/
protected $release;
+ /**
+ * @var int
+ */
+ protected $majorVersion;
+
+ /**
+ * @var int
+ */
+ protected $minorVersion;
+
+ /**
+ * @var string
+ */
+ protected $buildNumber;
+
/**
* @return int
*/
@@ -66,6 +81,19 @@ public function getServers() {
return $this->servers;
}
+ protected function _parseRelease(){
+ @list(
+ $this->majorVersion,
+ $this->minorVersion,
+ $this->buildNumber
+ ) = @explode( ".", $this->release );
+
+ if ( stripos( $this->minorVersion, "-" ) !== false ){
+ @list( $this->minorVersion, $this->buildNumber ) = explode( "-", $this->minorVersion );
+ }
+ @list( $this->buildNumber, ) = explode( " ", $this->buildNumber );
+ }
+
/**
* @return string
*/
@@ -73,7 +101,26 @@ public function getRelease() {
return $this->release;
}
+ /**
+ * @return int
+ */
+ public function getMajorVersion() {
+ return (int)$this->majorVersion;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMinorVersion() {
+ return (int)$this->minorVersion;
+ }
+ /**
+ * @return string
+ */
+ public function getBuildNumber() {
+ return $this->buildNumber;
+ }
/**
* Expected ClusterMap
@@ -99,6 +146,7 @@ public function getRelease() {
public function configure( Array $options = array() ) {
$this->config( $options );
+ $this->_parseRelease();
if ( !empty( $this->dataClusters ) ) {
$this->reverseMap = array();
$this->reverseIDMap = array();
diff --git a/tests/PhpOrient/RecordCommandsTest.php b/tests/PhpOrient/RecordCommandsTest.php
index 375adda..f429113 100644
--- a/tests/PhpOrient/RecordCommandsTest.php
+++ b/tests/PhpOrient/RecordCommandsTest.php
@@ -8,7 +8,9 @@
namespace PhpOrient;
use PhpOrient\Abstracts\TestCase;
-
+use PhpOrient\Configuration\Constants as ClientConstants;
+use PhpOrient\Protocols\Common\AbstractTransport;
+use PhpOrient\Protocols\Common\Constants;
use PhpOrient\Protocols\Binary\Data\ID;
use PhpOrient\Protocols\Binary\Data\Record;
@@ -305,4 +307,71 @@ public function testHiLevelCreateDelete(){
$this->assertEmpty( $result );
}
+ public function testUpdateEdges(){
+
+// ClientConstants::$LOGGING = true;
+// ClientConstants::$LOG_FILE_PATH = "php://stdout";
+
+ $client = PhpOrient::fromConfig(
+ array(
+ 'username' => 'admin',
+ 'password' => 'admin',
+ 'hostname' => 'localhost',
+ 'port' => 2424
+ )
+ );
+
+ $res = $client->execute('connect');
+
+ try {
+ $client->dbDrop( "db_test_edges", Constants::STORAGE_TYPE_MEMORY );
+ } catch ( \Exception $e ) {
+ echo $e->getMessage();
+ $client->getTransport()->debug( $e->getMessage() );
+ }
+
+ $client->dbCreate( "db_test_edges",
+ Constants::STORAGE_TYPE_MEMORY,
+ Constants::DATABASE_TYPE_GRAPH
+ );
+
+ $orientInfo = $client->dbOpen( "db_test_edges", 'admin', 'admin' );
+
+ $cmd = 'begin;' .
+ 'let a = create vertex set script = true;' .
+ 'let b = select from v limit 1;' .
+ 'let e = create edge from $a to $b;' .
+ 'commit retry 100;';
+
+ $lastRecord = $client->sqlBatch( $cmd );
+ $lastRecord = $client->sqlBatch( $cmd );
+ $lastRecord = $client->sqlBatch( $cmd );
+ $lastRecord = $client->sqlBatch( $cmd );
+ $lastRecord = $client->sqlBatch( $cmd );
+
+ $rec = $client->recordLoad( new ID("#9:0") )[0];
+
+ /**
+ * @var $bag \PhpOrient\Protocols\Binary\Data\Bag
+ */
+ $bag = $rec->getOData()['in_'];
+ $this->assertNotEmpty( $bag->getRawBagContent() );
+ $client->recordUpdate($rec);
+
+ /**
+ * @var $bag2 \PhpOrient\Protocols\Binary\Data\Bag
+ */
+ $rec = $client->recordLoad( new ID("#9:0") )[0];
+ $bag2 = $rec->getOData()['in_'];
+ $this->assertNotEmpty( $bag2->getRawBagContent() );
+
+ if( $orientInfo->getMajorVersion() >= 2
+ && $orientInfo->getMinorVersion() >= 0
+ && ( $orientInfo->getBuildNumber() >= 7 || !is_numeric( $orientInfo->getBuildNumber() ) )
+ ) {
+ $this->assertEquals( $bag->getRawBagContent(), $bag2->getRawBagContent() );
+ }
+
+ }
+
}
\ No newline at end of file