Zend Framework: Zend_Service_Rakuten Component Proposal
| Proposed Component Name | Zend_Service_Rakuten |
|---|---|
| Developer Notes | http://framework.zend.com/wiki/display/ZFDEV/Zend_Service_Rakuten |
| Proposers | TERUI Shingo, Satoru Yoshida Darby Felton, Zend liaison |
| Revision | 0.7 - 26 Dec: update References, Use Cases and Class Skeletons. 0.6 - 19 Dec: update References, Class Index, Use Cases and Class Skeletons. 0.5 - 11 Dec: update References, Use Cases and Class Skeletons. 0.4 - 22 Nov: update all except Dependencies and Milestones. 0.3 - 21 May: update class skeletons. 0.2 - 15 March 2007: add class skeletons. (wiki revision: 19) |
Table of Contents
1. Overview
Zend_Service_Rakuten is a interface to use the "Rakuten Web service" that is provided by the Rakuten, Inc. .
2. References
The following links are API references written in Japanese. I write method names and brief description for each API.
- Rakuten Web Service
- for the Rakuten Ichiba (Ichiba means shopping mall in japanese.)
- ItemSearch
- searchItem() - Search items.
- GenreSearch
- searchGenreChildren() - Retrieve genre's child genres.
- searchGenreParent() - Retrieve genre's parent genre.
- searchGenre() - Retrieve genre's information
- ItemCodeSearch
- searchItemCode() - Retrieve item's information by item code.
- CatalogSearch
- searchCatalog() - Search items by catalog.
- ItemSearch
- for the Rakuten Books
- BookSearch - searchBook()
- CDSearch - searchCd()
- DVDSearch - searchDvd()
- for the Rakuten Auction
- AuctionItemSearch
- searchAuctionItem() - Search items.
- AuctionItemCodeSearch
- searchAuctionItemCode() - Retrieve item's information by item code
- AuctionItemSearch
- for the Rakuten Travel
- SimpleHotelSearch
- searchSimpleHotel() - Search hotels.
- HotelDetailSearch
- searchHotelDetail() - Retrieve hotel's information by hotel number.
- VacantHotelSearch
- searchVacantHotelRoom() - Search vacant rooms.
- searchVacantHotel() - Search hotels that have vacant room.
- GetAreaClass
- getAreaClass() - Retrieve choices of area.
- KeywordHotelSearch
- searchKeywordHotel() - Search hotels by word.
- SimpleHotelSearch
- Other purpose
- DynamicAd
- dynamicAd() - Retrieve dynamic advertisements that is suitable for content in URL that you specify.
- DynamicAd
- for the Rakuten Ichiba (Ichiba means shopping mall in japanese.)
3. Component Requirements, Constraints, and Acceptance Criteria
- Implements the "Rakuten Web Service" APIs.
- Returns server responses as lightweight data objects.
4. Dependencies on Other Framework Components
- Zend_Rest_Client
- Zend_Service_Exception
5. Theory of Operation
Returns server response as the SimpleXMLElement.
6. Milestones / Tasks
- Milestone 1: Class development and write proposal
- Milestone 2: Unit tests and debugging
- Milestone 3: Documentation
7. Class Index
- Zend_Service_Rakuten
8. Use Cases
| UC-01 |
|---|
Search 3 items by word, "Zend Studio". Its case is most simple case.
| UC-02 |
|---|
Retrieve hotels that have vacant room for 1 adult person in the kasukabe city from today to tommorow.
The kasukabe city is in the saitama ward, and the saitama ward is in japan.
The checkinDate and checkoutDate are in Tokyo Time. If you use another time, you must use 3rd parameter of Zend_Service_Rakuten().
| UC-03 |
|---|
Display advertisements that is suitable for www.zend.com .
dynamicAd() needs affiliate ID in instantiation.
9. Class Skeletons
I updated wiki on May 21.
I classified inquiry classes in 'Zend_Service_Rakuten_Item' and 'Zend_Service_Rakuten_Travel'.
'Zend_Service_Rakuten_Item' contains a function about shopping mall.
'Zend_Service_Rakuten_Travel' contains a function about 'Rakuten Travel' service.
Why are many methods indicated as final? Is there a good reason for this? Does this not hinder extensibility, or do we expect that no one would ever need to override these methods?
I have the same questions as above for all the private variables. Probably these should be protected unless there are good reasons?
I notice in the code inconsistent usage of final keyword with respect to its position in the function declaration (e.g., final public and public final). I would recommend to be consistent with final public, as documented in the PHP manual. (I admit that this is inconsistent with the recommendation of public static, since the keywords appear in different orders, but the consistency is with the PHP manual pages on these keywords. Either way may be fine, but we should be consistent.)
Here is an idea - what about having a Zend_Service_Rakuten class, through which both Zend_Service_Rakuten_Item and Zend_Service_Rakuten_Travel are readily accessible? This new class would conveniently provide access to all of the currently available Rakuten services and could support additional services released in the future. Maybe it could follow the spirit of the fluent interfaces already available throughout the proposed component:
The basic idea is to provide a single point of entry to the Rakuten web services consumer component for ZF. If this is not a good idea, why not?
If such a thing would be useful and convenient, would the first-level methods such as item() and travel() return new instances each time they are called, or are the instances cached within the class (e.g., as static members) for reuse?
> Why are many methods indicated as final?...
I read these scripts and can understand from these as follows.
The all of final method are used in abstract class that are closely based on the specification of Rakuten API.
I think that these should not be extended by end user. If someone needs to extend these, we will hear that the time when this component should have been changed come. Till then, he does not need to use this component by force. He can call Rakuten API directly.
Please excuse since I did not necessarily ask Terui-san, when there is a misapprehension. But what do you think about my opinion?
> I notice in the code inconsistent usage of final keyword with respect to its position in the function declaration...
We have to repair this matter. I also think that sauce should follow the manual.
> Here is an idea...
Your idea looks excellent!! It seems that the reason for resisting this does not have anything. We may create new file 'Zend/Service/Rakuten.php' having Zend_Service_Rakuten class.
What about returning a result object (and perhaps collected in a resultset object) instead of delegating to the developer the need to use an XPath query?
I find the latter approach a little uncomfortable because requires the developer to have a deep knowledge of Rakuten XML response structure.
For instance, looking at UC-01 now I know that the following one is the best XPath expression for items
But does it fit a catalog search as well?
I would suggest to incorporate xpath query within the main class and let the user focus on reading result objects instead of querying XML.
Additionally, the fact that API documentation is only available in Japanese requires to avoid (or at least reduce) the need for the developer to read it.
Reading previous feedbacks, it seems a similar proposal was posted by Darby Felton a few comments ago.
I think that Simone deserves the credit for this suggestion, which I support. I definitely see added value from encapsulating the implementation (e.g., xpath queries) with easy-to-use, object-oriented goodness. ![]()
Hello, Simone. Thank you for comment.
I change this component to move xpath() into each methods for developers having no need to querying XML.
Unfortunately, the Rakuten, Inc. has no english docments, but is used by 18 million peoples. (at Jan. 2006)
It is greater than Amazon.co.jp that has 16 million customers.
Therefore Zend_Service_Rakuten will be used by many Japanese , I think.
I change this component to move xpath() into each methods for developers having no need to querying XML.
It definitely looks more friendly now. ![]()
I have a few random feedbacks.
1. method names
I noticed method names doesn't seem to follow an unique guideline.
Some method names originate from Rakuten API name
- searchItem --> ItemSearch
- searchBook --> BookSearch
- searchCd --> CdSearch
but other names doens't seem to follow any convention
- getItemInfo
?> ItemCodeSearch - getGenreInfo
?> GenreSearch - searchHotel
?> SimpleHotelSearch
I would suggest to define a reasonable convention and follow it for naming all methods.
For instance, according to initial standard the last three methods should be called
- searchItemCode <-- ItemCodeSearch
- searchGenre <-- GenreSearch
- searchSimpleHotel <-- SimpleHotelSearch
2. get vs search
Some search methods uses are prefixed by get keyword while others by search.
Again, I would suggest to find a reasonable convention.
You probably would use search instead of get and reserve the latter for attribute getter methods of an object.
3. Use exceptions when applicable
Looking at use cases I noticed the use of getErrorMessage() to check whether the response is successful.
I personally find this approach a little uncomfortable because requires the developer to test the response against a collection of error messages.
Additionally, it doesn't benefit from Exceptions and object oriented programming.
I would suggest to improve your search method(s) in order to raise an exception when an error occurs and let the developer use a try/catch block to handle the problem.
The developer side code would be something like:
4. _search() and Exceptions
A similar approach to Exception usage (point 3) could be used for _search method.
You may want to change _search method in order to return result object on success and raise an Exception on failure.
Catching the error will be in charge of the end user (developer) as described before and you don't need to perform the following check on each _search() request:
Additionally, this behavior allows you to convert _search method into a static method if you believe this approach fits your needs.
5. helper response method
Changes 3. and 4. provide you the ability to simplify search*() method.
You can define a custom helper to run xpath() and return a normalized result that would be the array of data on success or an empty array if no result is available.
All search method will be simplified to
As I said above, I just wanted to share with you some personal feedbacks. ![]()
Feel free to follow or ignore them.
Hello, Simone. Thank you for advices. I make some responces to you ![]()
about No.1 .
I think these API's name are japanized english
. I name these functions by their definition.
At first, ItemCodeSearch API is described as "This API retrieves item's information by item's code." in the document.
This API does not return more than one items, but only one item specified by the code. So, I use get instead of search in getItemInfo.
At second, GenreSearch does not usually mean "This API returns genre." . In the document, "This API returns name and structure of genre".
Therefore, I name the one of methods getGenreInfo .
At last, SimpleHotelSearch is named to be contrasted with HotelDetailSearch , I think.
But HotelDetailSearch does not search hotel in detail, but returns detailed information about hotel identified by hotel's No.
So, SimpleHotelSearch does not mean search hotels simply.
about No.2
I understand your advice that get would be reserved for attribute getter method.
For example, how about changing into following ?
retrieveItemInfo <-- ItemCodeSearch
Hello, Simone. I changed to use exception from getErrorMessage.
And I add new methods as the Rakuten Inc. incleases APIs.
2 more comments by: Satoru Yoshida, Simone Carletti
I cannot see that there is any functionality provided by Zend_Service_Rakuten_Abstract (only constants), and it does not appear that any other classes besides Zend_Service_Rakuten would inherit from Zend_Service_Rakuten_Abstract. These things being the case, it seems that the abstract class does not add any value. I would recommend simply having those constants in the Zend_Service_Rakuten class and doing away with the abstract class, or am I missing something?
Another concern of mine is how to change the versions of the web services, when they are updated. Having to modify a class constant to do so is not so good. I understand that the constants could be used to set the default values, but probably there should be another way to change the version values, such as in the following:
The above is just an example; maybe there is a better way.
Probably several of the other values currently stored in constants should be modifiable through the class API, as well.
I believe this proposal is at a stage that is most appropriate for our re-defined 'ready for review' section. I will move it there now.
Satoru, this proposal seems relatively mature. Are you still working on it? I would love to see you drive this to inclusion in one of the libraries; it seems to be very much in demand with our Japanese users.
Thanks.
,Wil
ZF Home Page
Code Browser
Wiki Dashboard
Instead of:
Use:
That eliminates all the repetitive getVersion() methods. Instead, the version can be retrieved with Zend_Service_Rakuten::API_VERSION in the event that someone needs it.
Minor class naming correction:
Zend_Service_Rakuten_CDSearch => Zend_Service_Rakuten_CdSearch
Zend_Service_Rakuten_DVDSearch => Zend_Service_Rakuten_DvdSearch
Is it possible to combine HotelDetailSearch and VacantHotelSearch into simply HotelSearch? Likewise for ItemSearch and ItemCodeSearch.