Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
data.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Platform
4  * @subpackage Data
5  *
6  * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
7  * @license GNU General Public License version 2 or later; see LICENSE
8  */
9 
10 defined('JPATH_PLATFORM') or die;
11 
12 /**
13  * JData is a class that is used to store data but allowing you to access the data
14  * by mimicking the way PHP handles class properties.
15  *
16  * @package Joomla.Platform
17  * @subpackage Data
18  * @since 12.3
19  */
20 class JData implements JDataDumpable, IteratorAggregate, JsonSerializable, Countable
21 {
22  /**
23  * The data properties.
24  *
25  * @var array
26  * @since 12.3
27  */
28  private $_properties = array();
29 
30  /**
31  * The class constructor.
32  *
33  * @param mixed $properties Either an associative array or another object
34  * by which to set the initial properties of the new object.
35  *
36  * @since 12.3
37  * @throws InvalidArgumentException
38  */
39  public function __construct($properties = array())
40  {
41  // Check the properties input.
42  if (!empty($properties))
43  {
44  // Bind the properties.
45  $this->bind($properties);
46  }
47  }
48 
49  /**
50  * The magic get method is used to get a data property.
51  *
52  * This method is a public proxy for the protected getProperty method.
53  *
54  * Note: Magic __get does not allow recursive calls. This can be tricky because the error generated by recursing into
55  * __get is "Undefined property: {CLASS}::{PROPERTY}" which is misleading. This is relevant for this class because
56  * requesting a non-visible property can trigger a call to a sub-function. If that references the property directly in
57  * the object, it will cause a recursion into __get.
58  *
59  * @param string $property The name of the data property.
60  *
61  * @return mixed The value of the data property, or null if the data property does not exist.
62  *
63  * @see JData::getProperty()
64  * @since 12.3
65  */
66  public function __get($property)
67  {
68  return $this->getProperty($property);
69  }
70 
71  /**
72  * The magic isset method is used to check the state of an object property.
73  *
74  * @param string $property The name of the data property.
75  *
76  * @return boolean True if set, otherwise false is returned.
77  *
78  * @since 12.3
79  */
80  public function __isset($property)
81  {
82  return isset($this->_properties[$property]);
83  }
84 
85  /**
86  * The magic set method is used to set a data property.
87  *
88  * This is a public proxy for the protected setProperty method.
89  *
90  * @param string $property The name of the data property.
91  * @param mixed $value The value to give the data property.
92  *
93  * @return void
94  *
95  * @see JData::setProperty()
96  * @since 12.3
97  */
98  public function __set($property, $value)
99  {
100  $this->setProperty($property, $value);
101  }
102 
103  /**
104  * The magic unset method is used to unset a data property.
105  *
106  * @param string $property The name of the data property.
107  *
108  * @return void
109  *
110  * @since 12.3
111  */
112  public function __unset($property)
113  {
114  unset($this->_properties[$property]);
115  }
116 
117  /**
118  * Binds an array or object to this object.
119  *
120  * @param mixed $properties An associative array of properties or an object.
121  * @param boolean $updateNulls True to bind null values, false to ignore null values.
122  *
123  * @return JData Returns itself to allow chaining.
124  *
125  * @since 12.3
126  * @throws InvalidArgumentException
127  */
128  public function bind($properties, $updateNulls = true)
129  {
130  // Check the properties data type.
131  if (!is_array($properties) && !is_object($properties))
132  {
133  throw new InvalidArgumentException(sprintf('%s(%s)', __METHOD__, gettype($properties)));
134  }
135 
136  // Check if the object is traversable.
137  if ($properties instanceof Traversable)
138  {
139  // Convert iterator to array.
140  $properties = iterator_to_array($properties);
141  }
142  // Check if the object needs to be converted to an array.
143  elseif (is_object($properties))
144  {
145  // Convert properties to an array.
146  $properties = (array) $properties;
147  }
148 
149  // Bind the properties.
150  foreach ($properties as $property => $value)
151  {
152  // Check if the value is null and should be bound.
153  if ($value === null && !$updateNulls)
154  {
155  continue;
156  }
157 
158  // Set the property.
159  $this->setProperty($property, $value);
160  }
161 
162  return $this;
163  }
164 
165  /**
166  * Dumps the data properties into a stdClass object, recursively if appropriate.
167  *
168  * @param integer $depth The maximum depth of recursion (default = 3).
169  * For example, a depth of 0 will return a stdClass with all the properties in native
170  * form. A depth of 1 will recurse into the first level of properties only.
171  * @param SplObjectStorage $dumped An array of already serialized objects that is used to avoid infinite loops.
172  *
173  * @return stdClass The data properties as a simple PHP stdClass object.
174  *
175  * @since 12.3
176  */
177  public function dump($depth = 3, SplObjectStorage $dumped = null)
178  {
179  // Check if we should initialise the recursion tracker.
180  if ($dumped === null)
181  {
182  $dumped = new SplObjectStorage;
183  }
184 
185  // Add this object to the dumped stack.
186  $dumped->attach($this);
187 
188  // Setup a container.
189  $dump = new stdClass;
190 
191  // Dump all object properties.
192  foreach (array_keys($this->_properties) as $property)
193  {
194  // Get the property.
195  $dump->$property = $this->dumpProperty($property, $depth, $dumped);
196  }
197 
198  return $dump;
199  }
200 
201  /**
202  * Gets this object represented as an ArrayIterator.
203  *
204  * This allows the data properties to be access via a foreach statement.
205  *
206  * @return ArrayIterator This object represented as an ArrayIterator.
207  *
208  * @see IteratorAggregate::getIterator()
209  * @since 12.3
210  */
211  public function getIterator()
212  {
213  return new ArrayIterator($this->dump(0));
214  }
215 
216  /**
217  * Gets the data properties in a form that can be serialised to JSON format.
218  *
219  * @return string An object that can be serialised by json_encode().
220  *
221  * @since 12.3
222  */
223  public function jsonSerialize()
224  {
225  return $this->dump();
226  }
227 
228  /**
229  * Dumps a data property.
230  *
231  * If recursion is set, this method will dump any object implementing JDumpable (like JData and JDataSet); it will
232  * convert a JDate object to a string; and it will convert a JRegistry to an object.
233  *
234  * @param string $property The name of the data property.
235  * @param integer $depth The current depth of recursion (a value of 0 will ignore recursion).
236  * @param SplObjectStorage $dumped An array of already serialized objects that is used to avoid infinite loops.
237  *
238  * @return mixed The value of the dumped property.
239  *
240  * @since 12.3
241  */
242  protected function dumpProperty($property, $depth, SplObjectStorage $dumped)
243  {
244  $value = $this->getProperty($property);
245 
246  if ($depth > 0)
247  {
248  // Check if the object is also an dumpable object.
249  if ($value instanceof JDataDumpable)
250  {
251  // Do not dump the property if it has already been dumped.
252  if (!$dumped->contains($value))
253  {
254  $value = $value->dump($depth - 1, $dumped);
255  }
256  }
257 
258  // Check if the object is a date.
259  if ($value instanceof JDate)
260  {
261  $value = (string) $value;
262  }
263  // Check if the object is a registry.
264  elseif ($value instanceof JRegistry)
265  {
266  $value = $value->toObject();
267  }
268  }
269 
270  return $value;
271  }
272 
273  /**
274  * Gets a data property.
275  *
276  * @param string $property The name of the data property.
277  *
278  * @return mixed The value of the data property.
279  *
280  * @see JData::__get()
281  * @since 12.3
282  */
283  protected function getProperty($property)
284  {
285  // Get the raw value.
286  $value = array_key_exists($property, $this->_properties) ? $this->_properties[$property] : null;
287 
288  return $value;
289  }
290 
291  /**
292  * Sets a data property.
293  *
294  * If the name of the property starts with a null byte, this method will return null.
295  *
296  * @param string $property The name of the data property.
297  * @param mixed $value The value to give the data property.
298  *
299  * @return mixed The value of the data property.
300  *
301  * @see JData::__set()
302  * @since 12.3
303  */
304  protected function setProperty($property, $value)
305  {
306  /*
307  * Check if the property starts with a null byte. If so, discard it because a later attempt to try to access it
308  * can cause a fatal error. See http://us3.php.net/manual/en/language.types.array.php#language.types.array.casting
309  */
310  if (strpos($property, "\0") === 0)
311  {
312  return null;
313  }
314 
315  // Set the value.
316  $this->_properties[$property] = $value;
317 
318  return $value;
319  }
320 
321  /**
322  * Count the number of data properties.
323  *
324  * @return integer The number of data properties.
325  *
326  * @since 12.3
327  */
328  public function count()
329  {
330  return count($this->_properties);
331  }
332 }