File indexing completed on 2024-12-22 05:36:37
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Dojo 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * dojo.data support for Zend Framework 0024 * 0025 * @uses ArrayAccess 0026 * @uses Iterator 0027 * @uses Countable 0028 * @package Zend_Dojo 0029 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0030 * @license http://framework.zend.com/license/new-bsd New BSD License 0031 */ 0032 class Zend_Dojo_Data implements ArrayAccess,Iterator,Countable 0033 { 0034 /** 0035 * Identifier field of item 0036 * @var string|int 0037 */ 0038 protected $_identifier; 0039 0040 /** 0041 * Collected items 0042 * @var array 0043 */ 0044 protected $_items = array(); 0045 0046 /** 0047 * Label field of item 0048 * @var string 0049 */ 0050 protected $_label; 0051 0052 /** 0053 * Data container metadata 0054 * @var array 0055 */ 0056 protected $_metadata = array(); 0057 0058 /** 0059 * Constructor 0060 * 0061 * @param string|null $identifier 0062 * @param array|Traversable|null $items 0063 * @param string|null $label 0064 * @return void 0065 */ 0066 public function __construct($identifier = null, $items = null, $label = null) 0067 { 0068 if (null !== $identifier) { 0069 $this->setIdentifier($identifier); 0070 } 0071 if (null !== $items) { 0072 $this->setItems($items); 0073 } 0074 if (null !== $label) { 0075 $this->setLabel($label); 0076 } 0077 } 0078 0079 /** 0080 * Set the items to collect 0081 * 0082 * @param array|Traversable $items 0083 * @return Zend_Dojo_Data 0084 */ 0085 public function setItems($items) 0086 { 0087 $this->clearItems(); 0088 return $this->addItems($items); 0089 } 0090 0091 /** 0092 * Set an individual item, optionally by identifier (overwrites) 0093 * 0094 * @param array|object $item 0095 * @param string|null $identifier 0096 * @return Zend_Dojo_Data 0097 */ 0098 public function setItem($item, $id = null) 0099 { 0100 $item = $this->_normalizeItem($item, $id); 0101 $this->_items[$item['id']] = $item['data']; 0102 return $this; 0103 } 0104 0105 /** 0106 * Add an individual item, optionally by identifier 0107 * 0108 * @param array|object $item 0109 * @param string|null $id 0110 * @return Zend_Dojo_Data 0111 */ 0112 public function addItem($item, $id = null) 0113 { 0114 $item = $this->_normalizeItem($item, $id); 0115 0116 if ($this->hasItem($item['id'])) { 0117 // require_once 'Zend/Dojo/Exception.php'; 0118 throw new Zend_Dojo_Exception('Overwriting items using addItem() is not allowed'); 0119 } 0120 0121 $this->_items[$item['id']] = $item['data']; 0122 0123 return $this; 0124 } 0125 0126 /** 0127 * Add multiple items at once 0128 * 0129 * @param array|Traversable $items 0130 * @return Zend_Dojo_Data 0131 */ 0132 public function addItems($items) 0133 { 0134 if (!is_array($items) && (!is_object($items) || !($items instanceof Traversable))) { 0135 // require_once 'Zend/Dojo/Exception.php'; 0136 throw new Zend_Dojo_Exception('Only arrays and Traversable objects may be added to ' . __CLASS__); 0137 } 0138 0139 foreach ($items as $item) { 0140 $this->addItem($item); 0141 } 0142 0143 return $this; 0144 } 0145 0146 /** 0147 * Get all items as an array 0148 * 0149 * Serializes items to arrays. 0150 * 0151 * @return array 0152 */ 0153 public function getItems() 0154 { 0155 return $this->_items; 0156 } 0157 0158 /** 0159 * Does an item with the given identifier exist? 0160 * 0161 * @param string|int $id 0162 * @return bool 0163 */ 0164 public function hasItem($id) 0165 { 0166 return array_key_exists($id, $this->_items); 0167 } 0168 0169 /** 0170 * Retrieve an item by identifier 0171 * 0172 * Item retrieved will be flattened to an array. 0173 * 0174 * @param string $id 0175 * @return array 0176 */ 0177 public function getItem($id) 0178 { 0179 if (!$this->hasItem($id)) { 0180 return null; 0181 } 0182 0183 return $this->_items[$id]; 0184 } 0185 0186 /** 0187 * Remove item by identifier 0188 * 0189 * @param string $id 0190 * @return Zend_Dojo_Data 0191 */ 0192 public function removeItem($id) 0193 { 0194 if ($this->hasItem($id)) { 0195 unset($this->_items[$id]); 0196 } 0197 0198 return $this; 0199 } 0200 0201 /** 0202 * Remove all items at once 0203 * 0204 * @return Zend_Dojo_Data 0205 */ 0206 public function clearItems() 0207 { 0208 $this->_items = array(); 0209 return $this; 0210 } 0211 0212 0213 /** 0214 * Set identifier for item lookups 0215 * 0216 * @param string|int|null $identifier 0217 * @return Zend_Dojo_Data 0218 */ 0219 public function setIdentifier($identifier) 0220 { 0221 if (null === $identifier) { 0222 $this->_identifier = null; 0223 } elseif (is_string($identifier)) { 0224 $this->_identifier = $identifier; 0225 } elseif (is_numeric($identifier)) { 0226 $this->_identifier = (int) $identifier; 0227 } else { 0228 // require_once 'Zend/Dojo/Exception.php'; 0229 throw new Zend_Dojo_Exception('Invalid identifier; please use a string or integer'); 0230 } 0231 0232 return $this; 0233 } 0234 0235 /** 0236 * Retrieve current item identifier 0237 * 0238 * @return string|int|null 0239 */ 0240 public function getIdentifier() 0241 { 0242 return $this->_identifier; 0243 } 0244 0245 0246 /** 0247 * Set label to use for displaying item associations 0248 * 0249 * @param string|null $label 0250 * @return Zend_Dojo_Data 0251 */ 0252 public function setLabel($label) 0253 { 0254 if (null === $label) { 0255 $this->_label = null; 0256 } else { 0257 $this->_label = (string) $label; 0258 } 0259 return $this; 0260 } 0261 0262 /** 0263 * Retrieve item association label 0264 * 0265 * @return string|null 0266 */ 0267 public function getLabel() 0268 { 0269 return $this->_label; 0270 } 0271 0272 /** 0273 * Set metadata by key or en masse 0274 * 0275 * @param string|array $spec 0276 * @param mixed $value 0277 * @return Zend_Dojo_Data 0278 */ 0279 public function setMetadata($spec, $value = null) 0280 { 0281 if (is_string($spec) && (null !== $value)) { 0282 $this->_metadata[$spec] = $value; 0283 } elseif (is_array($spec)) { 0284 foreach ($spec as $key => $value) { 0285 $this->setMetadata($key, $value); 0286 } 0287 } 0288 return $this; 0289 } 0290 0291 /** 0292 * Get metadata item or all metadata 0293 * 0294 * @param null|string $key Metadata key when pulling single metadata item 0295 * @return mixed 0296 */ 0297 public function getMetadata($key = null) 0298 { 0299 if (null === $key) { 0300 return $this->_metadata; 0301 } 0302 0303 if (array_key_exists($key, $this->_metadata)) { 0304 return $this->_metadata[$key]; 0305 } 0306 0307 return null; 0308 } 0309 0310 /** 0311 * Clear individual or all metadata item(s) 0312 * 0313 * @param null|string $key 0314 * @return Zend_Dojo_Data 0315 */ 0316 public function clearMetadata($key = null) 0317 { 0318 if (null === $key) { 0319 $this->_metadata = array(); 0320 } elseif (array_key_exists($key, $this->_metadata)) { 0321 unset($this->_metadata[$key]); 0322 } 0323 return $this; 0324 } 0325 0326 /** 0327 * Load object from array 0328 * 0329 * @param array $data 0330 * @return Zend_Dojo_Data 0331 */ 0332 public function fromArray(array $data) 0333 { 0334 if (array_key_exists('identifier', $data)) { 0335 $this->setIdentifier($data['identifier']); 0336 } 0337 if (array_key_exists('label', $data)) { 0338 $this->setLabel($data['label']); 0339 } 0340 if (array_key_exists('items', $data) && is_array($data['items'])) { 0341 $this->setItems($data['items']); 0342 } else { 0343 $this->clearItems(); 0344 } 0345 return $this; 0346 } 0347 0348 /** 0349 * Load object from JSON 0350 * 0351 * @param string $json 0352 * @return Zend_Dojo_Data 0353 */ 0354 public function fromJson($json) 0355 { 0356 if (!is_string($json)) { 0357 // require_once 'Zend/Dojo/Exception.php'; 0358 throw new Zend_Dojo_Exception('fromJson() expects JSON input'); 0359 } 0360 // require_once 'Zend/Json.php'; 0361 $data = Zend_Json::decode($json); 0362 return $this->fromArray($data); 0363 } 0364 0365 /** 0366 * Seralize entire data structure, including identifier and label, to array 0367 * 0368 * @return array 0369 */ 0370 public function toArray() 0371 { 0372 if (null === ($identifier = $this->getIdentifier())) { 0373 // require_once 'Zend/Dojo/Exception.php'; 0374 throw new Zend_Dojo_Exception('Serialization requires that an identifier be present in the object; first call setIdentifier()'); 0375 } 0376 0377 $array = array( 0378 'identifier' => $identifier, 0379 'items' => array_values($this->getItems()), 0380 ); 0381 0382 $metadata = $this->getMetadata(); 0383 if (!empty($metadata)) { 0384 foreach ($metadata as $key => $value) { 0385 $array[$key] = $value; 0386 } 0387 } 0388 0389 if (null !== ($label = $this->getLabel())) { 0390 $array['label'] = $label; 0391 } 0392 0393 return $array; 0394 } 0395 0396 /** 0397 * Serialize to JSON (dojo.data format) 0398 * 0399 * @return string 0400 */ 0401 public function toJson() 0402 { 0403 // require_once 'Zend/Json.php'; 0404 return Zend_Json::encode($this->toArray()); 0405 } 0406 0407 /** 0408 * Serialize to string (proxy to {@link toJson()}) 0409 * 0410 * @return string 0411 */ 0412 public function __toString() 0413 { 0414 return $this->toJson(); 0415 } 0416 0417 /** 0418 * ArrayAccess: does offset exist? 0419 * 0420 * @param string|int $offset 0421 * @return bool 0422 */ 0423 public function offsetExists($offset) 0424 { 0425 return (null !== $this->getItem($offset)); 0426 } 0427 0428 /** 0429 * ArrayAccess: retrieve by offset 0430 * 0431 * @param string|int $offset 0432 * @return array 0433 */ 0434 public function offsetGet($offset) 0435 { 0436 return $this->getItem($offset); 0437 } 0438 0439 /** 0440 * ArrayAccess: set value by offset 0441 * 0442 * @param string $offset 0443 * @param array|object|null $value 0444 * @return void 0445 */ 0446 public function offsetSet($offset, $value) 0447 { 0448 $this->setItem($value, $offset); 0449 } 0450 0451 /** 0452 * ArrayAccess: unset value by offset 0453 * 0454 * @param string $offset 0455 * @return void 0456 */ 0457 public function offsetUnset($offset) 0458 { 0459 $this->removeItem($offset); 0460 } 0461 0462 /** 0463 * Iterator: get current value 0464 * 0465 * @return array 0466 */ 0467 public function current() 0468 { 0469 return current($this->_items); 0470 } 0471 0472 /** 0473 * Iterator: get current key 0474 * 0475 * @return string|int 0476 */ 0477 public function key() 0478 { 0479 return key($this->_items); 0480 } 0481 0482 /** 0483 * Iterator: get next item 0484 * 0485 * @return void 0486 */ 0487 public function next() 0488 { 0489 return next($this->_items); 0490 } 0491 0492 /** 0493 * Iterator: rewind to first value in collection 0494 * 0495 * @return void 0496 */ 0497 public function rewind() 0498 { 0499 return reset($this->_items); 0500 } 0501 0502 /** 0503 * Iterator: is item valid? 0504 * 0505 * @return bool 0506 */ 0507 public function valid() 0508 { 0509 return (bool) $this->current(); 0510 } 0511 0512 /** 0513 * Countable: how many items are present 0514 * 0515 * @return int 0516 */ 0517 public function count() 0518 { 0519 return count($this->_items); 0520 } 0521 0522 /** 0523 * Normalize an item to attach to the collection 0524 * 0525 * @param array|object $item 0526 * @param string|int|null $id 0527 * @return array 0528 */ 0529 protected function _normalizeItem($item, $id) 0530 { 0531 if (null === ($identifier = $this->getIdentifier())) { 0532 // require_once 'Zend/Dojo/Exception.php'; 0533 throw new Zend_Dojo_Exception('You must set an identifier prior to adding items'); 0534 } 0535 0536 if (!is_object($item) && !is_array($item)) { 0537 // require_once 'Zend/Dojo/Exception.php'; 0538 throw new Zend_Dojo_Exception('Only arrays and objects may be attached'); 0539 } 0540 0541 if (is_object($item)) { 0542 if (method_exists($item, 'toArray')) { 0543 $item = $item->toArray(); 0544 } else { 0545 $item = get_object_vars($item); 0546 } 0547 } 0548 0549 if ((null === $id) && !array_key_exists($identifier, $item)) { 0550 // require_once 'Zend/Dojo/Exception.php'; 0551 throw new Zend_Dojo_Exception('Item must contain a column matching the currently set identifier'); 0552 } elseif (null === $id) { 0553 $id = $item[$identifier]; 0554 } else { 0555 $item[$identifier] = $id; 0556 } 0557 0558 return array( 0559 'id' => $id, 0560 'data' => $item, 0561 ); 0562 } 0563 }