1.1 - 10 April 2007: Early design notes.
1.2 - 06 May 2007: Ready for review. Code not yet in incubator.
1.3 - 07 May 2007: Code for App, Gdata and Calendar partially in incubator
1.4 - 09 May 2007: First draft of Spreadsheets code in incubator
1.6 - 12 June 2007: 1.0.0 RC2a of Zend_Gdata released with support for Spreadsheets and Calendar. See public docs for usage (as opposed to examples in this document), as the public docs are going to be more accurate. (wiki revision: 68)
This proposal describes enhancements to the Zend_Gdata component to make it more usable and consistent with GData client libraries for other languages (e.g. Python, Java).
3. Component Requirements, Constraints, and Acceptance Criteria
A developer should be able to perform most functionality by looking only at the PHP documentation of classes, methods and a few examples.
A developer should not need to know the structure of the XML documents used by the GData services nor the namespaces, etc in order to use the library effectively
As much consistency as possible should exist between the PHP client library and other GData client libraries, while still maintaining a PHP feel to the library.
The library should be usable by both experts and beginners in GData and PHP.
4. Dependencies on Other Framework Components
Zend_Http
5. Theory of Operation
General Operation
Retrieving Feeds is done through the creation of a Query and Service object. The query object is used to specify the query parameters using standard method calls such as $query->setUpdatedMin('2007-01-01');. The service object is called to retrieve the feed based upon the URL generated by the query object using a call such as $feed = $service->getFeed($query->getQueryUrl()). The service object uses a Zend_Http_Client to retrieve the feed and stores each of the entries as a DOMElement instances. The feed implements the Iterator interface to allow for iterating individual entries. As individual entries are iterated upon, the DOMElements are converted into individual instances of the appropriate Entry class (such as Zend_Gdata_Entry). These entry instances use 3 methods – transferFromDOM(), takeChildFromDOM(), takeAttributeFromDOM() – to store data from the DOM as protected members of the appropriate Entry instance. All entries and attributes that are children of the Atom <entry> are converted into their object equivalents. If elements are not consumed via the takeChildFromDOM() method, they become an instance of Zend_App_Extension_Element.
Retrieving Entries is done in a very similiar fashion as Retrieving Feeds (as described above), except the getEntry() method (or appropriate equivalent) is called on the Service object-- and an individual Entry of the appropriate type is constructed rather than a Feed.
Updating Entries is performed by retrieving the entry from the service, updating the appropriate instance members and saving changes to the entry (causing the associated service to do a HTTP PUT to the entry's edit URL on the server). The member elements can be modified using either the magic _set (such as $entry->title = $service->newTitle('entry title'); method or by callling pre-defined setters (such as $entry->setTitle($service->newTitle('entry title'));. Note the use of the $service->newTitle method to create instances of the Zend_Gdata_App_Extension_Title class. These factory methods (handled by the magic _call() method) are provided only as a conveience-- you could choose to instantiate an instance of the Zend_Gdata_App_Extension_Title class directly. See the use cases below for more information.
Creating Entries is accomplished by creating an instance of the correct Entry class, setting the appropriate instance members and using an authenticated Service class to perform a HTTP POST to the feed's post URL. The entry instance's members are set using the method described above in 'Updating Entries.'
Deleting Entries is accomplished either by directly passing an edit URL to an authenticated Service claass, or by retrieving an individual entry and calling its' delete() method – causing a HTTP DELETE request to be sent to the edit URL.
Services and queries
Remove query parameter functionality from Zend_Gdata, Zend_Gdata_Calendar, Zend_Gdata_spreadsheets, etc and create separate query classes which are used to generate the URL used for querying. This is a more natural model as query parameters can sometimes be used for POSTs. With the current design, if a developer wanted to specify query params for a query, but not for an insert, they would need to either create 2 service objects or clear out the params between the GET and the POST. Moving to having a separate Query class eliminates the need for this and is more in line with the other Google Data APIs client libraries. All service-specific query classes should inherit from Zend_Gdata and provide only those query parameters which are specific to the service.
Zend_Gdata classes should extend from classes providing basic Atom Publishing Protocol (APP) operations such as getEntry, getFeed, post, put, delete etc. This provides the ability for developers to use the Zend Framework to work with generic APP services offered by other companies, organizations, or sites and provide extensions to the Framework to implement any extensions to APP which are used by those services.
Zend_Gdata should remain as a class overriding the important client operation methods to handle the GData-specific versions of Atom Publishing Protocol (APP). This includes methods such as getEntry, getFeed, post, delete, put, etc.
Service classes, such as Zend_Gdata_Calendar, should override Zend_Gdata methods as necessary and implement additional methods such as getCalendarListEntry, getCalendarEventEntry, getCalendarListFeed, getCalendarEventFeed, updateEvent, deleteEvent, insertEvent, etc. These methods would return data model classes of the appropriate type (see data model section below).
Authentication mechanism (using Zend_Gdata_AuthSub/Zend_Gdata_ClientLogin to return a Zend_Http_Client) should remain. Although different than other GData client libraries, this is a very useful way of specifying credentials, configuring proxies, etc. However, some changes need to be made to the authentication mechanism to improve usability - a developer should not need to know the value of the Service parameter used by ClientLogin. Rather, the service class (extending Zend_Gdata) should provide this information.
Inheritance tree:
Zend_Gdata_App- provides basic APP methods such as getFeed(), getEntry(), post(), delete(), put()
Zend_Gdata- provides factory call method for creating data model classes, allows for GData-specific implementations of Zend_Gdata_App functionality
Zend_Gdata_Calendar- provides methods for getting a Zend_Gdata_Calendar_EventFeed via getCalendarEventFeed(), a Zend_Gdata_Calendar_ListFeed via getCalendarListFeed(), insertEvent() etc.
Zend_Gdata_Spreadsheets- provides spreadsheets-specific functionality such as getSpreadsheetsFeed(), getWorksheetsFeed(), updateCell(), insertRow(), etc.
etc.
Zend_Gdata_Query- provides methods for getting/setting the GData-wide query parameters such as q, updated-min, etc methods named like setUpdatedMin(). Also, provides a method to get the URL represented by the Query object.
Zend_Gdata_Calendar_EventQuery- provides additional query parameters that are specific to querying Calendar event feeds. This includes methods like setFutureEvents(), setRecurrenceExpansionStart(), etc.
Zend_Gdata_Calendar_ListQuery- provides additional query parameters that are specific to querying Calendar list (meta) feeds.
Zend_Gdata_Spreadsheets_CellQuery- provides additional query parameters that are specific to querying Spreadsheet Cell feeds, such as setMinRow(), setMaxRow(), etc.
etc.
Data model
Inheritance tree:
Zend_Gdata_App_Base- provides functionality common to feeds, entries and all other data model classes
Zend_Gdata_App_FeedEntryParent- implements functionality common to feeds and entries.
Zend_Gdata_App_Feed- implements functionality required by APP.
Zend_Gdata_Feed- stub to implement additional functionality required by a GData feed.
Zend_Gdata_Calendar_EventFeed- stub to implement additional functionality required by a Calendar event feed.
Zend_Gdata_Calendar_ListFeed- stub to implement additional functionality required by a Calendar list feed.
Zend_Gdata_Spreadsheets_CellFeed- stub to implement additional functionality required by a Spreadsheets cell feed.
...etc
Zend_Gdata_App_Entry- Generic implementations of methods such as construct(), getDOM(), takeChildFromDOM(), takeAttributeFromDOM(), transferFromDOM(), get(), set(). Also, provides accessors to generic Atom elements such as <title>, <content>, etc. Can be extended and overridden to handle specific types of entries.
Zend_Gdata_Entry- Placeholder for any GData-wide entry elements. Not much here at present
Zend_Gdata_Kind_EventEntry- Implements the Event "kind" used by GData serviecs. This includes all elements in the GData namespace (elements prefixed with gd: in the GData documentation).
Zend_Gdata_Calendar_EventEntry- Implements extensions to the basic Zend_Gdata_EventEntry that describe properties specifically related to the Google Calendar implementation of the Event "kind". This includes all elements in the Google Calendar namespace (elements prefixed with gCal: in the Calendar data API documentation).
Zend_Gdata_Calendar_ListEntry- Represents an individual Entry in a Calendar meta feed.
Zend_Gdata_Spreadsheets_CellEntry- Represents a Cell in a spreadsheet. Objects of this type are used when working with the Cell feed in the Google Spreadsheets data API.
...etc
6. Milestones / Tasks
Describe some intermediate state of this component in terms of design notes, additional material added to this page, and / code. Note any significant dependencies here, such as, "Milestone #3 can not be completed until feature Foo has been added to ZF component XYZ." Milestones will be required for acceptance of future proposals. They are not hard, and many times you will only need to think of the first three below.
Milestone 2: [IN PROGRESS] Working prototype checked into the incubator implementing the Atom Publishing Protocol(APP) and core GData components (minus batch support and media support)
Milestone 3: [IN PROGRESS] Implementation checked into the incubator supporting utility classes for working with the Google Spreadsheets data API
Milestone 4: [IN PROGRESS] Implementation checked into the incubator supporting utility classes for working with the Google Calendar data API
Milestone 5: Finalized and stable implementation of the core APP and GData components to exist in the incubator, based on any feedback from the Calendar data API and Spreadsheets data API component developers.
Milestone 6: Unit tests for APP, GData, Spreadsheets, Calendar exist, work, and are checked into SVN.
Milestone 7: Initial documentation exists.
Milestone 8: Changes are moved from the incubator to trunk to correspond with xxx release
Milestone 10: Implementation checked into the incubator supporting utility classes for working with the Google Base data API
Milestone 11: Implementation checked into the incubator supporting utility classes for working with the Google Picasa data API
7. Class Index
Zend_Gdata
Zend_Gdata_Entry
Zend_Gdata_Feed
Zend_Gdata_App
Zend_Gdata_Query
Zend_Gdata_Exception
Zend_Gdata_BadMethodCallException
Zend_Gdata_AuthException
Zend_Gdata_HttpException
Zend_Gdata_InvalidArgumentException
Zend_Gdata_App_Entry
Zend_Gdata_App_Feed
Zend_Gdata_App_Extension
Zend_Gdata_App_Extension_Element
Zend_Gdata_App_Extension_Author
Zend_Gdata_App_Extension_Category
Zend_Gdata_App_Extension_Content
Zend_Gdata_App_Extension_Contributor
Zend_Gdata_App_Extension_Date
Zend_Gdata_App_Extension_Email
Zend_Gdata_App_Extension_Generator
Zend_Gdata_App_Extension_Icon
Zend_Gdata_App_Extension_Id
Zend_Gdata_App_Extension_Link
Zend_Gdata_App_Extension_Logo
Zend_Gdata_App_Extension_Name
Zend_Gdata_App_Extension_Person
Zend_Gdata_App_Extension_Published
Zend_Gdata_App_Extension_Right
Zend_Gdata_App_Extension_Source
Zend_Gdata_App_Extension_Subtitle
Zend_Gdata_App_Extension_Summary
Zend_Gdata_App_Extension_Text
Zend_Gdata_App_Extension_Title
Zend_Gdata_App_Extension_Updated
Zend_Gdata_App_Extension_Uri
Zend_Gdata_Extension
Zend_Gdata_Extension_AttendeeStatus
Zend_Gdata_Extension_AttendeeType
Zend_Gdata_Extension_Comments
Zend_Gdata_Extension_EventStatus
Zend_Gdata_Extension_ExtendedProperty
Zend_Gdata_Extension_OriginalEvent
Zend_Gdata_Extension_Recurrence
Zend_Gdata_Extension_RecurrenceException
Zend_Gdata_Extension_Reminder
Zend_Gdata_Extension_SendEventNotifications
Zend_Gdata_Extension_Transparency
Zend_Gdata_Extension_Visibility
Zend_Gdata_Extension_When
Zend_Gdata_Extension_Where
Zend_Gdata_Extension_Who
Zend_Gdata_Calendar
Zend_Gdata_Calendar_ListEntry
Zend_Gdata_Calendar_EventEntry
Zend_Gdata_Calendar_EventCommentEntry
Zend_Gdata_Calendar_ListFeed
Zend_Gdata_Calendar_EventFeed
Zend_Gdata_Calendar_EventCommentFeed
Zend_Gdata_Calendar_EventQuery
Zend_Gdata_Calendar_Extension
Zend_Gdata_Calendar_Extension_AccessLevel
Zend_Gdata_Calendar_Extension_Color
Zend_Gdata_Calendar_Extension_Hidden
Zend_Gdata_Calendar_Extension_Link
Zend_Gdata_Calendar_Extension_Selected
Zend_Gdata_Calendar_Extension_Timezone
Zend_Gdata_Calendar_Extension_WebContent
Zend_Gdata_Spreadsheets
Zend_Gdata_Spreadsheets_CellEntry
Zend_Gdata_Spreadsheets_ListEntry
Zend_Gdata_Spreadsheets_SpreadsheetEntry
Zend_Gdata_Spreadsheets_WorksheetEntry
Zend_Gdata_Spreadsheets_CellFeed
Zend_Gdata_Spreadsheets_ListFeed
Zend_Gdata_Spreadsheets_SpreadsheetFeed
Zend_Gdata_Spreadsheets_WorksheetFeed
Zend_Gdata_Spreadsheets_CellQuery
Zend_Gdata_Spreadsheets_ListQuery
Zend_Gdata_Spreadsheets_Extension
Zend_Gdata_Spreadsheets_Extension_ColCount
Zend_Gdata_Spreadsheets_Extension_RowCount
Zend_Gdata_Spreadsheets_Extension_Cell
Zend_Gdata_Spreadsheets_Extension_ListCell
etc.
8. Use Cases
UC 1 : Unauthed Calendar Event Retrieval
UC 2 : Authed Calendar List Feed Retrieval
UC 3 : Authed Calendar Event Query
UC 4 : Creating a Calendar Event
UC 5 : Updating a Calendar Event
UC 6 : Deleting a Calendar Event
9. Class Skeletons
SK 1: Zend_Gdata_Calendar_EventEntry
SK 2: Zend_Gdata_App_Feed
SK 3..infinity: Zend_Gdata_*
10. Testing Strategy
Unit tests will be created for both offline and online operation. The offline unit tests will test the basic data model functionality – parsing XML, converting it to the appropriate class instances and members, etc. These tests should be run and pass as a dependency of running the online "unit" tests. These tests may use mock XML data. The online "unit" tests will explicitly test the service components (HTTP, etc) in addition to implicitly testing the data model.
<ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Comment</ac:parameter><ac:rich-text-body>
<p>This proposal is approved for development in the Zend Framework incubator.</p>
<p>It represents significant value to the target market of Gdata developers to make the programming model similar to that of the other Gdata client libraries for other languages, within the bounds that make sense for the capabilities of PHP and the goals of extreme simplicity for Zend Framework.</p>
<p>This is a well thought-out architecture that has proven itself with the other Gdata client libraries, and makes it very easy to manipulate feed data both for posting and consuming.</p>
<p>We would like to see this developed for the Zend Framework 1.0 product.</p></ac:rich-text-body></ac:macro>
1 Comment
comments.show.hideMay 06, 2007
Bill Karwin
<ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Comment</ac:parameter><ac:rich-text-body>
<p>This proposal is approved for development in the Zend Framework incubator.</p>
<p>It represents significant value to the target market of Gdata developers to make the programming model similar to that of the other Gdata client libraries for other languages, within the bounds that make sense for the capabilities of PHP and the goals of extreme simplicity for Zend Framework.</p>
<p>This is a well thought-out architecture that has proven itself with the other Gdata client libraries, and makes it very easy to manipulate feed data both for posting and consuming.</p>
<p>We would like to see this developed for the Zend Framework 1.0 product.</p></ac:rich-text-body></ac:macro>