File indexing completed on 2025-01-26 05:24:51
0001 <?php 0002 /** 0003 * LICENSE 0004 * 0005 * This source file is subject to the new BSD license that is bundled 0006 * with this package in the file LICENSE.txt. 0007 * It is also available through the world-wide-web at this URL: 0008 * http://framework.zend.com/license/new-bsd 0009 * If you did not receive a copy of the license and are unable to 0010 * obtain it through the world-wide-web, please send an email 0011 * to license@zend.com so we can send you a copy immediately. 0012 * 0013 * @category Zend 0014 * @package Zend_Cloud 0015 * @subpackage DocumentService 0016 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0017 * @license http://framework.zend.com/license/new-bsd New BSD License 0018 */ 0019 0020 // require_once 'Zend/Cloud/DocumentService/Adapter/AbstractAdapter.php'; 0021 // require_once 'Zend/Cloud/DocumentService/Adapter/SimpleDb/Query.php'; 0022 // require_once 'Zend/Cloud/DocumentService/Exception.php'; 0023 // require_once 'Zend/Service/Amazon/SimpleDb.php'; 0024 // require_once 'Zend/Service/Amazon/SimpleDb/Attribute.php'; 0025 0026 /** 0027 * SimpleDB adapter for document service. 0028 * 0029 * @category Zend 0030 * @package Zend_Cloud 0031 * @subpackage DocumentService 0032 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0033 * @license http://framework.zend.com/license/new-bsd New BSD License 0034 */ 0035 class Zend_Cloud_DocumentService_Adapter_SimpleDb 0036 extends Zend_Cloud_DocumentService_Adapter_AbstractAdapter 0037 { 0038 /* 0039 * Options array keys for the SimpleDB adapter. 0040 */ 0041 const AWS_ACCESS_KEY = 'aws_accesskey'; 0042 const AWS_SECRET_KEY = 'aws_secretkey'; 0043 0044 const ITEM_NAME = 'ItemName'; 0045 0046 const MERGE_OPTION = "merge"; 0047 const RETURN_DOCUMENTS = "return_documents"; 0048 0049 const DEFAULT_QUERY_CLASS = 'Zend_Cloud_DocumentService_Adapter_SimpleDb_Query'; 0050 0051 0052 /** 0053 * SQS service instance. 0054 * @var Zend_Service_Amazon_SimpleDb 0055 */ 0056 protected $_simpleDb; 0057 0058 /** 0059 * Class to utilize for new query objects 0060 * @var string 0061 */ 0062 protected $_queryClass = 'Zend_Cloud_DocumentService_Adapter_SimpleDb_Query'; 0063 0064 /** 0065 * Constructor 0066 * 0067 * @param array|Zend_Config $options 0068 * @return void 0069 */ 0070 public function __construct($options = array()) 0071 { 0072 if ($options instanceof Zend_Config) { 0073 $options = $options->toArray(); 0074 } 0075 0076 if (!is_array($options)) { 0077 throw new Zend_Cloud_DocumentService_Exception('Invalid options provided to constructor'); 0078 } 0079 0080 $this->_simpleDb = new Zend_Service_Amazon_SimpleDb( 0081 $options[self::AWS_ACCESS_KEY], $options[self::AWS_SECRET_KEY] 0082 ); 0083 0084 if (isset($options[self::HTTP_ADAPTER])) { 0085 $this->_simpleDb->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); 0086 } 0087 0088 if (isset($options[self::DOCUMENT_CLASS])) { 0089 $this->setDocumentClass($options[self::DOCUMENT_CLASS]); 0090 } 0091 0092 if (isset($options[self::DOCUMENTSET_CLASS])) { 0093 $this->setDocumentSetClass($options[self::DOCUMENTSET_CLASS]); 0094 } 0095 0096 if (isset($options[self::QUERY_CLASS])) { 0097 $this->setQueryClass($options[self::QUERY_CLASS]); 0098 } 0099 } 0100 0101 /** 0102 * Create collection. 0103 * 0104 * @param string $name 0105 * @param array $options 0106 * @return void 0107 */ 0108 public function createCollection($name, $options = null) 0109 { 0110 try { 0111 $this->_simpleDb->createDomain($name); 0112 } catch(Zend_Service_Amazon_Exception $e) { 0113 throw new Zend_Cloud_DocumentService_Exception('Error on domain creation: '.$e->getMessage(), $e->getCode(), $e); 0114 } 0115 } 0116 0117 /** 0118 * Delete collection. 0119 * 0120 * @param string $name 0121 * @param array $options 0122 * @return void 0123 */ 0124 public function deleteCollection($name, $options = null) 0125 { 0126 try { 0127 $this->_simpleDb->deleteDomain($name); 0128 } catch(Zend_Service_Amazon_Exception $e) { 0129 throw new Zend_Cloud_DocumentService_Exception('Error on collection deletion: '.$e->getMessage(), $e->getCode(), $e); 0130 } 0131 } 0132 0133 /** 0134 * List collections. 0135 * 0136 * @param array $options 0137 * @return array 0138 */ 0139 public function listCollections($options = null) 0140 { 0141 try { 0142 // TODO package this in Pages 0143 $domains = $this->_simpleDb->listDomains()->getData(); 0144 } catch(Zend_Service_Amazon_Exception $e) { 0145 throw new Zend_Cloud_DocumentService_Exception('Error on collection deletion: '.$e->getMessage(), $e->getCode(), $e); 0146 } 0147 0148 return $domains; 0149 } 0150 0151 /** 0152 * List documents 0153 * 0154 * Returns a key/value array of document names to document objects. 0155 * 0156 * @param string $collectionName Name of collection for which to list documents 0157 * @param array|null $options 0158 * @return Zend_Cloud_DocumentService_DocumentSet 0159 */ 0160 public function listDocuments($collectionName, array $options = null) 0161 { 0162 $query = $this->select('*')->from($collectionName); 0163 $items = $this->query($collectionName, $query, $options); 0164 return $items; 0165 } 0166 0167 /** 0168 * Insert document 0169 * 0170 * @param string $collectionName Collection into which to insert document 0171 * @param array|Zend_Cloud_DocumentService_Document $document 0172 * @param array $options 0173 * @return void 0174 */ 0175 public function insertDocument($collectionName, $document, $options = null) 0176 { 0177 if (is_array($document)) { 0178 $document = $this->_getDocumentFromArray($document); 0179 } 0180 0181 if (!$document instanceof Zend_Cloud_DocumentService_Document) { 0182 throw new Zend_Cloud_DocumentService_Exception('Invalid document supplied'); 0183 } 0184 0185 try { 0186 $this->_simpleDb->putAttributes( 0187 $collectionName, 0188 $document->getID(), 0189 $this->_makeAttributes($document->getID(), $document->getFields()) 0190 ); 0191 } catch(Zend_Service_Amazon_Exception $e) { 0192 throw new Zend_Cloud_DocumentService_Exception('Error on document insertion: '.$e->getMessage(), $e->getCode(), $e); 0193 } 0194 } 0195 0196 /** 0197 * Replace an existing document with a new version 0198 * 0199 * @param string $collectionName 0200 * @param array|Zend_Cloud_DocumentService_Document $document 0201 * @param array $options 0202 * @return void 0203 */ 0204 public function replaceDocument($collectionName, $document, $options = null) 0205 { 0206 if (is_array($document)) { 0207 $document = $this->_getDocumentFromArray($document); 0208 } 0209 0210 if (!$document instanceof Zend_Cloud_DocumentService_Document) { 0211 throw new Zend_Cloud_DocumentService_Exception('Invalid document supplied'); 0212 } 0213 0214 // Delete document first, then insert. PutAttributes always keeps any 0215 // fields not referenced in the payload, but present in the document 0216 $documentId = $document->getId(); 0217 $fields = $document->getFields(); 0218 $docClass = get_class($document); 0219 $this->deleteDocument($collectionName, $document, $options); 0220 0221 $document = new $docClass($fields, $documentId); 0222 $this->insertDocument($collectionName, $document); 0223 } 0224 0225 /** 0226 * Update document. The new document replaces the existing document. 0227 * 0228 * Option 'merge' specifies to add all attributes (if true) or 0229 * specific attributes ("attr" => true) instead of replacing them. 0230 * By default, attributes are replaced. 0231 * 0232 * @param string $collectionName 0233 * @param mixed|Zend_Cloud_DocumentService_Document $documentId Document ID, adapter-dependent 0234 * @param array|Zend_Cloud_DocumentService_Document $fieldset Set of fields to update 0235 * @param array $options 0236 * @return boolean 0237 */ 0238 public function updateDocument($collectionName, $documentId, $fieldset = null, $options = null) 0239 { 0240 if (null === $fieldset && $documentId instanceof Zend_Cloud_DocumentService_Document) { 0241 $fieldset = $documentId->getFields(); 0242 if (empty($documentId)) { 0243 $documentId = $documentId->getId(); 0244 } 0245 } elseif ($fieldset instanceof Zend_Cloud_DocumentService_Document) { 0246 if (empty($documentId)) { 0247 $documentId = $fieldset->getId(); 0248 } 0249 $fieldset = $fieldset->getFields(); 0250 } 0251 0252 $replace = array(); 0253 if (empty($options[self::MERGE_OPTION])) { 0254 // no merge option - we replace all 0255 foreach ($fieldset as $key => $value) { 0256 $replace[$key] = true; 0257 } 0258 } elseif (is_array($options[self::MERGE_OPTION])) { 0259 foreach ($fieldset as $key => $value) { 0260 if (empty($options[self::MERGE_OPTION][$key])) { 0261 // if there's merge key, we add it, otherwise we replace it 0262 $replace[$key] = true; 0263 } 0264 } 0265 } // otherwise $replace is empty - all is merged 0266 0267 try { 0268 $this->_simpleDb->putAttributes( 0269 $collectionName, 0270 $documentId, 0271 $this->_makeAttributes($documentId, $fieldset), 0272 $replace 0273 ); 0274 } catch(Zend_Service_Amazon_Exception $e) { 0275 throw new Zend_Cloud_DocumentService_Exception('Error on document update: '.$e->getMessage(), $e->getCode(), $e); 0276 } 0277 return true; 0278 } 0279 0280 /** 0281 * Delete document. 0282 * 0283 * @param string $collectionName Collection from which to delete document 0284 * @param mixed $document Document ID or Document object. 0285 * @param array $options 0286 * @return boolean 0287 */ 0288 public function deleteDocument($collectionName, $document, $options = null) 0289 { 0290 if ($document instanceof Zend_Cloud_DocumentService_Document) { 0291 $document = $document->getId(); 0292 } 0293 try { 0294 $this->_simpleDb->deleteAttributes($collectionName, $document); 0295 } catch(Zend_Service_Amazon_Exception $e) { 0296 throw new Zend_Cloud_DocumentService_Exception('Error on document deletion: '.$e->getMessage(), $e->getCode(), $e); 0297 } 0298 return true; 0299 } 0300 0301 /** 0302 * Fetch single document by ID 0303 * 0304 * @param string $collectionName Collection name 0305 * @param mixed $documentId Document ID, adapter-dependent 0306 * @param array $options 0307 * @return Zend_Cloud_DocumentService_Document 0308 */ 0309 public function fetchDocument($collectionName, $documentId, $options = null) 0310 { 0311 try { 0312 $attributes = $this->_simpleDb->getAttributes($collectionName, $documentId); 0313 if ($attributes == false || count($attributes) == 0) { 0314 return false; 0315 } 0316 return $this->_resolveAttributes($attributes, true); 0317 } catch(Zend_Service_Amazon_Exception $e) { 0318 throw new Zend_Cloud_DocumentService_Exception('Error on fetching document: '.$e->getMessage(), $e->getCode(), $e); 0319 } 0320 } 0321 0322 /** 0323 * Query for documents stored in the document service. If a string is passed in 0324 * $query, the query string will be passed directly to the service. 0325 * 0326 * @param string $collectionName Collection name 0327 * @param string $query 0328 * @param array $options 0329 * @return array Zend_Cloud_DocumentService_DocumentSet 0330 */ 0331 public function query($collectionName, $query, $options = null) 0332 { 0333 $returnDocs = isset($options[self::RETURN_DOCUMENTS]) 0334 ? (bool) $options[self::RETURN_DOCUMENTS] 0335 : true; 0336 0337 try { 0338 if ($query instanceof Zend_Cloud_DocumentService_Adapter_SimpleDb_Query) { 0339 $query = $query->assemble($collectionName); 0340 } 0341 $result = $this->_simpleDb->select($query); 0342 } catch(Zend_Service_Amazon_Exception $e) { 0343 throw new Zend_Cloud_DocumentService_Exception('Error on document query: '.$e->getMessage(), $e->getCode(), $e); 0344 } 0345 0346 return $this->_getDocumentSetFromResultSet($result, $returnDocs); 0347 } 0348 0349 /** 0350 * Create query statement 0351 * 0352 * @param string $fields 0353 * @return Zend_Cloud_DocumentService_Adapter_SimpleDb_Query 0354 */ 0355 public function select($fields = null) 0356 { 0357 $queryClass = $this->getQueryClass(); 0358 if (!class_exists($queryClass)) { 0359 // require_once 'Zend/Loader.php'; 0360 Zend_Loader::loadClass($queryClass); 0361 } 0362 0363 $query = new $queryClass($this); 0364 $defaultClass = self::DEFAULT_QUERY_CLASS; 0365 if (!$query instanceof $defaultClass) { 0366 throw new Zend_Cloud_DocumentService_Exception('Query class must extend ' . self::DEFAULT_QUERY_CLASS); 0367 } 0368 0369 $query->select($fields); 0370 return $query; 0371 } 0372 0373 /** 0374 * Get the concrete service client 0375 * 0376 * @return Zend_Service_Amazon_SimpleDb 0377 */ 0378 public function getClient() 0379 { 0380 return $this->_simpleDb; 0381 } 0382 0383 /** 0384 * Convert array of key-value pairs to array of Amazon attributes 0385 * 0386 * @param string $name 0387 * @param array $attributes 0388 * @return array 0389 */ 0390 protected function _makeAttributes($name, $attributes) 0391 { 0392 $result = array(); 0393 foreach ($attributes as $key => $attr) { 0394 $result[] = new Zend_Service_Amazon_SimpleDb_Attribute($name, $key, $attr); 0395 } 0396 return $result; 0397 } 0398 0399 /** 0400 * Convert array of Amazon attributes to array of key-value pairs 0401 * 0402 * @param array $attributes 0403 * @return array 0404 */ 0405 protected function _resolveAttributes($attributes, $returnDocument = false) 0406 { 0407 $result = array(); 0408 foreach ($attributes as $attr) { 0409 $value = $attr->getValues(); 0410 if (count($value) == 0) { 0411 $value = null; 0412 } elseif (count($value) == 1) { 0413 $value = $value[0]; 0414 } 0415 $result[$attr->getName()] = $value; 0416 } 0417 0418 // Return as document object? 0419 if ($returnDocument) { 0420 $documentClass = $this->getDocumentClass(); 0421 return new $documentClass($result, $attr->getItemName()); 0422 } 0423 0424 return $result; 0425 } 0426 0427 /** 0428 * Create suitable document from array of fields 0429 * 0430 * @param array $document 0431 * @return Zend_Cloud_DocumentService_Document 0432 */ 0433 protected function _getDocumentFromArray($document) 0434 { 0435 if (!isset($document[Zend_Cloud_DocumentService_Document::KEY_FIELD])) { 0436 if (isset($document[self::ITEM_NAME])) { 0437 $key = $document[self::ITEM_NAME]; 0438 unset($document[self::ITEM_NAME]); 0439 } else { 0440 throw new Zend_Cloud_DocumentService_Exception('Fields array should contain the key field '.Zend_Cloud_DocumentService_Document::KEY_FIELD); 0441 } 0442 } else { 0443 $key = $document[Zend_Cloud_DocumentService_Document::KEY_FIELD]; 0444 unset($document[Zend_Cloud_DocumentService_Document::KEY_FIELD]); 0445 } 0446 0447 $documentClass = $this->getDocumentClass(); 0448 return new $documentClass($document, $key); 0449 } 0450 0451 /** 0452 * Create a DocumentSet from a SimpleDb resultset 0453 * 0454 * @param Zend_Service_Amazon_SimpleDb_Page $resultSet 0455 * @param bool $returnDocs 0456 * @return Zend_Cloud_DocumentService_DocumentSet 0457 */ 0458 protected function _getDocumentSetFromResultSet(Zend_Service_Amazon_SimpleDb_Page $resultSet, $returnDocs = true) 0459 { 0460 $docs = array(); 0461 foreach ($resultSet->getData() as $item) { 0462 $docs[] = $this->_resolveAttributes($item, $returnDocs); 0463 } 0464 0465 $setClass = $this->getDocumentSetClass(); 0466 return new $setClass($docs); 0467 } 0468 }