~clinton-collins/familyproject/trunk

« back to all changes in this revision

Viewing changes to ZendFramework/library/Zend/Gdata/App/Base.php

  • Committer: Clinton Collins
  • Date: 2009-06-26 19:54:58 UTC
  • Revision ID: clinton.collins@gmail.com-20090626195458-5ebba0qcvo15xlpy
Initial Import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
26
require_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
 */
 
37
abstract 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
}