Issues

ZF-11947: Zend_GData does not handle major protocol version 2 correctly when building dom tree

Issue Type: Bug Created: 2011-12-17T23:44:58.000+0000 Last Updated: 2012-07-06T22:22:11.000+0000 Status: Open Fix version(s): Reporter: Dolf Starreveld (dolfs) Assignee: Trevor Johns (tjohns) Tags: - Zend_Gdata

Related issues: Attachments:

Description

When processing a YouTube response requested with major version 2, some nodes that are clearly present in the XML stream, are not found. Example is entry->getControl() would return null, even though the element is present. I traced this back to an oversight in the following code:

<pre class="highlight">
    protected function takeChildFromDOM($child)
    {
        $absoluteNodeName = $child->namespaceURI . ':' . $child->localName;
        switch ($absoluteNodeName) {
        case $this->lookupNamespace('atom') . ':' . 'entry':
            $newEntry = new $this->_entryClassName($child);
            $newEntry->setHttpClient($this->getHttpClient());
            $newEntry->setMajorProtocolVersion($this->getMajorProtocolVersion());
            $newEntry->setMinorProtocolVersion($this->getMinorProtocolVersion());
            $this->_entry[] = $newEntry;
            break;
        default:
            parent::takeChildFromDOM($child);
            break;
        }
    }

You will note that the protocol version for the new entry is set after it has been created. Its creation, however, recursively processes all the DOM elements under it. During this processing, the entry object believes its protocol version to be the default, which is 1. Consequently some other element lookups will go wrong due to an apparent namespace mismatch:

<pre class="highlight">
        case $this->lookupNamespace('app') . ':' . 'control':

The namespace is looked up:

<pre class="highlight">
    public function lookupNamespace($prefix,
                                    $majorVersion = null,
                                    $minorVersion = null)
    {
        // Auto-select current version
        if ($majorVersion === null) {
            $majorVersion = $this->getMajorProtocolVersion();
        }
        if ($minorVersion === null) {
            $minorVersion = $this->getMinorProtocolVersion();
        }

        // Perform lookup
        return parent::lookupNamespace($prefix, $majorVersion, $minorVersion);
    }

At the time of the lookup, the entry's protocol version has not yet been set correctly, yet its value affects the lookup of the namespace. In this particular example is not being recognized as the default major protocol version is 1 and thus the namespace does not get recognized (only available in version 2) and the corresponding element is not treated correctly.

My fix has been to change the constructor of all "entry" elements to accept a major and minor version number and to pass them to the constructor of the element:

<pre class="highlight">
    protected function takeChildFromDOM($child)
    {
        $absoluteNodeName = $child->namespaceURI . ':' . $child->localName;
        switch ($absoluteNodeName) {
        case $this->lookupNamespace('atom') . ':' . 'entry':
            $newEntry = new $this->_entryClassName($child, $this->getMajorProtocolVersion(), $this->getMinorProtocolVersion());
            $newEntry->setHttpClient($this->getHttpClient());
            $this->_entry[] = $newEntry;
            break;
        default:
            parent::takeChildFromDOM($child);
            break;
        }
    }

I will not repeat the 5 or 6 cases where the constructor needs to be changed, except at the root level, where the incoming values need to be set (unless null for backward compatability):

<pre class="highlight">
    public function __construct($element = null, $major = null, $minor = null)
    {
        if (!is_null($major)) {
            $this->setMajorProtocolVersion($major);
        }
        if (!is_null($minor)) {
            $this->setMinorProtocolVersion($minor);
        }
        if (!($element instanceof DOMElement)) {
            if ($element) {
                $this->transferFromXML($element);
            }
        } else {
            $this->transferFromDOM($element);
        }
    }

Comments

Posted by R Servus (rservus) on 2012-07-06T22:08:45.000+0000

Yet another place where protocol version is handled wrong

<pre class="highlight">
protected function takeChildFromDOM($child)
    {
        $absoluteNodeName = $child->namespaceURI . ':' . $child->localName;
        switch ($absoluteNodeName) {
        case $this->lookupNamespace('app') . ':' . 'draft':
            $draft = new Zend_Gdata_App_Extension_Draft();
            $draft->transferFromDOM($child);
            $this->_draft = $draft;
            break;
        default:
            parent::takeChildFromDOM($child);
            break;
        }
    }

and now look at the lookupNamespace method, which always use version majorVersion = 1

<pre class="highlight">
public function lookupNamespace($prefix,
                                    $majorVersion = 1,
                                    $minorVersion = null)
    {
        // Check for a memoized result
        $key = $prefix . ' ' .
               ($majorVersion === null ? 'NULL' : $majorVersion) .
               ' '. ($minorVersion === null ? 'NULL' : $minorVersion);

Simple search over library code for lookupNamespace and majorVersion gets a lot of possible issues with protocol 2 support. Looks like v2 support is completely broken in current version of library.

Google should clearly state in their documentation that v2 is not only "not enabled yet" but is unsupported.

{quote} As of version 1.7.4 of the PHP Client Library, the version 2 specific functionality has not yet been enabled by default. You can use the setMajorProtocolVersion function to set a version for either a service class, a feed or an entry. A version 2 specific service class will always return v2 feeds and entries. {quote}

Posted by R Servus (rservus) on 2012-07-06T22:22:11.000+0000

oops, lookupNamespace method is in Zend_Gdata_App_Base

Have you found an issue?

See the Overview section for more details.

Copyright

© 2006-2016 by Zend, a Rogue Wave Company. Made with by awesome contributors.

This website is built using zend-expressive and it runs on PHP 7.

Contacts