예제 #1
0
 protected function doExecute()
 {
     $path = $this->getHttpQuery();
     $response = $this->client->request("GET", $path);
     if ($response instanceof ErrorResponse) {
         // Create view, if it does not exist yet
         $this->createDesignDocument();
         $response = $this->client->request("GET", $path);
     }
     if ($response->status >= 400) {
         throw HTTPException::fromResponse($path, $response);
     }
     return $response;
 }
예제 #2
0
 protected function doExecute()
 {
     $path = $this->getHttpQuery();
     $method = "GET";
     $data = null;
     if ($this->getParameter("keys") !== null) {
         $method = "POST";
         $data = json_encode(array("keys" => $this->getParameter("keys")));
     }
     $response = $this->client->request($method, $path, $data);
     if ($response instanceof ErrorResponse && $this->doc) {
         $this->createDesignDocument();
         $response = $this->client->request($method, $path, $data);
     }
     if ($response->status >= 400) {
         throw HTTPException::fromResponse($path, $response);
     }
     return $response;
 }
예제 #3
0
 /**
  * Commit any recent changes to the specified database to disk.
  *
  * @return array
  * @throws HTTPException
  */
 public function ensureFullCommit()
 {
     $path = '/' . $this->databaseName . '/_ensure_full_commit';
     $response = $this->httpClient->request('POST', $path);
     if ($response->status != 201) {
         throw HTTPException::fromResponse($path, $response);
     }
     return $response->body;
 }
예제 #4
0
 /**
  * POST /db/_replicate
  *
  * @param string $source
  * @param string $target
  * @param bool|null $cancel
  * @param bool|null $continuous
  * @param string|null $filter
  * @param array|null $ids
  * @param string|null $proxy
  * @return array
  */
 public function replicate($source, $target, $cancel = null, $continuous = null, $filter = null, array $ids = null, $proxy = null)
 {
     $params = array('target' => $target, 'source' => $source);
     if ($cancel !== null) {
         $params['cancel'] = (bool) $cancel;
     }
     if ($continuous !== null) {
         $params['continuous'] = (bool) $continuous;
     }
     if ($filter !== null) {
         $params['filter'] = $filter;
     }
     if ($ids !== null) {
         $params['doc_ids'] = $ids;
     }
     if ($proxy !== null) {
         $params['proxy'] = $proxy;
     }
     $path = '/_replicate';
     $response = $this->httpClient->request('POST', $path, json_encode($params));
     if ($response->status >= 400) {
         throw HTTPException::fromResponse($path, $response);
     }
     return $response->body;
 }
예제 #5
0
 /**
  * Flush Operation - Write all dirty entries to the CouchDB.
  *
  * @return void
  */
 public function flush()
 {
     $this->detectChangedDocuments();
     if ($this->evm->hasListeners(Event::onFlush)) {
         $this->evm->dispatchEvent(Event::onFlush, new Event\OnFlushEventArgs($this));
     }
     $config = $this->dm->getConfiguration();
     $bulkUpdater = $this->dm->getCouchDBClient()->createBulkUpdater();
     $bulkUpdater->setAllOrNothing($config->getAllOrNothingFlush());
     foreach ($this->scheduledRemovals as $oid => $document) {
         $bulkUpdater->deleteDocument($this->documentIdentifiers[$oid], $this->documentRevisions[$oid]);
         $this->removeFromIdentityMap($document);
         if ($this->evm->hasListeners(Event::postRemove)) {
             $this->evm->dispatchEvent(Event::postRemove, new Event\LifecycleEventArgs($document, $this->dm));
         }
     }
     foreach ($this->scheduledUpdates as $oid => $document) {
         $class = $this->dm->getClassMetadata(get_class($document));
         if ($this->evm->hasListeners(Event::preUpdate)) {
             $this->evm->dispatchEvent(Event::preUpdate, new Event\LifecycleEventArgs($document, $this->dm));
             $this->computeChangeSet($class, $document);
             // TODO: prevent association computations in this case?
         }
         $data = $this->metadataResolver->createDefaultDocumentStruct($class);
         // Convert field values to json values.
         foreach ($this->originalData[$oid] as $fieldName => $fieldValue) {
             if (isset($class->fieldMappings[$fieldName])) {
                 if ($fieldValue !== null && isset($class->fieldMappings[$fieldName]['embedded'])) {
                     // As we store the serialized value in originalEmbeddedData, we can simply copy here.
                     $fieldValue = $this->originalEmbeddedData[$oid][$class->fieldMappings[$fieldName]['jsonName']];
                 } else {
                     if ($fieldValue !== null) {
                         $fieldValue = Type::getType($class->fieldMappings[$fieldName]['type'])->convertToCouchDBValue($fieldValue);
                     }
                 }
                 $data[$class->fieldMappings[$fieldName]['jsonName']] = $fieldValue;
             } else {
                 if (isset($class->associationsMappings[$fieldName])) {
                     if ($class->associationsMappings[$fieldName]['type'] & ClassMetadata::TO_ONE) {
                         if (\is_object($fieldValue)) {
                             $fieldValue = $this->getDocumentIdentifier($fieldValue);
                         } else {
                             $fieldValue = null;
                         }
                         $data = $this->metadataResolver->storeAssociationField($data, $class, $this->dm, $fieldName, $fieldValue);
                     } else {
                         if ($class->associationsMappings[$fieldName]['type'] & ClassMetadata::TO_MANY) {
                             if ($class->associationsMappings[$fieldName]['isOwning']) {
                                 // TODO: Optimize when not initialized yet! In ManyToMany case we can keep track of ALL ids
                                 $ids = array();
                                 if (is_array($fieldValue) || $fieldValue instanceof \Doctrine\Common\Collections\Collection) {
                                     foreach ($fieldValue as $key => $relatedObject) {
                                         $ids[$key] = $this->getDocumentIdentifier($relatedObject);
                                     }
                                 }
                                 $data = $this->metadataResolver->storeAssociationField($data, $class, $this->dm, $fieldName, $ids);
                             }
                         }
                     }
                 } else {
                     if ($class->hasAttachments && $fieldName == $class->attachmentField) {
                         if (is_array($fieldValue) && $fieldValue) {
                             $data['_attachments'] = array();
                             foreach ($fieldValue as $filename => $attachment) {
                                 if (!$attachment instanceof \Doctrine\CouchDB\Attachment) {
                                     throw CouchDBException::invalidAttachment($class->name, $this->documentIdentifiers[$oid], $filename);
                                 }
                                 $data['_attachments'][$filename] = $attachment->toArray();
                             }
                         }
                     }
                 }
             }
         }
         // respect the non mapped data, otherwise they will be deleted.
         if (isset($this->nonMappedData[$oid]) && $this->nonMappedData[$oid]) {
             $data = array_merge($data, $this->nonMappedData[$oid]);
         }
         $rev = $this->getDocumentRevision($document);
         if ($rev) {
             $data['_rev'] = $rev;
         }
         $bulkUpdater->updateDocument($data);
     }
     $response = $bulkUpdater->execute();
     $updateConflictDocuments = array();
     if ($response->status == 201) {
         foreach ($response->body as $docResponse) {
             if (!isset($this->identityMap[$docResponse['id']])) {
                 // deletions
                 continue;
             }
             $document = $this->identityMap[$docResponse['id']];
             if (isset($docResponse['error'])) {
                 $updateConflictDocuments[] = $document;
             } else {
                 $this->documentRevisions[spl_object_hash($document)] = $docResponse['rev'];
                 $class = $this->dm->getClassMetadata(get_class($document));
                 if ($class->isVersioned) {
                     $class->reflFields[$class->versionField]->setValue($document, $docResponse['rev']);
                 }
             }
             if ($this->evm->hasListeners(Event::postUpdate)) {
                 $this->evm->dispatchEvent(Event::postUpdate, new Event\LifecycleEventArgs($document, $this->dm));
             }
         }
     } else {
         if ($response->status >= 400) {
             throw HTTPException::fromResponse($bulkUpdater->getPath(), $response);
         }
     }
     foreach ($this->visitedCollections as $col) {
         $col->takeSnapshot();
     }
     $this->scheduledUpdates = $this->scheduledRemovals = $this->visitedCollections = array();
     if (count($updateConflictDocuments)) {
         throw new UpdateConflictException($updateConflictDocuments);
     }
 }
예제 #6
0
 /**
  * Get revision difference.
  *
  * @param  array $data
  * @return array
  * @throws HTTPException
  */
 public function getRevisionDifference($data)
 {
     $path = '/' . $this->databaseName . '/_revs_diff';
     $response = $this->httpClient->request('POST', $path, json_encode($data));
     if ($response->status != 200) {
         throw HTTPException::fromResponse($path, $response);
     }
     return $response->body;
 }
예제 #7
0
 /**
  * @return array
  * @throws HTTPException
  * @throws \Exception
  */
 public function getReplicationLog()
 {
     $sourceLog = null;
     $targetLog = null;
     $replicationDocId = '_local' . '/' . $this->task->getRepId();
     $sourceResponse = $this->source->findDocument($replicationDocId);
     $targetResponse = $this->target->findDocument($replicationDocId);
     if ($sourceResponse->status == 200) {
         $sourceLog = $sourceResponse->body;
     } elseif ($sourceResponse->status != 404) {
         throw HTTPException::fromResponse('/' . $this->source->getDatabase() . '/' . $replicationDocId, $sourceResponse);
     }
     if ($targetResponse->status == 200) {
         $targetLog = $targetResponse->body;
     } elseif ($targetResponse->status != 404) {
         throw HTTPException::fromResponse('/' . $this->target->getDatabase() . '/' . $replicationDocId, $targetResponse);
     }
     return array($sourceLog, $targetLog);
 }
예제 #8
0
 /**
  * Lazy Load Data from CouchDB if necessary
  *
  * @return void
  */
 private function lazyLoad()
 {
     if ($this->stub) {
         $response = $this->httpClient->request('GET', $this->path, null, true);
         // raw request
         if ($response->status != 200) {
             throw HTTPException::fromResponse($this->path, $response);
         }
         $this->stub = false;
         $this->binaryData = $response->body;
         $this->data = \base64_encode($this->binaryData);
     }
 }
 /**
  * @expectedException \Doctrine\CouchDB\HTTP\HTTPException
  */
 public function testGetReplicationLogRaisesExceptionWhenPeerNotReachable()
 {
     $this->response->status = 500;
     $this->source->expects($this->once())->method('findDocument')->willThrowException(HTTPException::fromResponse(null, $this->response));
     $task = new ReplicationTask();
     $replication = new Replication($this->source, $this->target, $task);
     list($sourceLog, $targetLog) = $replication->getReplicationLog();
     $this->assertEquals($targetLog, array("log" => "source_replication_log"));
     $this->assertEquals($sourceLog, null);
 }
예제 #10
0
 /**
  * Get changes as a stream.
  *
  * This method similar to the getChanges() method. But instead of returning
  * the set of changes, it returns the connection stream from which the response
  * can be read line by line. This is useful when you want to continuously get changes
  * as they occur. Filtered changes feed is not supported by this method.
  *
  * @param array $params
  * @param bool $raw
  * @return resource
  * @throws HTTPException
  */
 public function getChangesAsStream(array $params = array())
 {
     // Set feed to continuous.
     if (!isset($params['feed']) || $params['feed'] != 'continuous') {
         $params['feed'] = 'continuous';
     }
     $path = '/' . $this->databaseName . '/_changes';
     $connectionOptions = $this->getHttpClient()->getOptions();
     $streamClient = new StreamClient($connectionOptions['host'], $connectionOptions['port'], $connectionOptions['username'], $connectionOptions['password'], $connectionOptions['ip'], $connectionOptions['ssl']);
     foreach ($params as $key => $value) {
         if (isset($params[$key]) === true && is_bool($value) === true) {
             $params[$key] = $value ? 'true' : 'false';
         }
     }
     if (count($params) > 0) {
         $query = http_build_query($params);
         $path = $path . '?' . $query;
     }
     $stream = $streamClient->getConnection('GET', $path, null);
     $headers = $streamClient->getStreamHeaders($stream);
     if (empty($headers['status'])) {
         throw HTTPException::readFailure($connectionOptions['ip'], $connectionOptions['port'], 'Received an empty response or not status code', 0);
     } elseif ($headers['status'] != 200) {
         $body = '';
         while (!feof($stream)) {
             $body .= fgets($stream);
         }
         throw HTTPException::fromResponse($path, new Response($headers['status'], $headers, $body));
     }
     // Everything seems okay. Return the connection resource.
     return $stream;
 }