PageRenderTime 40ms CodeModel.GetById 10ms app.highlight 18ms RepoModel.GetById 2ms app.codeStats 0ms

/zf/library/Zend/Gdata/App/Base.php

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