web/Zend/Dojo/Data.php
changeset 0 4eba9c11703f
equal deleted inserted replaced
-1:000000000000 0:4eba9c11703f
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Dojo
       
    17  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  * @version    $Id: Data.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    20  */
       
    21 
       
    22 /**
       
    23  * dojo.data support for Zend Framework
       
    24  *
       
    25  * @uses       ArrayAccess
       
    26  * @uses       Iterator
       
    27  * @uses       Countable
       
    28  * @package    Zend_Dojo
       
    29  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    30  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    31  */
       
    32 class Zend_Dojo_Data implements ArrayAccess,Iterator,Countable
       
    33 {
       
    34     /**
       
    35      * Identifier field of item
       
    36      * @var string|int
       
    37      */
       
    38     protected $_identifier;
       
    39 
       
    40     /**
       
    41      * Collected items
       
    42      * @var array
       
    43      */
       
    44     protected $_items = array();
       
    45 
       
    46     /**
       
    47      * Label field of item
       
    48      * @var string
       
    49      */
       
    50     protected $_label;
       
    51 
       
    52     /**
       
    53      * Data container metadata
       
    54      * @var array
       
    55      */
       
    56     protected $_metadata = array();
       
    57 
       
    58     /**
       
    59      * Constructor
       
    60      *
       
    61      * @param  string|null $identifier
       
    62      * @param  array|Traversable|null $items
       
    63      * @param  string|null $label
       
    64      * @return void
       
    65      */
       
    66     public function __construct($identifier = null, $items = null, $label = null)
       
    67     {
       
    68         if (null !== $identifier) {
       
    69             $this->setIdentifier($identifier);
       
    70         }
       
    71         if (null !== $items) {
       
    72             $this->setItems($items);
       
    73         }
       
    74         if (null !== $label) {
       
    75             $this->setLabel($label);
       
    76         }
       
    77     }
       
    78 
       
    79     /**
       
    80      * Set the items to collect
       
    81      *
       
    82      * @param array|Traversable $items
       
    83      * @return Zend_Dojo_Data
       
    84      */
       
    85     public function setItems($items)
       
    86     {
       
    87         $this->clearItems();
       
    88         return $this->addItems($items);
       
    89     }
       
    90 
       
    91     /**
       
    92      * Set an individual item, optionally by identifier (overwrites)
       
    93      *
       
    94      * @param  array|object $item
       
    95      * @param  string|null $identifier
       
    96      * @return Zend_Dojo_Data
       
    97      */
       
    98     public function setItem($item, $id = null)
       
    99     {
       
   100         $item = $this->_normalizeItem($item, $id);
       
   101         $this->_items[$item['id']] = $item['data'];
       
   102         return $this;
       
   103     }
       
   104 
       
   105     /**
       
   106      * Add an individual item, optionally by identifier
       
   107      *
       
   108      * @param  array|object $item
       
   109      * @param  string|null $id
       
   110      * @return Zend_Dojo_Data
       
   111      */
       
   112     public function addItem($item, $id = null)
       
   113     {
       
   114         $item = $this->_normalizeItem($item, $id);
       
   115 
       
   116         if ($this->hasItem($item['id'])) {
       
   117             require_once 'Zend/Dojo/Exception.php';
       
   118             throw new Zend_Dojo_Exception('Overwriting items using addItem() is not allowed');
       
   119         }
       
   120 
       
   121         $this->_items[$item['id']] = $item['data'];
       
   122 
       
   123         return $this;
       
   124     }
       
   125 
       
   126     /**
       
   127      * Add multiple items at once
       
   128      *
       
   129      * @param  array|Traversable $items
       
   130      * @return Zend_Dojo_Data
       
   131      */
       
   132     public function addItems($items)
       
   133     {
       
   134         if (!is_array($items) && (!is_object($items) || !($items instanceof Traversable))) {
       
   135             require_once 'Zend/Dojo/Exception.php';
       
   136             throw new Zend_Dojo_Exception('Only arrays and Traversable objects may be added to ' . __CLASS__);
       
   137         }
       
   138 
       
   139         foreach ($items as $item) {
       
   140             $this->addItem($item);
       
   141         }
       
   142 
       
   143         return $this;
       
   144     }
       
   145 
       
   146     /**
       
   147      * Get all items as an array
       
   148      *
       
   149      * Serializes items to arrays.
       
   150      *
       
   151      * @return array
       
   152      */
       
   153     public function getItems()
       
   154     {
       
   155         return $this->_items;
       
   156     }
       
   157 
       
   158     /**
       
   159      * Does an item with the given identifier exist?
       
   160      *
       
   161      * @param  string|int $id
       
   162      * @return bool
       
   163      */
       
   164     public function hasItem($id)
       
   165     {
       
   166         return array_key_exists($id, $this->_items);
       
   167     }
       
   168 
       
   169     /**
       
   170      * Retrieve an item by identifier
       
   171      *
       
   172      * Item retrieved will be flattened to an array.
       
   173      *
       
   174      * @param  string $id
       
   175      * @return array
       
   176      */
       
   177     public function getItem($id)
       
   178     {
       
   179         if (!$this->hasItem($id)) {
       
   180             return null;
       
   181         }
       
   182 
       
   183         return $this->_items[$id];
       
   184     }
       
   185 
       
   186     /**
       
   187      * Remove item by identifier
       
   188      *
       
   189      * @param  string $id
       
   190      * @return Zend_Dojo_Data
       
   191      */
       
   192     public function removeItem($id)
       
   193     {
       
   194         if ($this->hasItem($id)) {
       
   195             unset($this->_items[$id]);
       
   196         }
       
   197 
       
   198         return $this;
       
   199     }
       
   200 
       
   201     /**
       
   202      * Remove all items at once
       
   203      *
       
   204      * @return Zend_Dojo_Data
       
   205      */
       
   206     public function clearItems()
       
   207     {
       
   208         $this->_items = array();
       
   209         return $this;
       
   210     }
       
   211 
       
   212 
       
   213     /**
       
   214      * Set identifier for item lookups
       
   215      *
       
   216      * @param  string|int|null $identifier
       
   217      * @return Zend_Dojo_Data
       
   218      */
       
   219     public function setIdentifier($identifier)
       
   220     {
       
   221         if (null === $identifier) {
       
   222             $this->_identifier = null;
       
   223         } elseif (is_string($identifier)) {
       
   224             $this->_identifier = $identifier;
       
   225         } elseif (is_numeric($identifier)) {
       
   226             $this->_identifier = (int) $identifier;
       
   227         } else {
       
   228             require_once 'Zend/Dojo/Exception.php';
       
   229             throw new Zend_Dojo_Exception('Invalid identifier; please use a string or integer');
       
   230         }
       
   231 
       
   232         return $this;
       
   233     }
       
   234 
       
   235     /**
       
   236      * Retrieve current item identifier
       
   237      *
       
   238      * @return string|int|null
       
   239      */
       
   240     public function getIdentifier()
       
   241     {
       
   242         return $this->_identifier;
       
   243     }
       
   244 
       
   245 
       
   246     /**
       
   247      * Set label to use for displaying item associations
       
   248      *
       
   249      * @param  string|null $label
       
   250      * @return Zend_Dojo_Data
       
   251      */
       
   252     public function setLabel($label)
       
   253     {
       
   254         if (null === $label) {
       
   255             $this->_label = null;
       
   256         } else {
       
   257             $this->_label = (string) $label;
       
   258         }
       
   259         return $this;
       
   260     }
       
   261 
       
   262     /**
       
   263      * Retrieve item association label
       
   264      *
       
   265      * @return string|null
       
   266      */
       
   267     public function getLabel()
       
   268     {
       
   269         return $this->_label;
       
   270     }
       
   271 
       
   272     /**
       
   273      * Set metadata by key or en masse
       
   274      *
       
   275      * @param  string|array $spec
       
   276      * @param  mixed $value
       
   277      * @return Zend_Dojo_Data
       
   278      */
       
   279     public function setMetadata($spec, $value = null)
       
   280     {
       
   281         if (is_string($spec) && (null !== $value)) {
       
   282             $this->_metadata[$spec] = $value;
       
   283         } elseif (is_array($spec)) {
       
   284             foreach ($spec as $key => $value) {
       
   285                 $this->setMetadata($key, $value);
       
   286             }
       
   287         }
       
   288         return $this;
       
   289     }
       
   290 
       
   291     /**
       
   292      * Get metadata item or all metadata
       
   293      *
       
   294      * @param  null|string $key Metadata key when pulling single metadata item
       
   295      * @return mixed
       
   296      */
       
   297     public function getMetadata($key = null)
       
   298     {
       
   299         if (null === $key) {
       
   300             return $this->_metadata;
       
   301         }
       
   302 
       
   303         if (array_key_exists($key, $this->_metadata)) {
       
   304             return $this->_metadata[$key];
       
   305         }
       
   306 
       
   307         return null;
       
   308     }
       
   309 
       
   310     /**
       
   311      * Clear individual or all metadata item(s)
       
   312      *
       
   313      * @param  null|string $key
       
   314      * @return Zend_Dojo_Data
       
   315      */
       
   316     public function clearMetadata($key = null)
       
   317     {
       
   318         if (null === $key) {
       
   319             $this->_metadata = array();
       
   320         } elseif (array_key_exists($key, $this->_metadata)) {
       
   321             unset($this->_metadata[$key]);
       
   322         }
       
   323         return $this;
       
   324     }
       
   325 
       
   326     /**
       
   327      * Load object from array
       
   328      *
       
   329      * @param  array $data
       
   330      * @return Zend_Dojo_Data
       
   331      */
       
   332     public function fromArray(array $data)
       
   333     {
       
   334         if (array_key_exists('identifier', $data)) {
       
   335             $this->setIdentifier($data['identifier']);
       
   336         }
       
   337         if (array_key_exists('label', $data)) {
       
   338             $this->setLabel($data['label']);
       
   339         }
       
   340         if (array_key_exists('items', $data) && is_array($data['items'])) {
       
   341             $this->setItems($data['items']);
       
   342         } else {
       
   343             $this->clearItems();
       
   344         }
       
   345         return $this;
       
   346     }
       
   347 
       
   348     /**
       
   349      * Load object from JSON
       
   350      *
       
   351      * @param  string $json
       
   352      * @return Zend_Dojo_Data
       
   353      */
       
   354     public function fromJson($json)
       
   355     {
       
   356         if (!is_string($json)) {
       
   357             require_once 'Zend/Dojo/Exception.php';
       
   358             throw new Zend_Dojo_Exception('fromJson() expects JSON input');
       
   359         }
       
   360         require_once 'Zend/Json.php';
       
   361         $data = Zend_Json::decode($json);
       
   362         return $this->fromArray($data);
       
   363     }
       
   364 
       
   365     /**
       
   366      * Seralize entire data structure, including identifier and label, to array
       
   367      *
       
   368      * @return array
       
   369      */
       
   370     public function toArray()
       
   371     {
       
   372         if (null === ($identifier = $this->getIdentifier())) {
       
   373             require_once 'Zend/Dojo/Exception.php';
       
   374             throw new Zend_Dojo_Exception('Serialization requires that an identifier be present in the object; first call setIdentifier()');
       
   375         }
       
   376 
       
   377         $array = array(
       
   378             'identifier' => $identifier,
       
   379             'items'      => array_values($this->getItems()),
       
   380         );
       
   381 
       
   382         $metadata = $this->getMetadata();
       
   383         if (!empty($metadata)) {
       
   384             foreach ($metadata as $key => $value) {
       
   385                 $array[$key] = $value;
       
   386             }
       
   387         }
       
   388 
       
   389         if (null !== ($label = $this->getLabel())) {
       
   390             $array['label'] = $label;
       
   391         }
       
   392 
       
   393         return $array;
       
   394     }
       
   395 
       
   396     /**
       
   397      * Serialize to JSON (dojo.data format)
       
   398      *
       
   399      * @return string
       
   400      */
       
   401     public function toJson()
       
   402     {
       
   403         require_once 'Zend/Json.php';
       
   404         return Zend_Json::encode($this->toArray());
       
   405     }
       
   406 
       
   407     /**
       
   408      * Serialize to string (proxy to {@link toJson()})
       
   409      *
       
   410      * @return string
       
   411      */
       
   412     public function __toString()
       
   413     {
       
   414         return $this->toJson();
       
   415     }
       
   416 
       
   417     /**
       
   418      * ArrayAccess: does offset exist?
       
   419      *
       
   420      * @param  string|int $offset
       
   421      * @return bool
       
   422      */
       
   423     public function offsetExists($offset)
       
   424     {
       
   425         return (null !== $this->getItem($offset));
       
   426     }
       
   427 
       
   428     /**
       
   429      * ArrayAccess: retrieve by offset
       
   430      *
       
   431      * @param  string|int $offset
       
   432      * @return array
       
   433      */
       
   434     public function offsetGet($offset)
       
   435     {
       
   436         return $this->getItem($offset);
       
   437     }
       
   438 
       
   439     /**
       
   440      * ArrayAccess: set value by offset
       
   441      *
       
   442      * @param  string $offset
       
   443      * @param  array|object|null $value
       
   444      * @return void
       
   445      */
       
   446     public function offsetSet($offset, $value)
       
   447     {
       
   448         $this->setItem($value, $offset);
       
   449     }
       
   450 
       
   451     /**
       
   452      * ArrayAccess: unset value by offset
       
   453      *
       
   454      * @param  string $offset
       
   455      * @return void
       
   456      */
       
   457     public function offsetUnset($offset)
       
   458     {
       
   459         $this->removeItem($offset);
       
   460     }
       
   461 
       
   462     /**
       
   463      * Iterator: get current value
       
   464      *
       
   465      * @return array
       
   466      */
       
   467     public function current()
       
   468     {
       
   469         return current($this->_items);
       
   470     }
       
   471 
       
   472     /**
       
   473      * Iterator: get current key
       
   474      *
       
   475      * @return string|int
       
   476      */
       
   477     public function key()
       
   478     {
       
   479         return key($this->_items);
       
   480     }
       
   481 
       
   482     /**
       
   483      * Iterator: get next item
       
   484      *
       
   485      * @return void
       
   486      */
       
   487     public function next()
       
   488     {
       
   489         return next($this->_items);
       
   490     }
       
   491 
       
   492     /**
       
   493      * Iterator: rewind to first value in collection
       
   494      *
       
   495      * @return void
       
   496      */
       
   497     public function rewind()
       
   498     {
       
   499         return reset($this->_items);
       
   500     }
       
   501 
       
   502     /**
       
   503      * Iterator: is item valid?
       
   504      *
       
   505      * @return bool
       
   506      */
       
   507     public function valid()
       
   508     {
       
   509         return (bool) $this->current();
       
   510     }
       
   511 
       
   512     /**
       
   513      * Countable: how many items are present
       
   514      *
       
   515      * @return int
       
   516      */
       
   517     public function count()
       
   518     {
       
   519         return count($this->_items);
       
   520     }
       
   521 
       
   522     /**
       
   523      * Normalize an item to attach to the collection
       
   524      *
       
   525      * @param  array|object $item
       
   526      * @param  string|int|null $id
       
   527      * @return array
       
   528      */
       
   529     protected function _normalizeItem($item, $id)
       
   530     {
       
   531         if (null === ($identifier = $this->getIdentifier())) {
       
   532             require_once 'Zend/Dojo/Exception.php';
       
   533             throw new Zend_Dojo_Exception('You must set an identifier prior to adding items');
       
   534         }
       
   535 
       
   536         if (!is_object($item) && !is_array($item)) {
       
   537             require_once 'Zend/Dojo/Exception.php';
       
   538             throw new Zend_Dojo_Exception('Only arrays and objects may be attached');
       
   539         }
       
   540 
       
   541         if (is_object($item)) {
       
   542             if (method_exists($item, 'toArray')) {
       
   543                 $item = $item->toArray();
       
   544             } else {
       
   545                 $item = get_object_vars($item);
       
   546             }
       
   547         }
       
   548 
       
   549         if ((null === $id) && !array_key_exists($identifier, $item)) {
       
   550             require_once 'Zend/Dojo/Exception.php';
       
   551             throw new Zend_Dojo_Exception('Item must contain a column matching the currently set identifier');
       
   552         } elseif (null === $id) {
       
   553             $id = $item[$identifier];
       
   554         } else {
       
   555             $item[$identifier] = $id;
       
   556         }
       
   557 
       
   558         return array(
       
   559             'id'   => $id,
       
   560             'data' => $item,
       
   561         );
       
   562     }
       
   563 }