Rojakcoder
Of Linux, Programming, and Singaporean Ramblings

Improvements to Zend Framework Gdata for Docs ACL

Sat, Aug 27, 2011 1:44PM +0800

This post is going to be about the modifications I’ve made to the Zend Framework’s Gdata library for accessing Google Docs.

As early as 2008, I think, Google has made feeds available for ACL manipulation of Google Docs. However, the Zend Framework library hasn’t caught up with the speed of development with Google – there were other higher priorities for the open source community.

This post here attempts to briefly explain the modifications so that it is easier for someone else to pick up and bring about more modifications to Zend Framework’s Gdata library (and for me to remember how to navigate the spaghetti classes that is in Gdata). In this patch (diffed from 24410) here are the changes that will add ACL modification to Google Docs in Zend Framework. The change also includes the capability to make bulk changes to documents.

I also want to make use of this post to explain the reasons for including certain tests and values into the project. I hope that the project leads for Gdata (Joachen and Trevor?) can find it easy to understand the changes I’ve made and the rationale for doing. Hopefully, this blog will also provide a easy manner for discussion to take place if ever necessary.

Overview

To allow Google Docs to make changes to the ACL, a new set of ACL classes have to be added to represent the ACL rules. These classes can be found in the /library/Zend/Gdata/Acl directory. These classes represent the ACL entities directly. However, there is also a need to create classes pertaining to the ACL rules specific to Docs. These classes are Zend_Gdata_Docs_AclEntry and Zend_Gdata_Docs_AclFeed.

In addition to these, because performing a change is a relatively expensive (in terms of time and bandwidth) operation, Google does provide the option to perform batch operations for ACL changes. To facilitate these, therefore, a corresponding set of classes also need to be added under the directory /library/Zend/Gdata/Batch. Therefore, the classes Zend_Gdata_Docs_BatchAclEntry and Zend_Gdata_BatchAclFeed are needed to be created as well.

Tests & Other Modifications (for project leads)

I’ve modified TestConfiguration.php.dist to add two more constants: TESTS_ZEND_GDATA_DOCS_DOCUMENTTITLE and TESTS_ZEND_GDATA_DOCS_DOCUMENTSHARE. These two are used to perform the online tests. The former is used as the title for identifying a document to modify its sharing settings and the latter is used as the user ID for whom the share is given to. The latter necessarily has to be a Gmail account (I’m not sure if an account hosted on Google Apps will or not though.)

I’ve also modified Zend_Gdata_App to change the docblock for the delete() method that says “return void” to “return Zend_Http_Response”.

I’ve also modified a few lines in Zend_Gdata_Docs that hard codes the URL to using a static constant.

I can’t remember why but I’ve changed the separation of the file parts from using explode() under uploadFile() to first getting the slug and then separating on it. I think it’s because the slug contains a more accurate value?

The “offline” and online tests are updated to cover 100% of the affected classes in this patch.

Actual Classes

Zend_Gdata_Acl_Role

This class represents the role a user may adopt with reference to accessing a document. Its root name space is “gAcl” and the corresponding XML element is named “role”. The actual value of the element is stored in its “value” attribute.

Zend_Gdata_Acl_Scope

The user entity that has access to the document is represented by the element with two attributes: “type” and “value”. The “value” attribute stores the actual user ID. At present, the only “type” value I know of is “user”. There must be a different value for this attribute to indicate a group as the user.

Zend_Gdata_Batch (/library/Zend/Gdata/Batch.php)

This is a new class to represent the Batch extension to Gdata. It is an abstract class setting the root namespace to “batch” for inheriting classes.

Zend_Gdata_Batch_Id

This class represents the batch ID for insert-type batch operations. This is needed for insert-type operations and can be optionally used to identify other batch operations as well. Because the value is stored as the text node, when retrieving this element’s value, you can do so like this:

$id = new Zend_Gdata_Batch_Id('1');
echo $id->text;  //outputs 1

Zend_Gdata_Batch_Operation

This class represents the XML entry to identify the batch operation type. Accepted types are insert, update, delete and query.

Zend_Gdata_Batch_Status

The <status> element of the returned feed from batch processing. According to the documentation, it seems that there are just the “reason” and “code” attributes. However, for some reason, I recall that earlier somewhere, there could be a “content-type” attribute as well. This is why “content-type” is a property of this class even though the batch operation document does not indicate that it is there.

Zend_Gdata_Docs_AclEntry

Both ACL role and scope are contained within this class to represent an ACL entry for Docs.

Zend_Gdata_Docs_AclFeed

The feed class is necessary to contain the entries.

Zend_Gdata_Docs_AclQuery

This class helps to format the URL for querying Google servers.

Zend_Gdata_Docs_BatchAclEntry

This entry encompasses the Id, Operation and Status elements to present an entry in the batch feed.

Zend_Gdata_Docs_BatchAclFeed

The feed is necessary to contain the batch ACL entries.

Zend_Gdata_Docs

A static property $namespaces is added to this class to specify the namespaces for ‘gd’, ‘openSearch’, ‘rss’ and ‘gAcl’.

A private property $_batchOperations is used to store batch operations.

In the constructor for this class the “Zend_Gdata_Acl” class is registered as a package for this class.

getAclFeed()

The method getAclFeed() being added to Zend_Gdata_Docs retrieves the ACL feed containing the information about the ACL entries for the document (see [http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#AccessControlLists]{http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#AccessControlLists) for an example of the feed). This method accepts a single argument that can either be an instance of Zend_Gdata_Docs_DocumentListEntry or the URL of the feed itself. If it is the former, the method will attempt to get the URL from the extension element “feedLink” of the instance. Finally, an instance of Zend_Gdata_Docs_AclFeed is returned from this method. From the returned feed, you can iterate through each of the entries to retrieve the scope and role of the entries (more on this later).

insertAcl()

This method accepts two parameters to add an ACL rule to the document. One is the ACL entry instance (Zend_Gdata_Docs_AclEntry) and the other is either the ACL URI of the document or instance of Zend_Gdata_Docs_DocumentListEntry. Similar to getAclFeed(), this method knows to iterate through the extension elements looking for the “feedLink” element that is the ACL URL of the document.

updateAcl()

This method provides a higher level of abstraction on the functions than other methods. It accepts the document followed by the user name and role for the user to be updated. (I cannot remember exactly what happens if you specify a user that does not have any rights to the document. Someone who has tried it can probably post in the comments?) This method then generates the necessary objects to make the call to update.

deleteAcl()

Deleting an ACL entry is different from the insert and update actions because there is no need to construct any entry objects for it – instead the URL needs to be crafted correctly so that the DELETE request is able to target the document and ACL entry correctly. This method does that for you and simply requires the user ID as a string to do so in addition to the document.

addBatchAclEntry()

This method lets you aggregate different ACL actions into a single HTTP request so that it is more effective in terms of performance. This method, however, does not send immediately send the operation request to Google’s servers when called. What it does is that it appends the ACL operations into a private internal property (_batchOperations) everytime it is called. Therefore, you can correspondingly clear this private property (through clearBatchAclEntries()). When the appropriate ACL entries are aggregated, you can call the following method to effect the change.

doBatchAcl()

This method invokes the actual HTTP request to send the batch requests over to Google’s servers.

After sending the request, this method clears the internal storage by calling the clearBatchAclEntries() method so that the next time the batch request is sent, it doesn’t send the same actions again.

comments powered by Disqus