diff --git a/lib/ArangoDBClient/Batch.php b/lib/ArangoDBClient/Batch.php index 957f5076..3e77e01e 100644 --- a/lib/ArangoDBClient/Batch.php +++ b/lib/ArangoDBClient/Batch.php @@ -361,7 +361,10 @@ public function append($method, $request) $result .= '{"error":false,"_id":"0/0","id":"0","_rev":0,"hasMore":1, "result":[{}], "documents":[{}]}' . $eol . $eol; $response = new HttpResponse($result); - $batchPart = new BatchPart($this, $batchPartId, $type, $request, $response, ['cursorOptions' => $this->_batchPartCursorOptions]); + $batchPart = new BatchPart($this, $batchPartId, $type, $request, $response, [ + 'cursorOptions' => $this->_batchPartCursorOptions, + '_documentClass' => $this->_documentClass, + ]); $this->_batchParts[$batchPartId] = $batchPart; @@ -556,6 +559,21 @@ public function getConnection() { return $this->_connection; } + + /** + * @var string Document class to use + */ + protected $_documentClass = '\ArangoDBClient\Document'; + + /** + * Sets the document class to use + * + * @param string $class Document class to use + */ + public function setDocumentClass($class) + { + $this->_documentClass = $class; + } } class_alias(Batch::class, '\triagens\ArangoDb\Batch'); diff --git a/lib/ArangoDBClient/BatchPart.php b/lib/ArangoDBClient/BatchPart.php index 52c767d0..94b8cc5c 100644 --- a/lib/ArangoDBClient/BatchPart.php +++ b/lib/ArangoDBClient/BatchPart.php @@ -89,6 +89,11 @@ public function __construct($batch, $id, $type, $request, $response, $options) { $sanitize = false; $options = array_merge($options, $this->getCursorOptions()); + + if (isset($options['_documentClass'])) { + $this->setDocumentClass($options['_documentClass']); + } + extract($options, EXTR_IF_EXISTS); $this->setBatch($batch); $this->setId($id); diff --git a/lib/ArangoDBClient/Export.php b/lib/ArangoDBClient/Export.php index 46c7abb9..b2984c35 100644 --- a/lib/ArangoDBClient/Export.php +++ b/lib/ArangoDBClient/Export.php @@ -258,11 +258,27 @@ private function getCursorOptions() $result = [ ExportCursor::ENTRY_FLAT => (bool) $this->_flat, ExportCursor::ENTRY_BASEURL => Urls::URL_EXPORT, - ExportCursor::ENTRY_TYPE => $this->_type + ExportCursor::ENTRY_TYPE => $this->_type, + '_documentClass' => $this->_documentClass, ]; return $result; } + + /** + * @var string Document class to use + */ + protected $_documentClass = '\ArangoDBClient\Document'; + + /** + * Sets the document class to use + * + * @param string $class Document class to use + */ + public function setDocumentClass($class) + { + $this->_documentClass = $class; + } } class_alias(Export::class, '\triagens\ArangoDb\Export'); diff --git a/lib/ArangoDBClient/ExportCursor.php b/lib/ArangoDBClient/ExportCursor.php index 575ce70c..c5dd02fe 100644 --- a/lib/ArangoDBClient/ExportCursor.php +++ b/lib/ArangoDBClient/ExportCursor.php @@ -117,6 +117,10 @@ public function __construct(Connection $connection, array $data, array $options) if (isset($data[self::ENTRY_ID])) { $this->_id = $data[self::ENTRY_ID]; } + + if (isset($options['_documentClass'])) { + $this->setDocumentClass($options['_documentClass']); + } // attribute must be there assert(isset($data[self::ENTRY_HASMORE])); diff --git a/tests/CustomDocumentClassTest.php b/tests/CustomDocumentClassTest.php index 95c12db6..2336715e 100644 --- a/tests/CustomDocumentClassTest.php +++ b/tests/CustomDocumentClassTest.php @@ -21,32 +21,207 @@ class CustomDocumentClassTest extends \PHPUnit_Framework_TestCase { + protected static $testsTimestamp; + + public function __construct($name = null, array $data = [], $dataName = '') + { + parent::__construct($name, $data, $dataName); + static::$testsTimestamp = str_replace('.', '_', (string) microtime(true)); + } + + public function setUp() { - $this->connection = getConnection(); + $this->connection = getConnection(); + $this->collectionHandler = new CollectionHandler($this->connection); - // remove existing databases to make test repeatable - $database = 'ArangoTestSuiteDatabaseTest03'; try { - Database::delete($this->connection, $database); - } catch (Exception $e) { + $this->collectionHandler->drop('ArangoDB_PHP_TestSuite_TestCollection_01'); + } catch (\Exception $e) { + // don't bother us, if it's already deleted. + } + + $this->collection = new Collection(); + $this->collection->setName('ArangoDB_PHP_TestSuite_TestCollection_01' . '_' . static::$testsTimestamp); + $this->collectionHandler->create($this->collection); + } + + + /** + * Try to retrieve a document with custom document class + */ + public function testGetCustomDocumentWithHandler() + { + $connection = $this->connection; + $collection = $this->collection; + $document = new Document(); + $documentHandler = new DocumentHandler($connection); + + $document->someAttribute = 'someValue'; + + $documentId = $documentHandler->save($collection->getId(), $document); + + $documentHandler->setDocumentClass(CustomDocumentClass1::class); + $resultingDocument1 = $documentHandler->get($collection->getId(), $documentId); + static::assertInstanceOf(CustomDocumentClass1::class, $resultingDocument1, 'Retrieved document isn\'t made with provided CustomDocumentClass1!'); + + $documentHandler->setDocumentClass(CustomDocumentClass2::class); + $resultingDocument2 = $documentHandler->get($collection->getId(), $documentId); + static::assertInstanceOf(CustomDocumentClass2::class, $resultingDocument2, 'Retrieved document isn\'t made with provided CustomDocumentClass2!'); + + $documentHandler->setDocumentClass(Document::class); + $resultingDocument = $documentHandler->get($collection->getId(), $documentId); + static::assertInstanceOf(Document::class, $resultingDocument, 'Retrieved document isn\'t made with provided Document!'); + static::assertNotInstanceOf(CustomDocumentClass1::class, $resultingDocument, 'Retrieved document is made with CustomDocumentClass1!'); + static::assertNotInstanceOf(CustomDocumentClass2::class, $resultingDocument, 'Retrieved document is made with CustomDocumentClass2!'); + + $resultingAttribute = $resultingDocument->someAttribute; + static::assertSame( + 'someValue', $resultingAttribute, 'Resulting Attribute should be "someValue". It\'s :' . $resultingAttribute + ); + + $resultingAttribute1 = $resultingDocument1->someAttribute; + static::assertSame( + 'someValue', $resultingAttribute1, 'Resulting Attribute should be "someValue". It\'s :' . $resultingAttribute + ); + + $resultingAttribute2 = $resultingDocument2->someAttribute; + static::assertSame( + 'someValue', $resultingAttribute2, 'Resulting Attribute should be "someValue". It\'s :' . $resultingAttribute + ); + + $documentHandler->remove($document); + } + + /** + * Try to retrieve a custom document class via Statement. + */ + public function testGetCustomDocumentWithStatement() + { + $connection = $this->connection; + $collection = $this->collection; + $document = new Document(); + $documentHandler = new DocumentHandler($connection); + + $document->someAttribute = 'anotherValue'; + + $documentHandler->save($collection->getId(), $document); + + $statement = new Statement( + $connection, [ + 'query' => '', + 'count' => true, + 'batchSize' => 1000, + '_sanitize' => true, + ] + ); + $statement->setDocumentClass(CustomDocumentClass1::class); + $statement->setQuery(sprintf('FOR a IN `%s` RETURN a', $collection->getName())); + $cursor = $statement->execute(); + + $result = $cursor->current(); + + static::assertInstanceOf(CustomDocumentClass1::class, $result, 'Retrieved document isn\'t made with provided CustomDocumentClass1!'); + static::assertSame( + 'anotherValue', $result->someAttribute, 'Expected value anotherValue, found :' . $result->someAttribute + ); + + $documentHandler->remove($document); + } + + /** + * Try to retrieve a custom document class via Export. + */ + public function testGetCustomDocumentWithExport() + { + $connection = $this->connection; + $collection = $this->collection; + $document = new Document(); + $documentHandler = new DocumentHandler($connection); + + $document->someAttribute = 'exportValue'; + + $documentHandler->save($collection->getId(), $document); + + $export = new Export($connection, $collection->getName(), [ + 'batchSize' => 5000, + '_flat' => false, + 'flush' => true, + ]); + + // execute the export. this will return a special, forward-only cursor + $export->setDocumentClass(CustomDocumentClass1::class); + $cursor = $export->execute(); + + $found = false; + while ($docs = $cursor->getNextBatch()) { + $found = true; + static::assertTrue(count($docs) > 0, 'No documents retrieved!'); + foreach($docs as $doc) { + static::assertInstanceOf(CustomDocumentClass1::class, $doc, 'Retrieved document isn\'t made with provided CustomDocumentClass1!'); + static::assertSame( + 'exportValue', $doc->someAttribute, 'Expected value exportValue, found :' . $doc->someAttribute + ); + } } + + static::assertTrue($found, 'No batch results in Export'); - Database::create($this->connection, $database); + $documentHandler->remove($document); + } + + public function testGetCustomDocumentWithBatch() + { + $connection = $this->connection; + $collection = $this->collection; + $documentHandler = new DocumentHandler($connection); + $document1 = Document::createFromArray( + ['someAttribute' => 'someValue', 'someOtherAttribute' => 'someOtherValue'] + ); + $docId1 = $documentHandler->save($this->collection->getId(), $document1); + $document2 = Document::createFromArray( + ['someAttribute' => 'someValue2', 'someOtherAttribute' => 'someOtherValue2'] + ); + $docId2 = $documentHandler->save($this->collection->getId(), $document2); - $this->collectionHandler = new CustomCollectionHandler($this->connection); + $batch = new Batch($connection); + $batch->setDocumentClass(CustomDocumentClass1::class); + $batch->startCapture(); + + $documentHandler->getById($this->collection->getId(), $docId1); + $documentHandler->getById($this->collection->getId(), $docId2); + + $batch->process(); + $result = $batch->getPart(0)->getProcessedResponse(); + + static::assertInstanceOf(CustomDocumentClass1::class, $result, 'Retrieved document isn\'t made with provided CustomDocumentClass1!'); + static::assertSame( + 'someValue', $result->someAttribute, 'Expected value someValue, found :' . $result->someAttribute + ); + + $batchPart = $batch->getPart(1); + $batchPart->setDocumentClass(CustomDocumentClass2::class); + $result = $batchPart->getProcessedResponse(); + + static::assertInstanceOf(CustomDocumentClass2::class, $result, 'Retrieved document isn\'t made with provided CustomDocumentClass2!'); + static::assertSame( + 'someValue2', $result->someAttribute, 'Expected value someValue2, found :' . $result->someAttribute + ); + + $documentHandler->remove($document1); + $documentHandler->remove($document2); } + public function tearDown() { - // clean up - $database = ['ArangoTestSuiteDatabaseTest03']; try { - Database::delete($this->connection, $database); - } catch (Exception $e) { + $this->collectionHandler->drop('ArangoDB_PHP_TestSuite_TestCollection_01' . '_' . static::$testsTimestamp); + } catch (\Exception $e) { + // don't bother us, if it's already deleted. } - unset($this->connection); + unset($this->documentHandler, $this->document, $this->collectionHandler, $this->collection, $this->connection); } @@ -58,4 +233,12 @@ public function tearDown() */ class CustomCollectionHandler extends CollectionHandler { -} \ No newline at end of file +} + +/** + * Class CustomDocumentClass1 & CustomDocumentClass2 + * @package ArangoDBClient + */ +class CustomDocumentClass1 extends Document {} +class CustomDocumentClass2 extends Document {} + diff --git a/tests/bootstrap-connection-close.php b/tests/bootstrap-connection-close.php index 76f58b6e..e8758be6 100644 --- a/tests/bootstrap-connection-close.php +++ b/tests/bootstrap-connection-close.php @@ -50,7 +50,7 @@ function getConnectionOptions() // use basic authorization ConnectionOptions::OPTION_AUTH_USER => 'root', // user for basic authorization - ConnectionOptions::OPTION_AUTH_PASSWD => 'test', + ConnectionOptions::OPTION_AUTH_PASSWD => '', // password for basic authorization ConnectionOptions::OPTION_TIMEOUT => 12, // timeout in seconds