Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: ZendX_Service_Rakuten Component Proposal

Proposed Component Name ZendX_Service_Rakuten
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/ZendX_Service_Rakuten
Proposers Satoru Yoshida
Ralph Schindler, Zend liaison
Revision ------31 Dec:Name change from Zend_ to ZendX_
------11 Dec:add explanation of method parameters.
0.8 - 28 Nov 2008:I made APIs correspond from version 1.10 to 1.12 and I implemented the checking of the required parameters.
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: 35)

Table of Contents

1. Overview

ZendX_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 Market
      • searchItem() - Search items. Uses ItemSearch API
        parameter type min max required default explanation
        following in params array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        keyword string
        may required null key word. One of keyword, genreId or catalogCode is required
        shopCode string
        null shop code
        genreId int 0
        may required 0 genre id. One of keyword, genreId or catalogCode is required.
        catalogCode string
        may required null catalog code. One of keyword, genreId or catalogCode is required
        hits int 1 30
        30 items per page.
        page int 1 100
        1 page limits.
        sort string
        standard sort type. (mark)affiliateRate, (mark)reviewCount, (mark)itemPrice, (mark)updateTimestamp or standard. (mark) means plus or minus mark, each mark means Ascend and Descend. For example, +itemPrice
        minPrice int 0
        null minimum price
        maxPrice int 0
        null maximum price. It must be grater than minPrice
        availability int 0 1
        1 0:all items, 1:only items that can be bought
        field int 0 1
        1 0:search widely, 1:search narrowly
        carrier int 0 1
        0 0:PC, 1:mobile
        imageFlag int 0 1
        0 0:all item, 1:only items that has image
        orFlag int 0 1
        0 0:AND keywords, 1:OR keywords
        NGKeyword string
        null keyword that you want to omit
        genreInformationFlag int 0 1
        0 No Use. 0:not get count of items that are in the same genre, 1:get count. This method supports only 0.
      • searchGenre() - Retrieve genre's information. Uses GenreSearch API
        parameter type min max required default explanation
        type string
        required child information type. child, parent or current
        genreId int 0
        required 0 genre id. If parent is specified, genre id must be grater than 0.
        following in optparams array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        genrePath int 0 1
        No Use. genrePath is auto controlled in this method.
      • searchItemCode() - Retrieve item's information by item code. Uses ItemCodeSearch API
        parameter type min max required default explanation
        code string
        required
        item code
        following in optparams array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        carrier int 0 1
        0 0:PC, 1:mobile
      • searchCatalog() - Search items by catalog. Uses CatalogSearch API
        parameter type min max required default explanation
        following in params array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        keyword string
        may required null key word. One of keyword or genreId is required
        genreId int 0
        may required 0 genre id. One of keyword or genreId is required.
        hits int 1 30
        30 items per page.
        page int 1 100
        1 page limits.
        sort string
        -registerDate sort type. (mark)registerDate,(mark)releaseDate, (mark)reviewNum or random. (mark) means plus or minus mark, each mark means Ascend and Descend. For example, +reviewNum
        field int 0 1
        1 0:search widely, 1:search narrowly
        imageFlag int 0 1
        0 0:all item, 1:only items that has image
        releaseRange int 0 12
        0 0:no limit, 1-12:search only sold in specified months
        orFlag int 0 1
        0 0:AND keywords, 1:OR keywords
        NGKeyword string
        null keyword that you want to omit
        genreInformationFlag int 0 1
        0 No use. cf. searchItem()
      • itemRanking() - Retrieve item ranking. Uses ItemRanking API
        parameter type min max required default explanation
        following in optparams array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        genreId int 0
        null genre id.
        age int 10 50
        null age zone. 10:teen agers, 20:20 agers, 30:30 agers, 40:40 agers, 50:50 over
        sex int 0 1
        null sex. 0:men, 1:women
    • for the Rakuten Books
      • searchBook() - search books. Uses BookSearch API
        parameter type min max required default explanation
        following in params array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        keyword string
        may required null key word. One of keyword or genreId is required
        genreId int 0
        may required 0 genre id. One of keyword or genreId is required. The root id of the genreId must be 200162(books, magazine and comic).
        hits int 1 30
        30 items per page.
        page int 1 100
        1 page limits.
        sort string
        standard sort type. (mark)affiliateRate, (mark)reviewCount, (mark)itemPrice, (mark)updateTimestamp or random. (mark) means plus or minus mark, each mark means Ascend and Descend. For example, +itemPrice
        minPrice int 0
        null minimum price
        maxPrice int 0
        null maximum price. It must be grater than minPrice.
        availability int 0 1
        1 0:all items, 1:only items that you can buy.
        field int 0 1
        1 0:search widely, 1:search narrowly
        carrier int 0 1
        0 0:PC, 1:mobile
        imageFlag int 0 1
        0 0:all item, 1:only items that has image
        orFlag int 0 1
        0 0:AND keywords, 1:OR keywords
        NGKeyword string
        null keyword that you want to omit
        genreInformationFlag int 0 1
        0 No use. cf. searchItem()
      • searchCd() - search CDs. Uses CDSearch API
        This method has same parameters like searchBook(). But the root id of the genreId must be 101311(CD).
      • searchDvd() - search DVDs. Uses DVDSearch API
        This method has same parameters like searchBook(). But the root id of the genreId must be 101354(DVD).
    • for the Rakuten Auction
      • searchAuctionItem() - Search items. Uses AuctionItemSearch API
        parameter type min max required default explanation
        following in params array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        keyword string
        may required null key word. One of keyword or genreId is required
        genreId int 0
        may required 0 genre id. One of keyword or genreId is required.
        hits int 1 30
        30 items per page.
        page int 1 100
        1 page limits.
        minPrice int 0
        null minimum price
        maxPrice int 0
        null maximum price. It must be grater than minPrice.
        sort string
        +endTime sort type. (mark)endTime, (mark)itemPrice, (mark)bidCount or (mark)affiliateRate. (mark) means plus or minus mark, each mark means Ascend and Descend. For example, +itemPrice
        blowFlag int 0 1
        0 0:all items, 1:only items that you can buy without waiting auction's end.
        itemType int 0 3
        0 0:all items, 1:only items that are sold by personal seller, 2:only items that are sold by shops, 3:only items that are sold by auction shops
        newFlag int 0 2
        0 0:all items, 1:only used items, 2:only unused items
        field int 0 1
        1 0:search widely, 1:search narrowly
        carrier int 0 1
        0 0:PC, 1:mobile
        imageFlag int 0 1
        0 0:all item, 1:only items that has image
        orFlag int 0 1
        0 0:AND keywords, 1:OR keywords
        NGKeyword string
        null keyword that you want to omit
      • searchAuctionItemCode() - Retrieve item's information by item code. Uses AuctionItemCodeSearch API
        parameter type min max required default explanation
        code string
        required
        item code
        following in optparams array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        carrier int 0 1
        0 0:PC, 1:mobile
    • for the Rakuten Travel
      • searchSimpleHotel() - Search hotels. Uses SimpleHotelSearch API
        parameter type min max required default explanation
        following in params array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        largeClassCode string
        may required null area code. It specifies most wide area. For example, country. You can get the class codes list with getAreaClass(). One of the class codes set, hotelNo or latitude/longitude pair is required.
        middleClassCode string
        may required null area code. It is children of largeClassCode.
        smallClassCode string
        may required null area code. It is children of middleClassCode.
        detailClassCode string
        may required null area code. It is children of smallClassCode.
        hotelNo integer
        may required null hotel number. One of the class codes set, hotelNo or latitude/longitude pair is required.
        latitude float
        may required null latitude. One of the class codes set, hotelNo or latitude/longitude pair is required. Unit is specified with datumType.
        longitude float
        may required null longitude. Unit is specified with datumType.
        searchRadius float 0.1 3.0
        1.0 radius in searching. enable if you use the latitude/longitude pair. Unit is Km.
        squeezeCondition string
        null condition of hotel. kinen?only hotels that have no smoking rooms, internet?only hotels where you can enjoy internet, daiyoku?only hotels that have swimming bath, onsen?only hotels that have hot springs.
        carrier int 0 1
        0 0:PC, 1:mobile
        hits int
        null limit hit counts. enable if you use the latitude/longitude pair.
        datumType int 1 2
        2 1:Unit is degree, 2:Unit is second.
      • searchHotelDetail() - Retrieve hotel's information by hotel number. Uses HotelDetailSearch API
        parameter type min max required default explanation
        hotelNo integer
        required
        hotel number
        following in optparams array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        carrier int 0 1
        0 0:PC, 1:mobile
        datumType int 1 2
        2 1:Unit is degree, 2:Unit is second.
      • searchVacantHotel() - Search hotels that have vacant room. Uses VacantHotelSearch
        parameter type min max required default explanation
        type string
        required hotel information type. hotel or room.
        checkinDate date
        required null YYYY-MM-DD in Asia/Tokyo time zone.
        checkoutDate date
        required null YYYY-MM-DD in Asia/Tokyo time zone.
        following in optparams array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        largeClassCode string
        may required null area code. It specifies most wide area. For example, country. You can get the class codes list with getAreaClass(). One of the class codes set, hotelNo or latitude/longitude pair is required.
        middleClassCode string
        may required null area code. It is children of largeClassCode.
        smallClassCode string
        may required null area code. It is children of middleClassCode.
        detailClassCode string
        may required null area code. It is children of smallClassCode.
        hotelNo integer
        may required null hotel number. One of the class codes set, hotelNo or latitude/longitude pair is required.
        adultNum int 1 99
        1 adult members count
        upClassNum int 0 99
        0 members count. The members are over elementary school higher students.
        lowClassNum int 0 99
        0 members count. The members are under elementary school lower students.
        infantWithMBNum int 0 99
        0 infant members count. They need foods and blankets.
        infantWithMNum int 0 99
        0 infant members count. They need only blankets.
        infantWithBNum int 0 99
        0 infant members count. They need only foods.
        infantWithoutMBNum int 0 99
        0 infant members count. They no need foods and blankets.
        roomNum int 1 999
        1 required room count
        maxCharge int 0 9999999999
        null 0:PC, 1:mobile. It must be grater than minCharge.
        minCharge int 0 9999999999
        null 0:PC, 1:mobile
        latitude float
        may required null latitude. One of the class codes set, hotelNo or latitude/longitude pair is required. Unit is specified with datumType.
        longitude float
        may required null longitude. Unit is specified with datumType.
        searchRadius float 0.1 3.0
        1.0 radius in searching. enable if you use the latitude/longitude pair. Unit is Km.
        squeezeCondition string
        null condition of hotel. kinen?only hotels that have no smoking rooms, internet?only hotels where you can enjoy internet, daiyoku?only hotels that have swimming bath, onsen?only hotels that have hot springs, breakfast:only hotels where you can take breakfast, dinner:only hotels where you can take dinner.
        carrier int 0 1
        0 0:PC, 1:mobile
        datumType int 1 2
        2 1:Unit is degree, 2:Unit is second.
        hits int
        null limit hit counts. enable if you use the latitude/longitude pair.
      • getAreaClass() - Retrieve choices of area. Uses GetAreaClass API
        parameter type min max required default explanation
        following in optparams array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
      • searchKeywordHotel() - Search hotels by word. Uses KeywordHotelSearch API
        parameter type min max required default explanation
        keyword string
        required
        key word.
        following in optparams array
        affiliateId string
        null affiliate id
        callBack string
        null function name of Json call back
        carrier int 0 1
        0 0:PC, 1:mobile
        page int
        1 page limits.
        hits int 1 100
        20 items per page.
        sumDisplayFlag int 0 1
        0 0:not display features about the area and the hotel, 1:display.
        middleClassCode string
        null area code. You can get the list with getAreaClass().
    • Other purpose
      • dynamicAd() - Retrieve dynamic advertisements that is suitable for content in URL that you specify. Uses DynamicAd API and DynamicAd API (travel)
        parameter type min max required default explanation
        type string
        required item advertisement type. item or travel.
        affiliateId string
        required
        affiliate id
        url string
        required
        URL
        following in optparams array
        carrier int 0 1
        0 0:PC, 1:mobile
        callBack string
        null function name of Json call back

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 : Finished!
  • Milestone 2: Unit tests and debugging : Now working.
  • Milestone 3: Documentation : Now working

7. Class Index

  • ZendX_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 Asia/Tokyo (GMT +9) time zone.

UC-03

Display advertisements that is suitable for www.zend.com .
dynamicAd() needs your affiliate ID from the Rakuten web service.

9. Class Skeletons

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
zend_webservices zend_webservices Delete
proposal proposal Delete
api api Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Mar 22, 2007

    <p>Instead of:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    protected $_rwsVersion = '1.4';
    ]]></ac:plain-text-body></ac:macro>

    <p>Use:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    const API_VERSION = 1.4;
    ]]></ac:plain-text-body></ac:macro>

    <p>That eliminates all the repetitive <code>getVersion()</code> methods. Instead, the version can be retrieved with <code>Zend_Service_Rakuten::API_VERSION</code> in the event that someone needs it.</p>

    <p>Minor class naming correction:</p>

    <p><code>Zend_Service_Rakuten_CDSearch</code> => <code>Zend_Service_Rakuten_CdSearch</code><br />
    <code>Zend_Service_Rakuten_DVDSearch</code> => <code>Zend_Service_Rakuten_DvdSearch</code></p>

    <p>Is it possible to combine <code>HotelDetailSearch</code> and <code>VacantHotelSearch</code> into simply <code>HotelSearch</code>? Likewise for <code>ItemSearch</code> and <code>ItemCodeSearch</code>.</p>

    1. Mar 28, 2007

      <p>Thank you for your comment.</p>

      <p>class name of "Zend_Service_Rakuten_*" depends on the name of API of Rakuten Web Service.<br />
      I am mending the design of these class now.<br />
      I will renew the script and Wiki on the week first of April. </p>

      <ac:macro ac:name="code"><ac:parameter ac:name="title">Example</ac:parameter><ac:parameter ac:name="borderStyle">solid</ac:parameter><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
      $item = new Zend_Service_Rakuten_Item($devId);
      $itemResultSet = $item->keyword('DS-Lite')>hits(3)>search();
      $itemCodeResult = $item->searchItemCode('ko-cho:570418');

      $catalog = new Zend_Service_Rakuten_Catalog($devId);
      $catalogResultSet = $catalog->keyword('display')>hits(10)>search();

      $hotel = new Zend_Service_Rakuten_Hotel($devId);
      $hotelDetailResult = $hotel->searchDetail('123456');
      $hotelVacantResultSet = $hotel->largeClass('japan')
      ->middleClass('okinawa')
      ->checkinDate('2007-07-01')
      ->checkoutDate('2007-07-05')
      ->adultNum(2)
      ->chesearchVacant();
      ]]></ac:plain-text-body></ac:macro>

  2. May 23, 2007

    <p>I updated wiki on May 21.</p>

    <p>I classified inquiry classes in 'Zend_Service_Rakuten_Item' and 'Zend_Service_Rakuten_Travel'.<br />
    'Zend_Service_Rakuten_Item' contains a function about shopping mall.<br />
    'Zend_Service_Rakuten_Travel' contains a function about 'Rakuten Travel' service.</p>

  3. Aug 07, 2007

    <p>Why are many methods indicated as <code>final</code>? 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?</p>

    <p>I have the same questions as above for all the <code>private</code> variables. Probably these should be <code>protected</code> unless there are good reasons?</p>

    <p>I notice in the code inconsistent usage of <code>final</code> keyword with respect to its position in the function declaration (e.g., <code>final public</code> and <code>public final</code>). I would recommend to be consistent with <code>final public</code>, as documented in the PHP manual. (I admit that this is inconsistent with the recommendation of <code>public static</code>, 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.)</p>

    <p>Here is an idea - what about having a <code>Zend_Service_Rakuten</code> class, through which both <code>Zend_Service_Rakuten_Item</code> and <code>Zend_Service_Rakuten_Travel</code> 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:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    require_once 'Zend/Service/Rakuten.php';

    $rakuten = new Zend_Service_Rakuten(MY_RAKUTEN_ID);

    $itemResultSet = $rakuten->item()
    ->keyword('DS-Lite')
    ->hits(3)
    ->search();

    $itemCodeResult = $rakuten->item()
    ->searchItemCode('ko-cho:570418');

    $simpleHotelResultSet = $rakuten->travel()
    ->largeClassCode('japan')
    ->middleClassCode('kanagawa')
    ->smallClassCode('hakone')
    ->search();
    ]]></ac:plain-text-body></ac:macro>

    <p>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?</p>

    <p>If such a thing would be useful and convenient, would the first-level methods such as <code>item()</code> and <code>travel()</code> return new instances each time they are called, or are the instances cached within the class (e.g., as <code>static</code> members) for reuse?</p>

    1. Sep 18, 2007

      <p>> Why are many methods indicated as final?...</p>

      <p>I read these scripts and can understand from these as follows.<br />
      The all of final method are used in abstract class that are closely based on the specification of Rakuten API.<br />
      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.<br />
      Please excuse since I did not necessarily ask Terui-san, when there is a misapprehension. But what do you think about my opinion?</p>

      <p>> I notice in the code inconsistent usage of final keyword with respect to its position in the function declaration...</p>

      <p>We have to repair this matter. I also think that sauce should follow the manual.</p>

      <p>> Here is an idea...</p>

      <p>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.</p>

      1. Oct 30, 2007

        <p>Any word on updating the proposal to reflect the latest commentary?</p>

        1. Nov 21, 2007

          <p>Hello, I rewrited.<br />
          Now we can use all methods by only including Zend_Service_Rakuten class.<br />
          And no final and private keywords.</p>

    2. Dec 19, 2007

      <p>Oh! thank you for reading this pages and very quick response. <ac:emoticon ac:name="smile" /> I will think about it carefully.</p>

  4. Nov 27, 2007

    <p>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?<br />
    I find the latter approach a little uncomfortable because requires the developer to have a deep knowledge of Rakuten XML response structure.</p>

    <p>For instance, looking at UC-01 now I know that the following one is the best XPath expression for items</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA//itemSearch:ItemSearch/Items/Item]></ac:plain-text-body></ac:macro>

    <p>But does it fit a <a href="http://webservice.rakuten.co.jp/api/catalogsearch/">catalog search</a> as well?</p>

    <p>I would suggest to incorporate xpath query within the main class and let the user focus on reading result objects instead of querying XML.<br />
    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.</p>

    <p>Reading previous feedbacks, it seems a similar proposal was posted by Darby Felton a few comments ago.</p>

    1. Dec 05, 2007

      <p>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. <ac:emoticon ac:name="smile" /></p>

      1. Dec 11, 2007

        <p>Hello, Derby, Thank you for advice.</p>

        <p>I improve this component just today, I expect advices from you if you have time to read this. <ac:emoticon ac:name="smile" /></p>

    2. Dec 11, 2007

      <p>Hello, Simone. Thank you for comment.</p>

      <p>I change this component to move xpath() into each methods for developers having no need to querying XML.</p>

      <p>Unfortunately, the Rakuten, Inc. has no english docments, but is used by 18 million peoples. (at Jan. 2006)<br />
      It is greater than Amazon.co.jp that has 16 million customers.<br />
      Therefore Zend_Service_Rakuten will be used by many Japanese , I think.</p>

      1. Dec 11, 2007

        <blockquote><p>I change this component to move xpath() into each methods for developers having no need to querying XML.</p></blockquote>

        <p>It definitely looks more friendly now. <ac:emoticon ac:name="smile" /><br />
        I have a few random feedbacks.</p>

        <p><strong>1. method names</strong></p>

        <p>I noticed method names doesn't seem to follow an unique guideline.<br />
        Some method names originate from Rakuten API name </p>

        <ul>
        <li>searchItem --> ItemSearch</li>
        <li>searchBook --> BookSearch</li>
        <li>searchCd --> CdSearch</li>
        </ul>

        <p>but other names doens't seem to follow any convention</p>

        <ul>
        <li>getItemInfo <span style="text-decoration: line-through;">?</span>> ItemCodeSearch</li>
        <li>getGenreInfo <span style="text-decoration: line-through;">?</span>> GenreSearch</li>
        <li>searchHotel <span style="text-decoration: line-through;">?</span>> SimpleHotelSearch</li>
        </ul>

        <p>I would suggest to define a reasonable convention and follow it for naming all methods.<br />
        For instance, according to initial standard the last three methods should be called</p>

        <ul>
        <li>searchItemCode <-- ItemCodeSearch</li>
        <li>searchGenre <-- GenreSearch</li>
        <li>searchSimpleHotel <-- SimpleHotelSearch</li>
        </ul>

        <p><strong>2. get vs search</strong></p>

        <p>Some search methods uses are prefixed by <strong>get</strong> keyword while others by <strong>search</strong>.</p>

        <p>Again, I would suggest to find a reasonable convention.<br />
        You probably would use <strong>search</strong> instead of <strong>get</strong> and reserve the latter for attribute getter methods of an object.</p>

        <p><strong>3. Use exceptions when applicable</strong></p>

        <p>Looking at use cases I noticed the use of getErrorMessage() to check whether the response is successful.</p>

        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
        $params = array('keyword' => 'Zend Studio', 'hits' => 3);
        $results = $rakuten->searchItem($params);
        $error = $rakuten->getErrorMessage();

        if ($error !== null) {
        /* error message from the Rakuten Web Service.

        • NotFound, ServerError, ClientError, Maintenance
          */
          echo $error;

        }
        ]]></ac:plain-text-body></ac:macro>

        <p>I personally find this approach a little uncomfortable because requires the developer to test the response against a collection of error messages.<br />
        Additionally, it doesn't benefit from Exceptions and object oriented programming.</p>

        <p>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.<br />
        The developer side code would be something like: </p>

        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
        $params = array('keyword' => 'Zend Studio', 'hits' => 3);
        try {
        $results = $rakuten->searchItem($params);
        } catch(Zend_Service_Rakuten_Exception $e) {
        echo 'An error occured: ' . $e->getMessage();
        // you may want to set result array to an empty array
        $results = array();
        }
        ]]></ac:plain-text-body></ac:macro>

        <p><strong>4. _search() and Exceptions</strong></p>

        <p>A similar approach to Exception usage (point 3) could be used for _<em>search</em> method.<br />
        You may want to change _<em>search</em> method in order to return result object on success and raise an Exception on failure.</p>

        <p>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:</p>

        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[if($this->_search('GenreSearch', self::VERSION_GENRESEARCH, $params)) { // should be === true ]]></ac:plain-text-body></ac:macro>

        <p>Additionally, this behavior allows you to convert _<em>search</em> method into a static method if you believe this approach fits your needs.</p>

        <p><strong>5. helper response method</strong></p>

        <p>Changes 3. and 4. provide you the ability to simplify search*() method.<br />
        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.</p>

        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
        protected static function _run_xpath_and_normalize_response($path, SimpleXMLElement $simplexml)
        {
        $result = $simplexml->xpath($path);
        return is_array($result) ? $result : array();
        // the following statement would probably cause the same result
        // return (array) $simplexml->xpath($path);
        }
        ]]></ac:plain-text-body></ac:macro>

        <p>All search method will be simplified to</p>

        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
        public function searchItemByCatalog($params)
        {
        $response = self::_search('CatalogSearch', self::VERSION_CATALOGSEARCH, $params));
        return $this->_run_xpath_and_normalize_response('//catalogSearch:CatalogSearch/Catalogs/Catalog', $response);
        }
        ]]></ac:plain-text-body></ac:macro>

        <p>As I said above, I just wanted to share with you some <strong>personal feedbacks</strong>. <ac:emoticon ac:name="smile" /><br />
        Feel free to follow or ignore them.</p>

        1. Dec 11, 2007

          <p>Thanks, Simone, for the excellent feedback! <ac:emoticon ac:name="smile" /></p>

        2. Dec 14, 2007

          <p>Hello, Simone. Thank you for advices. I make some responces to you <ac:emoticon ac:name="smile" /></p>

          <p> about <strong>No.1</strong> .<br />
          I think these API's name are japanized english <ac:emoticon ac:name="sad" /> . I name these functions by their definition.</p>

          <p>At first, <strong>ItemCodeSearch</strong> API is described as "This API retrieves item's <strong>information</strong> by item's code." in the document.<br />
          This API does not return more than one items, but only one item specified by the code. So, I use <strong>get</strong> instead of <strong>search</strong> in <strong>getItemInfo</strong>.</p>

          <p>At second, <strong>GenreSearch</strong> does not usually mean "This API returns genre." . In the document, "This API returns name and structure of genre". <br />
          Therefore, I name the one of methods <strong>getGenreInfo</strong> . </p>

          <p>At last, <strong>SimpleHotelSearch</strong> is named to be contrasted with <strong>HotelDetailSearch</strong> , I think.<br />
          But <strong>HotelDetailSearch</strong> does not search hotel in detail, but returns detailed information about hotel identified by hotel's No.<br />
          So, SimpleHotelSearch does not mean search hotels <strong>simply</strong>.</p>

          <p> about <strong>No.2</strong><br />
          I understand your advice that <strong>get</strong> would be reserved for attribute getter method.<br />
          For example, how about changing into following ?</p>

          <p>retrieveItemInfo <-- ItemCodeSearch</p>

        3. Dec 19, 2007

          <p>Hello, Simone. I changed to use exception from getErrorMessage.<br />
          And I add new methods as the Rakuten Inc. incleases APIs.</p>

          1. Dec 19, 2007

            <p>Great! <ac:emoticon ac:name="smile" /></p>

            <p>I'm sorry, I just noticed I didn't answer your previous comment.</p>

            <blockquote><p>At first, ItemCodeSearch API is described as "This API retrieves item's information by item's code." in the document.<br />
            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.</p></blockquote>

            <p>Your explanation may appear correct, however IMHO it's quite difficult that an end user will read all the documentation provided by Rakuten and will be able to evaluate it as you did.<br />
            He will probably read just the most common steps (if we are lucky, or he won't probably read it at all!) and will try to find a corrispondence between Rakuten names and Zend_Service_Rakuten class.</p>

            <p>This is why I suggest to define a close correspondence between method calls and Rakuten API names.</p>

            <p>I have a question for you.<br />
            Does the following API call has some mandatory arguments?<br />
            According to <a class="external-link" href="http://translate.google.com/translate?u=http%3A%2F%2Fwebservice.rakuten.co.jp%2Fapi%2Fdvdsearch%2F&langpair=ja%7Cen&hl=en&ie=UTF-8">http://translate.google.com/translate?u=http%3A%2F%2Fwebservice.rakuten.co.jp%2Fapi%2Fdvdsearch%2F&amp;langpair=ja%7Cen&amp;hl=en&amp;ie=UTF-8</a> it seems that <em>Keyword</em> is requested.</p>

            <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
            /**

            • Search DVDs from the Rakuten books.
              *
            • @see http://webservice.rakuten.co.jp/api/dvdsearch/
            • @param array $params parameters
            • @return array array(SimpleXMLElement)
              */
              public function searchDvd($params)
              Unknown macro: { return $this->_search('DVDSearch', '//dvdSearch}

              ]]></ac:plain-text-body></ac:macro>

            <p>If so, I would suggest to move mandatory arguments from $params array directly to method definition.<br />
            This will cause PHP parser to raise an Exception at your place whether a mandatory element is not provided.</p>

            <p>It seems you already used this technique elsewhere, for instance <em>getItemInfo</em> method.<br />
            $code is included in method definition and $params is reserved for optional parameters.</p>

            <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
            /**

            • Retrieve item's information by the item code from the Rakuten Market.
              *
            • @see http://webservice.rakuten.co.jp/api/itemcodesearch/
            • @param string $code item code
            • @param array $optparams option parameters
            • @return array array(SimpleXMLElement)
              */
              public function getItemInfo($code, $optparams = array())
              Unknown macro: { $params = array_merge( array('itemCode' => $code), $optparams ); return $this->_search('ItemCodeSearch', '//itemCodeSearch}

              ]]></ac:plain-text-body></ac:macro>

            1. Dec 21, 2007

              <p>Thank you for reading and advicing very quickly! <ac:emoticon ac:name="smile" /></p>

              <p>At first, I agree about that end user may <strong>not</strong> read <strong>all</strong> documents.<br />
              So, I will change names to useItemCodeSearch (use + API name) or like as searchItemCode.</p>

              <p>At second, the code is usually mandatory arguments in the getItemInfo(), but unusually the keyword in searchDvd().<br />
              In searchDvd(), one of keyword <strong>or</strong> genreId is needed.</p>

              <p>Do you think it is better to check whether one of arguments is not null? </p>

  5. Dec 11, 2007

    <p>I cannot see that there is any functionality provided by <code>Zend_Service_Rakuten_Abstract</code> (only constants), and it does not appear that any other classes besides <code>Zend_Service_Rakuten</code> would inherit from <code>Zend_Service_Rakuten_Abstract</code>. 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 <code>Zend_Service_Rakuten</code> class and doing away with the abstract class, or am I missing something?</p>

    <p>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 <em>default</em> values, but probably there should be another way to change the version values, such as in the following:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $rakuten = new Zend_Service_Rakuten(YOUR_DEVELOPER_ID);
    $rakuten->setVersion('genreSearch', '2008-01-01');
    ]]></ac:plain-text-body></ac:macro>

    <p>The above is just an example; maybe there is a better way.</p>

    <p>Probably several of the other values currently stored in constants should be modifiable through the class API, as well.</p>

    1. Dec 19, 2007

      <p>Hello, Darby.<br />
      I rewrite this component to be able to specify version.<br />
      I added getVersion and setVersion methods. </p>

  6. May 14, 2008

    <p>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.</p>

    <p>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.</p>

    <p>Thanks.<br />
    ,Wil</p>

    1. May 15, 2008

      <p>Thank you for your comment, Wil. I agree to move this component to the 'ready for review' section.</p>

      <p>However, unfortunately, I am not working on this proposals.<br />
      If anyone want to work on this, I will be happy.</p>

      <p>Satoru.</p>

      1. Nov 27, 2008

        <p>At first, I made APIs correspond from version 1.10 to 1.12.</p>

        <p>1) The ItemRanking() is new API.<br />
        2) The VacantHotelSearch API request new required parameters.<br />
        3) URI format of the DynamicAd API was extended.</p>

        <p>At second, I unified several functions.<br />
        1)searchGenreParent() and searchGenreChildren() into searchGenre().<br />
        searchGenre() requires new parameter, $type.</p>

        <p>2)searchVacantHotelRoom() into searchVacantHotel().<br />
        searchVacantHotel() also requires new parameter, $type.</p>

        <p>At last, I implemented the checking of the required parameters on many functions.</p>

  7. Dec 30, 2008

    <ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Official Comment</ac:parameter><ac:rich-text-body>

    <p>This component has been accepted for development inside the <strong>Extras Incubator</strong>.</p>

    <p>It appears as though this component has been very well thought out and as such, (along with the popularity of this service within specific regions), it is accepted to the ZendX extras incubator.</p>

    <p>There are two concerns I would additionally like to discuss:</p>
    <ul>
    <li>there are a few methods that indicate they will be "doing some action" but do not contain any verbs, is it possible to review this part of the API? For example:
    <ul>
    <li>There are a few methods in the use cases that are not preceded by "search" or "get", this makes it hard to understand what the methods is intending to do and return.</li>
    </ul>
    </li>
    <li>Can you address how the API on the server side changes over time and what _apiVer does and what it provides. Does this mean that the server API changes in such a way that is hard to maintain?</li>
    </ul>

    <p>Aside from those concerns, please feel free to get this in the Extras incubator to facilitate development.</p>

    <p>-ralph</p>
    </ac:rich-text-body></ac:macro>

    1. Dec 31, 2008

      <p>Thank you for accepting.</p>

      <p>At first, I think you take care of the itemRanking() and the dynamicAd().</p>

      <p>If method name can be differ from API name, I have an idea that itemRanking() may be changed to getRanking() and dynamicAd() also may be changed to getAdvertisements().<br />
      (Please refer comments from Mr Simone Carletti last year)</p>

      <p>At second, the server changes will be shown leftside in <a class="external-link" href="http://webservice.rakuten.co.jp/">http://webservice.rakuten.co.jp/</a> .<br />
      And I will write document how to know the new values of API versions.</p>

      <p>For example, we can find the version of the ItemSearch API by looking topside of <a class="external-link" href="http://webservice.rakuten.co.jp/api/itemsearch/">http://webservice.rakuten.co.jp/api/itemsearch/</a> .<br />
      We can find a string '(version:2008-09-01)' there. The string '2008-09-01' is the value of _apiVer(<ac:link><ri:page ri:content-title="'ItemSearch'" /></ac:link>).</p>

      <p>And we can find the value of 'api_rws' in bottom side of <a class="external-link" href="http://webservice.rakuten.co.jp/document/index.html">http://webservice.rakuten.co.jp/document/index.html</a> .<br />
      There is explanation of url format, and version of the Rakuten Web Service is shown as following.</p>

      <p>'<ac:link><ri:page ri:content-title="version" /></ac:link>xxxxxxxxxxxxxxxxxxxxxxxx1.12xxxxx' (x is instead of Japanese characters)<br />
      The sentence means, '<ac:link><ri:page ri:content-title="version" /></ac:link> is version of the Rakuten Web Service. The last value is 1.12 now.'</p>

      <p>At last, I will be happy if this responce will be useful. </p>

      <p>Satoru Yoshida</p>

  8. Mar 18, 2009

    <p>Satoru, do you plan to finish this for the 1.8 release?</p>

    1. Mar 18, 2009

      <p>Hello, Wil.</p>

      <p> I will finish to make unit tests at May 10th .<br />
      Sadly, now I am caught by oci extension trouble from my customer long time.</p>

      <p> I should schedule to end more early ?</p>

  9. Mar 19, 2009

    <p>Did you mean May or March? We'll probably have 1.8 code freeze in the middle of April.</p>

    <p>,Wil</p>

    1. Mar 22, 2009

      <p>Hi, Wil.</p>

      <p>I schedule to work from 29/April/2009 to 10/May/2009.</p>

      <p>Unfortunately, I am in trouble now. <ac:emoticon ac:name="sad" /></p>

      <p>Satoru Yoshida</p>

      1. May 11, 2009

        <p>Hello, <br />
        I will be happy if you will close and archive this .</p>