source: trunk/www.guidonia.net/wp/wp-content/plugins/webtv/Drivers/Zend/Gdata/App/Base.php@ 44

Last change on this file since 44 was 44, checked in by luciano, 14 years ago
File size: 18.8 KB
Line 
1<?php
2
3/**
4 * Zend Framework
5 *
6 * LICENSE
7 *
8 * This source file is subject to the new BSD license that is bundled
9 * with this package in the file LICENSE.txt.
10 * It is also available through the world-wide-web at this URL:
11 * http://framework.zend.com/license/new-bsd
12 * If you did not receive a copy of the license and are unable to
13 * obtain it through the world-wide-web, please send an email
14 * to license@zend.com so we can send you a copy immediately.
15 *
16 * @category Zend
17 * @package Zend_Gdata
18 * @subpackage App
19 * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
20 * @license http://framework.zend.com/license/new-bsd New BSD License
21 */
22
23/**
24 * @see Zend_Gdata_App_Util
25 */
26require_once 'Zend/Gdata/App/Util.php';
27
28/**
29 * Abstract class for all XML elements
30 *
31 * @category Zend
32 * @package Zend_Gdata
33 * @subpackage App
34 * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
35 * @license http://framework.zend.com/license/new-bsd New BSD License
36 */
37abstract class Zend_Gdata_App_Base
38{
39
40 /**
41 * @var string The XML element name, including prefix if desired
42 */
43 protected $_rootElement = null;
44
45 /**
46 * @var string The XML namespace prefix
47 */
48 protected $_rootNamespace = 'atom';
49
50 /**
51 * @var string The XML namespace URI - takes precedence over lookup up the
52 * corresponding URI for $_rootNamespace
53 */
54 protected $_rootNamespaceURI = null;
55
56 /**
57 * @var array Leftover elements which were not handled
58 */
59 protected $_extensionElements = array();
60
61 /**
62 * @var array Leftover attributes which were not handled
63 */
64 protected $_extensionAttributes = array();
65
66 /**
67 * @var string XML child text node content
68 */
69 protected $_text = null;
70
71 /**
72 * @var array Memoized results from calls to lookupNamespace() to avoid
73 * expensive calls to getGreatestBoundedValue(). The key is in the
74 * form 'prefix-majorVersion-minorVersion', and the value is the
75 * output from getGreatestBoundedValue().
76 */
77 protected static $_namespaceLookupCache = array();
78
79 /**
80 * List of namespaces, as a three-dimensional array. The first dimension
81 * represents the namespace prefix, the second dimension represents the
82 * minimum major protocol version, and the third dimension is the minimum
83 * minor protocol version. Null keys are NOT allowed.
84 *
85 * When looking up a namespace for a given prefix, the greatest version
86 * number (both major and minor) which is less than the effective version
87 * should be used.
88 *
89 * @see lookupNamespace()
90 * @see registerNamespace()
91 * @see registerAllNamespaces()
92 * @var array
93 */
94 protected $_namespaces = array(
95 'atom' => array(
96 1 => array(
97 0 => 'http://www.w3.org/2005/Atom'
98 )
99 ),
100 'app' => array(
101 1 => array(
102 0 => 'http://purl.org/atom/app#'
103 ),
104 2 => array(
105 0 => 'http://www.w3.org/2007/app'
106 )
107 )
108 );
109
110 public function __construct()
111 {
112 }
113
114 /**
115 * Returns the child text node of this element
116 * This represents any raw text contained within the XML element
117 *
118 * @return string Child text node
119 */
120 public function getText($trim = true)
121 {
122 if ($trim) {
123 return trim($this->_text);
124 } else {
125 return $this->_text;
126 }
127 }
128
129 /**
130 * Sets the child text node of this element
131 * This represents any raw text contained within the XML element
132 *
133 * @param string $value Child text node
134 * @return Zend_Gdata_App_Base Returns an object of the same type as 'this' to provide a fluent interface.
135 */
136 public function setText($value)
137 {
138 $this->_text = $value;
139 return $this;
140 }
141
142 /**
143 * Returns an array of all elements not matched to data model classes
144 * during the parsing of the XML
145 *
146 * @return array All elements not matched to data model classes during parsing
147 */
148 public function getExtensionElements()
149 {
150 return $this->_extensionElements;
151 }
152
153 /**
154 * Sets an array of all elements not matched to data model classes
155 * during the parsing of the XML. This method can be used to add arbitrary
156 * child XML elements to any data model class.
157 *
158 * @param array $value All extension elements
159 * @return Zend_Gdata_App_Base Returns an object of the same type as 'this' to provide a fluent interface.
160 */
161 public function setExtensionElements($value)
162 {
163 $this->_extensionElements = $value;
164 return $this;
165 }
166
167 /**
168 * Returns an array of all extension attributes not transformed into data
169 * model properties during parsing of the XML. Each element of the array
170 * is a hashed array of the format:
171 * array('namespaceUri' => string, 'name' => string, 'value' => string);
172 *
173 * @return array All extension attributes
174 */
175 public function getExtensionAttributes()
176 {
177 return $this->_extensionAttributes;
178 }
179
180 /**
181 * Sets an array of all extension attributes not transformed into data
182 * model properties during parsing of the XML. Each element of the array
183 * is a hashed array of the format:
184 * array('namespaceUri' => string, 'name' => string, 'value' => string);
185 * This can be used to add arbitrary attributes to any data model element
186 *
187 * @param array $value All extension attributes
188 * @return Zend_Gdata_App_Base Returns an object of the same type as 'this' to provide a fluent interface.
189 */
190 public function setExtensionAttributes($value)
191 {
192 $this->_extensionAttributes = $value;
193 return $this;
194 }
195
196 /**
197 * Retrieves a DOMElement which corresponds to this element and all
198 * child properties. This is used to build an entry back into a DOM
199 * and eventually XML text for sending to the server upon updates, or
200 * for application storage/persistence.
201 *
202 * @param DOMDocument $doc The DOMDocument used to construct DOMElements
203 * @return DOMElement The DOMElement representing this element and all
204 * child properties.
205 */
206 public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null)
207 {
208 if ($doc === null) {
209 $doc = new DOMDocument('1.0', 'utf-8');
210 }
211 if ($this->_rootNamespaceURI != null) {
212 $element = $doc->createElementNS($this->_rootNamespaceURI, $this->_rootElement);
213 } elseif ($this->_rootNamespace !== null) {
214 if (strpos($this->_rootElement, ':') === false) {
215 $elementName = $this->_rootNamespace . ':' . $this->_rootElement;
216 } else {
217 $elementName = $this->_rootElement;
218 }
219 $element = $doc->createElementNS($this->lookupNamespace($this->_rootNamespace), $elementName);
220 } else {
221 $element = $doc->createElement($this->_rootElement);
222 }
223 if ($this->_text != null) {
224 $element->appendChild($element->ownerDocument->createTextNode($this->_text));
225 }
226 foreach ($this->_extensionElements as $extensionElement) {
227 $element->appendChild($extensionElement->getDOM($element->ownerDocument));
228 }
229 foreach ($this->_extensionAttributes as $attribute) {
230 $element->setAttribute($attribute['name'], $attribute['value']);
231 }
232 return $element;
233 }
234
235 /**
236 * Given a child DOMNode, tries to determine how to map the data into
237 * object instance members. If no mapping is defined, Extension_Element
238 * objects are created and stored in an array.
239 *
240 * @param DOMNode $child The DOMNode needed to be handled
241 */
242 protected function takeChildFromDOM($child)
243 {
244 if ($child->nodeType == XML_TEXT_NODE) {
245 $this->_text = $child->nodeValue;
246 } else {
247 $extensionElement = new Zend_Gdata_App_Extension_Element();
248 $extensionElement->transferFromDOM($child);
249 $this->_extensionElements[] = $extensionElement;
250 }
251 }
252
253 /**
254 * Given a DOMNode representing an attribute, tries to map the data into
255 * instance members. If no mapping is defined, the name and value are
256 * stored in an array.
257 *
258 * @param DOMNode $attribute The DOMNode attribute needed to be handled
259 */
260 protected function takeAttributeFromDOM($attribute)
261 {
262 $arrayIndex = ($attribute->namespaceURI != '')?(
263 $attribute->namespaceURI . ':' . $attribute->name):
264 $attribute->name;
265 $this->_extensionAttributes[$arrayIndex] =
266 array('namespaceUri' => $attribute->namespaceURI,
267 'name' => $attribute->localName,
268 'value' => $attribute->nodeValue);
269 }
270
271 /**
272 * Transfers each child and attribute into member variables.
273 * This is called when XML is received over the wire and the data
274 * model needs to be built to represent this XML.
275 *
276 * @param DOMNode $node The DOMNode that represents this object's data
277 */
278 public function transferFromDOM($node)
279 {
280 foreach ($node->childNodes as $child) {
281 $this->takeChildFromDOM($child);
282 }
283 foreach ($node->attributes as $attribute) {
284 $this->takeAttributeFromDOM($attribute);
285 }
286 }
287
288 /**
289 * Parses the provided XML text and generates data model classes for
290 * each know element by turning the XML text into a DOM tree and calling
291 * transferFromDOM($element). The first data model element with the same
292 * name as $this->_rootElement is used and the child elements are
293 * recursively parsed.
294 *
295 * @param string $xml The XML text to parse
296 */
297 public function transferFromXML($xml)
298 {
299 if ($xml) {
300 // Load the feed as an XML DOMDocument object
301 @ini_set('track_errors', 1);
302 $doc = new DOMDocument();
303 $success = @$doc->loadXML($xml);
304 @ini_restore('track_errors');
305 if (!$success) {
306 require_once 'Zend/Gdata/App/Exception.php';
307 throw new Zend_Gdata_App_Exception("DOMDocument cannot parse XML: $php_errormsg");
308 }
309 $element = $doc->getElementsByTagName($this->_rootElement)->item(0);
310 if (!$element) {
311 require_once 'Zend/Gdata/App/Exception.php';
312 throw new Zend_Gdata_App_Exception('No root <' . $this->_rootElement . '> element');
313 }
314 $this->transferFromDOM($element);
315 } else {
316 require_once 'Zend/Gdata/App/Exception.php';
317 throw new Zend_Gdata_App_Exception('XML passed to transferFromXML cannot be null');
318 }
319 }
320
321 /**
322 * Converts this element and all children into XML text using getDOM()
323 *
324 * @return string XML content
325 */
326 public function saveXML()
327 {
328 $element = $this->getDOM();
329 return $element->ownerDocument->saveXML($element);
330 }
331
332 /**
333 * Alias for saveXML() returns XML content for this element and all
334 * children
335 *
336 * @return string XML content
337 */
338 public function getXML()
339 {
340 return $this->saveXML();
341 }
342
343 /**
344 * Alias for saveXML()
345 *
346 * Can be overridden by children to provide more complex representations
347 * of entries.
348 *
349 * @return string Encoded string content
350 */
351 public function encode()
352 {
353 return $this->saveXML();
354 }
355
356 /**
357 * Get the full version of a namespace prefix
358 *
359 * Looks up a prefix (atom:, etc.) in the list of registered
360 * namespaces and returns the full namespace URI if
361 * available. Returns the prefix, unmodified, if it's not
362 * registered.
363 *
364 * @param string $prefix The namespace prefix to lookup.
365 * @param integer $majorVersion The major protocol version in effect.
366 * Defaults to '1'.
367 * @param integer $minorVersion The minor protocol version in effect.
368 * Defaults to null (use latest).
369 * @return string
370 */
371 public function lookupNamespace($prefix,
372 $majorVersion = 1,
373 $minorVersion = null)
374 {
375 // Check for a memoized result
376 $key = $prefix . ' ' .
377 (is_null($majorVersion) ? 'NULL' : $majorVersion) .
378 ' '. (is_null($minorVersion) ? 'NULL' : $minorVersion);
379 if (array_key_exists($key, self::$_namespaceLookupCache))
380 return self::$_namespaceLookupCache[$key];
381 // If no match, return the prefix by default
382 $result = $prefix;
383
384 // Find tuple of keys that correspond to the namespace we should use
385 if (isset($this->_namespaces[$prefix])) {
386 // Major version search
387 $nsData = $this->_namespaces[$prefix];
388 $foundMajorV = Zend_Gdata_App_Util::findGreatestBoundedValue(
389 $majorVersion, $nsData);
390 // Minor version search
391 $nsData = $nsData[$foundMajorV];
392 $foundMinorV = Zend_Gdata_App_Util::findGreatestBoundedValue(
393 $minorVersion, $nsData);
394 // Extract NS
395 $result = $nsData[$foundMinorV];
396 }
397
398 // Memoize result
399 self::$_namespaceLookupCache[$key] = $result;
400
401 return $result;
402 }
403
404 /**
405 * Add a namespace and prefix to the registered list
406 *
407 * Takes a prefix and a full namespace URI and adds them to the
408 * list of registered namespaces for use by
409 * $this->lookupNamespace().
410 *
411 * WARNING: Currently, registering a namespace will NOT invalidate any
412 * memoized data stored in $_namespaceLookupCache. Under normal
413 * use, this behavior is acceptable. If you are adding
414 * contradictory data to the namespace lookup table, you must
415 * call flushNamespaceLookupCache().
416 *
417 * @param string $prefix The namespace prefix
418 * @param string $namespaceUri The full namespace URI
419 * @param integer $majorVersion The major protocol version in effect.
420 * Defaults to '1'.
421 * @param integer $minorVersion The minor protocol version in effect.
422 * Defaults to null (use latest).
423 * @return void
424 */
425 public function registerNamespace($prefix,
426 $namespaceUri,
427 $majorVersion = 1,
428 $minorVersion = 0)
429 {
430 $this->_namespaces[$prefix][$majorVersion][$minorVersion] =
431 $namespaceUri;
432 }
433
434 /**
435 * Flush namespace lookup cache.
436 *
437 * Empties the namespace lookup cache. Call this function if you have
438 * added data to the namespace lookup table that contradicts values that
439 * may have been cached during a previous call to lookupNamespace().
440 */
441 public static function flushNamespaceLookupCache()
442 {
443 self::$_namespaceLookupCache = array();
444 }
445
446 /**
447 * Add an array of namespaces to the registered list.
448 *
449 * Takes an array in the format of:
450 * namespace prefix, namespace URI, major protocol version,
451 * minor protocol version and adds them with calls to ->registerNamespace()
452 *
453 * @param array $namespaceArray An array of namespaces.
454 * @return void
455 */
456 public function registerAllNamespaces($namespaceArray)
457 {
458 foreach($namespaceArray as $namespace) {
459 $this->registerNamespace(
460 $namespace[0], $namespace[1], $namespace[2], $namespace[3]);
461 }
462 }
463
464
465 /**
466 * Magic getter to allow access like $entry->foo to call $entry->getFoo()
467 * Alternatively, if no getFoo() is defined, but a $_foo protected variable
468 * is defined, this is returned.
469 *
470 * TODO Remove ability to bypass getFoo() methods??
471 *
472 * @param string $name The variable name sought
473 */
474 public function __get($name)
475 {
476 $method = 'get'.ucfirst($name);
477 if (method_exists($this, $method)) {
478 return call_user_func(array(&$this, $method));
479 } else if (property_exists($this, "_${name}")) {
480 return $this->{'_' . $name};
481 } else {
482 require_once 'Zend/Gdata/App/InvalidArgumentException.php';
483 throw new Zend_Gdata_App_InvalidArgumentException(
484 'Property ' . $name . ' does not exist');
485 }
486 }
487
488 /**
489 * Magic setter to allow acces like $entry->foo='bar' to call
490 * $entry->setFoo('bar') automatically.
491 *
492 * Alternatively, if no setFoo() is defined, but a $_foo protected variable
493 * is defined, this is returned.
494 *
495 * TODO Remove ability to bypass getFoo() methods??
496 *
497 * @param string $name
498 * @param string $value
499 */
500 public function __set($name, $val)
501 {
502 $method = 'set'.ucfirst($name);
503 if (method_exists($this, $method)) {
504 return call_user_func(array(&$this, $method), $val);
505 } else if (isset($this->{'_' . $name}) || ($this->{'_' . $name} === null)) {
506 $this->{'_' . $name} = $val;
507 } else {
508 require_once 'Zend/Gdata/App/InvalidArgumentException.php';
509 throw new Zend_Gdata_App_InvalidArgumentException(
510 'Property ' . $name . ' does not exist');
511 }
512 }
513
514 /**
515 * Magic __isset method
516 *
517 * @param string $name
518 */
519 public function __isset($name)
520 {
521 $rc = new ReflectionClass(get_class($this));
522 $privName = '_' . $name;
523 if (!($rc->hasProperty($privName))) {
524 require_once 'Zend/Gdata/App/InvalidArgumentException.php';
525 throw new Zend_Gdata_App_InvalidArgumentException(
526 'Property ' . $name . ' does not exist');
527 } else {
528 if (isset($this->{$privName})) {
529 if (is_array($this->{$privName})) {
530 if (count($this->{$privName}) > 0) {
531 return true;
532 } else {
533 return false;
534 }
535 } else {
536 return true;
537 }
538 } else {
539 return false;
540 }
541 }
542 }
543
544 /**
545 * Magic __unset method
546 *
547 * @param string $name
548 */
549 public function __unset($name)
550 {
551 if (isset($this->{'_' . $name})) {
552 if (is_array($this->{'_' . $name})) {
553 $this->{'_' . $name} = array();
554 } else {
555 $this->{'_' . $name} = null;
556 }
557 }
558 }
559
560 /**
561 * Magic toString method allows using this directly via echo
562 * Works best in PHP >= 4.2.0
563 *
564 * @return string The text representation of this object
565 */
566 public function __toString()
567 {
568 return $this->getText();
569 }
570
571}
Note: See TracBrowser for help on using the repository browser.