use Doctrine\CouchDB\CouchDBClient; use Relaxed\Replicator\ReplicationTask; use Relaxed\Replicator\Replicator; $sourceClient = CouchDBClient::create(array('dbname' => 'sourcedb')); $targetClient = CouchDBClient::create(array('dbname' => 'targetdb1')); // Add docs to the source db. $id = 'id'; $docs = array(array('_id' => $id . '1', 'foo' => 'bar1', '_rev' => '1-abc'), array('_id' => $id . '2', 'foo' => 'bar2', '_rev' => '1-bcd'), array('_id' => $id . '3', 'foo' => 'bar3', '_rev' => '1-cde')); $updater = $sourceClient->createBulkUpdater(); $updater->updateDocuments($docs); // Set newedits to false to use the supplied _rev instead of assigning // new ones. $updater->setNewEdits(false); $response = $updater->execute(); // Create the replication task. $task = new ReplicationTask(); // Enable target creation. $task->setCreateTarget(true); // Create the replicator. $replicator = new Replicator($sourceClient, $targetClient, $task); // Get the replication report as an array. var_dump($replicator->startReplication(false, true)); /* * array(3) { ["multipartResponse"]=> array(0) { } ["bulkResponse"]=> array(3) { ["id1"]=> array(1) {
/** * When $printStatus is true, the replication details are written to the * STDOUT. When $getFinalReport is true, detailed replication report is * returned and if false, only the success and failure counts are returned. * Both $printStatus and $getFinalReport are used only when the * replication is continuous and are ignored in case of normal replication. * * @param bool $printStatus * @param bool $getFinalReport * @return array * @throws HTTPException */ public function locateChangedDocumentsAndReplicate($printStatus, $getFinalReport) { $finalResponse = array('multipartResponse' => array(), 'bulkResponse' => array(), 'errorResponse' => array()); // Filtered changes stream is not supported. So Don't use the doc_ids // to specify the specific document ids. if ($this->task->getContinuous()) { $options = array('feed' => 'continuous', 'style' => $this->task->getStyle(), 'heartbeat' => $this->task->getHeartbeat(), 'since' => $this->task->getSinceSeq(), 'filter' => $this->task->getFilter()); if ($this->task->getHeartbeat() != null) { $options['heartbeat'] = $this->task->getHeartbeat(); } else { $options['timeout'] = $this->task->getTimeout() != null ? $this->task->getTimeout() : 10000; } $changesStream = $this->source->getChangesAsStream($options); $successCount = 0; $failureCount = 0; while (!feof($changesStream)) { $changes = fgets($changesStream); if ($changes == false || trim($changes) == '' || strpos($changes, 'last_seq') !== false) { sleep(2); continue; } $mapping = $this->getMapping($changes); $docId = array_keys($mapping)[0]; try { // getRevisionDifference throws bad request when JSON is // empty. So check before sending. $revDiff = count($mapping) > 0 ? $this->target->getRevisionDifference($mapping) : array(); $response = $this->replicateChanges($revDiff); if ($getFinalReport == true) { foreach ($response['multipartResponse'] as $docID => $res) { // Add the response of posting each revision of the // doc that had attachments. foreach ($res as $singleRevisionResponse) { // An Exception. if (is_a($singleRevisionResponse, 'Exception')) { // Note: In this case there is no 'rev' field in // the response. $finalResponse['errorResponse'][$docID][] = $singleRevisionResponse; } else { $finalResponse['multipartResponse'][$docID][] = $singleRevisionResponse; } } } foreach ($response['bulkResponse'] as $docID => $status) { $finalResponse['bulkResponse'][$docID][] = $status; } } if ($printStatus == true) { echo 'Document with id = ' . $docId . ' successfully replicated.' . "\n"; } $successCount++; } catch (\Exception $e) { if ($getFinalReport == true) { $finalResponse['errorResponse'][$docID][] = $e; } if ($printStatus == true) { echo 'Replication of document with id = ' . $docId . ' failed with code: ' . $e->getCode() . ".\n"; } $failureCount++; } } $finalResponse['successCount'] = $successCount; $finalResponse['failureCount'] = $failureCount; // The final response in case of continuous replication. // In case where $getFinalReport is true, response has five keys: // (i)multipartResponse, (ii) bulkResponse, (iii)errorResponse, // (iv) successCount, (v) failureCount. The errorResponse has the // responses from the failed replication attempt of docs having // attachments. To check failures related to bulk posting, the // returned status codes can be used. // When $getFinalReport is false, the returned response has only the // successCount and failureCount. return $finalResponse; } else { $changes = $this->source->getChanges(array('feed' => 'normal', 'style' => $this->task->getStyle(), 'since' => $this->task->getSinceSeq(), 'filter' => $this->task->getFilter(), 'doc_ids' => $this->task->getDocIds())); $mapping = $this->getMapping($changes); $revDiff = count($mapping) > 0 ? $this->target->getRevisionDifference($mapping) : array(); $response = $this->replicateChanges($revDiff); foreach ($response['multipartResponse'] as $docID => $res) { // Add the response of posting each revision of the // doc that had attachments. foreach ($res as $singleRevisionResponse) { // An Exception. if (is_a($singleRevisionResponse, 'Exception')) { // Note: In this case there is no 'rev' field in // the response. $finalResponse['errorResponse'][$docID][] = $singleRevisionResponse; } else { $finalResponse['multipartResponse'][$docID][] = $singleRevisionResponse; } } } foreach ($response['bulkResponse'] as $docID => $res) { $finalResponse['bulkResponse'][$docID][] = $res; } // In case of normal replication the $finalResponse has three // keys: (i) multipartResponse, (ii) bulkResponse, (iii) // errorResponse. return $finalResponse; } }
use Doctrine\CouchDB\CouchDBClient; use Relaxed\Replicator\ReplicationTask; use Relaxed\Replicator\Replicator; $sourceClient = CouchDBClient::create(array('dbname' => 'sourcedb')); $targetClient = CouchDBClient::create(array('dbname' => 'targetdb2')); // Add docs to the source db. $id = 'id'; $docs = array(array('_id' => $id . '1', 'foo' => 'bar1', '_rev' => '1-abc'), array('_id' => $id . '2', 'foo' => 'bar2', '_rev' => '1-bcd'), array('_id' => $id . '3', 'foo' => 'bar3', '_rev' => '1-cde')); $updater = $sourceClient->createBulkUpdater(); $updater->updateDocuments($docs); // Set newedits to false to use the supplied _rev instead of assigning // new ones. $updater->setNewEdits(false); $response = $updater->execute(); // Create the replication task. $task = new ReplicationTask(); $task->setDocIds(array('id1', 'id3')); // Enable target creation. $task->setCreateTarget(true); // Create the replicator. $replicator = new Replicator($sourceClient, $targetClient, $task); // Get the replication report as an array. var_dump($replicator->startReplication(false, true)); /* array(3) { ["multipartResponse"]=> array(0) { } ["bulkResponse"]=> array(2) { ["id1"]=>
/** * Test the mapping done in getMapping * * @dataProvider changesFeedProvider */ public function testGetMapping($changes, $continuous, $expected) { $task = new ReplicationTask(); $task->setContinuous($continuous); $replication = new Replication($this->source, $this->target, $task); $mapping = $replication->getMapping($changes); $this->assertEquals($expected, $mapping, 'Incorrect mapping in getMapping.'); }